포맷스트링 버그에 이용하는 .dtors 영역에 대해서 알아 보겠습니다.
GNU Compiler(gcc)는 컴파일 할 때 .ctors, .dtors 두 segment를 생성합니다. (gcc의 속성)
( ctors - constructor, dtors - destructor )
이 두 영역의 특징은
.ctors 속성의 함수는 main() 전에 실행되고
.dtors 속성의 함수는 main() 종료 후에 실행 된다는 것입니다.
그러므로 main() 종료 후에 .dtors 속성의 함수가 실행되는 것을 이용해서 그 부분을 쉘 코드가 있는 주소 값으로 덮음으로써 쉘 코드가 실행되게 할 수 있다는 것입니다.
포맷 스트링 버그 - FSB (Format String Bug) 기본 연습하기 <- 에서는 포맷스트링 버그를 이용해서 .dtors를 에 쉘 코드가 있는 주소를 덮었습니다. 또 RedHat 버전일 때는 .data 영역이 .dtors보다 아래에 있어서 bof를 통해 덮어쓸 수도 있다고 합니다.
.data 영역의 위치를 간단히 확인해보면 아래와 같습니다. ( readelf -S (실행 파일) )
1. 아래는 Red Hat에서 (해커스쿨의 FTZ입니다.)
.data영역 위쪽에 .ctors나 .dtors가 있는 것을 확인할 수 있습니다. (따라서 .data영역에서 bof를 통해 .dtors를 덮을 수 있었습니다.)
2. 이번에는 fedora core3에서 확인해본 결과입니다.
.data를 .ctors나 .dtors보다 높은 곳에 위치시킨 것을 확인할 수 있습니다. (.data에서 bof로 .dtors를 덮을 수 없음; - 포인터를 조작하면 가능할 수 있겠지만)
그럼 ( ctors - constructor, dtors - destructor )에 대해서 좀 더 알아보겠습니다.
위에서 ( 이 두 영역의 특징은 .ctors 속성의 함수는 main() 전에 실행되고 .dtors 속성의 함수는 main() 종료 후에 실행 된다는 것입니다. ) 라고 했는데 여기서 말하는 속성의 함수는 __attribute__((constructor)) 또는 __attribute__((destructor))를 사용해서 정의한 함수를 말합니다.
그럼 __attribute__((constructor))와 __attribute_((destructor))를 이용한 간단한 예제를 보겠습니다.
위와 같이 프로그램을 만들어서 실행시켜보면 예상대로 test_ctors() -> main() -> test_dtors() 순서로 함수가 수행되는 것을 알 수 있습니다. (main전에 constructor 수행, main 종료 후에 destructor 수행)
이제 위의 프로그램 gdb로 좀 더 살펴봅시다.
아래는 우분투 11.04에서 확인해본 결과입니다.
ctor와 dtor부분을 살펴본 것으로 LIST의 첫 부분(LIST)은 0xffffffff이고 마지막 부분(END)은 0x00000000로 끝나는 것이 기본적인 구조라는 것을 알 수 있습니다.
그런데 제가 본 문서에서는 LIST와 END 사이에 attribute로 추가했던 함수를 가리키는 부분이 있었습니다.
그래서 아래는 RedHat (역시 해커스쿨의 FTZ입니다.)에서 확인해본 결과입니다.
LIST부분과 END부분에 각각 아까 attribute로 선언했던 test_ctors함수와 test_dtors함수를 가리키는 부분이 있습니다.
그래서 vm에 있던 fedora11에서도 확인해보니 LIST+4에 함수 부분이 제대로 있었습니다.
또 백트랙5에서도 확인해보니 제대로 있습니다.
우분투의 특징인지 아니면 페도라도 높은 버전을 사용하면 이렇게 바뀌는지 .. 앞으로 공부하면서 왜 그런지 알아 보도록 하겠습니다.
그래서 위의 우분투는 좀 다르게 나왔지만 구조를 정리해보면
( ctor는 dtor와 같은 형태일 것이므로 dtor만 쓰겠습니다. )
__DTOR_LIST__ |
__DTOR_LIST__+4 |
__DTOR_END__ |
가 될 것입니다. ( 만약 attribute로 추가한 함수가 2개라면 __DTOR_LIST__+8까지 있을 것이고 함수가 더있다면 계속해서 추가 되겠죠 )
그리고 attribute로 추가해준 함수가 없다면 단순하게
__DTOR_LIST__ |
__DTOR_END__ |
의 구조를 가지게 될 것입니다.
여기서 우리가 포맷스트링 버그를 할때 .dtors영역에 +4 해준 곳을 덮는데 따로 attribute로 추가해준 함수가 있다면 그 함수의 주소를 덮어 씌우게 될 것이고 추가해준 함수가 없다면 __DTOR_END__를 덮어 씌우는 것이 될 것입니다.
왜 __DTOR_END__를 덮어도 실행되는지 궁긍하시면 http://x82.inetcop.org/h0me/papers/FC_exploit/ctors_dtors.txt 문서의 _do_global_dtors_aux()가 동작하는 부분을 보고 알 수 있을 것입니다.
지금 까지 ctors와 dtors의 역할과 간단한 구조 (LIST - 함수들 - END)를 알아보았습니다.
REF : http://x82.inetcop.org/h0me/papers/FC_exploit/ctors_dtors.txt
'System > Linux' 카테고리의 다른 글
Fedora Core5의 bof공격 (0) | 2012.08.27 |
---|---|
remote BOF1 - [xinetd 데몬으로 작동하는 프로그램] (0) | 2012.07.24 |
FSB(Format String Bug)로 GOT Overwrite 해보기 (0) | 2012.05.22 |
PLT(Procedure Linkage Table), GOT(Global Offset Table) (6) | 2012.05.07 |
포맷 스트링 버그 - FSB (Format String Bug) 기본 연습하기 (0) | 2012.05.02 |