Format String Bug (FSB) : printf() 함수 계열을 사용할 때, 인자로 포맷 스트링과 포맷 스트링에 대응하는 인자를 사용하지 않고 바로 변수를 인자로 지정했을 때, 악의적인 공격자가 포맷 스트링을 입력하여 스택의 값을 leak 하거나, RET나 _DTOR_END__, GOT와 같은 프로그램의 흐름을 제어할 수 있는 메모리 주소값을 변조하여 악의적인 행동을 할 수 있게 된다.

 

윈도우와 우분투에 파일을 다운받고 IDA로 코드를 확인해보자.

 

main 함수
vuln 함수

메인함수에선 따로 확인할건 없어보인다.

 

vuln 함수를보자.

 

snprintf 함수와 printf 함수에서 서식문자를 따로 지정해주지 않고 바로 넘겨버린다.

 

이 함수에서 FSB 취약점이 발생한다는 것을 알 수 있다.  두 함수에 대해 알아보자.

 

sprintf(char * buffer, const char * format, ...)

 - ... 은 가변 파라미터를 뜻 한다.
 - 첫 번째 인자에 두 번째 인자의 내용이 문자열로써 담기게 된다.


snprintf(char * buffer, int buf_size, const char * format, ...)
 - sprintf 함수에서 두 번째 인자로 size가 추가된 함수로, buffer overflow를 방지하기위해 출력할 문자열의 길이를 지정하였다.

 

flag 함수

gdb를 이용해 basic_fsb에 flag 함수가 있는걸 확인했다.

 

이 함수를 이용하면 될 것 같다.

 

우분투에서 파일을 실행해서 서식문자를 넣어보자.

 

%x = hex

두 번째 서식문자에는 입력된 AAAA의 hex값인 41414141이 출력된다.

 

%n : 서식문자 앞까지의 바이트 수를 계산 후 출력, 출력했던 값을 주소로 생각하고 계산한 값을 주소에 넣는다.

 

그렇다면 위의 서식문자를 바탕으로 이렇게 사용할 수 있을 것 같다.

 

-> printf_GOT 주소에 %n 이 오게한 다음, %n이 flag 함수의 주소를 계산하게 만들면 문제가 해결될 것이다!!

 

GOT는 PLT가 참조하는 테이블이다. 쉽게 말하면 함수의 실제 주소가 들어있다.

 

자! 이제 printf_GOT의 주소와 flag 함수의 주소를 찾아보자.

 

printf_GOT 주소

 

flag 함수 주소

모두 찾았다. python으로 익스를 짜보자.

 

flag 함수의 주소값 0x80485b4을 10진수로 바꾼만큼 %x 포맷을 이용해 출력 해준다.

 

그리고 위에서 포맷스트링 두 번째부터 입력값이 출력됐기 때문에 -4byte를 해줘야 한다.

 

0x80485b4 -> 134514100

 

134514100 - 4 = 134514096

 

실행해보자.

 

flag

익스가 되고 플래그가 나왔다.

 

플래그는 HackCTF{여보게_오늘_반찬은_포맷스트링이_어떠한가?} 이다.

 

 

문제를 이해하기 위해 많은 시간을 들였다. 좀 더 열심히 공부해야겠다.

+ Recent posts