[DAS2024](fmt漏洞劫持)springboard解题wp+格式化字符串漏洞深入理解
[DAS2024](fmt漏洞劫持)springboard解题wp+格式化字符串漏洞深入理解
一个非栈上的格式化字符串漏洞,主要是用到了格式化字符串给目标地址赋值的特性
题目程序非常简单,就是一个重复触发了五次格式化字符串漏洞的循环
由于唯一的读入是朝bss段上读的,靠溢出做题就别想了,这题很明显是想让我们利用格式化字符串(fmt)漏洞
这里先对格式化字符串的几点进行补充解析:
一、"%Nc"(N指整数)
我们知道%n这个fmt可以将已打印的字符个数作为整形赋值给目标地址,在刚了解到格式化字符串漏洞时一般都会用aaaa%x$n这种方式去赋值,这种方式当然是效率极低的一种利用方式,实际上有一种更好的方式:"%c":
%c这个fmt是用来解析字符的,如果出现了[width]参数即%nc这种情况则表示printf应该打印出7个字符,如果参数不足7个那么就会用空格进行填充,所以在有限的读入长度下就可以用这种写法去赋值,比如%777c%n$n就会将第n个栈里的地址赋值为777
那么这种方式最大可以赋值多少呢,答案是一个int型的最大值65535=0xffff(内存里的两字节)
二、"%hn"
在与%Nc搭配使用时往往不会直接用%n,而是再加一个h参数,这个h参数的作用是规定修改目标地址的哪几位,64位下%n会修改4字节的内容,而加一个h %hn会修改2字节的内容,而前面也说到了%Nc的N最大是0xffff,正好就是两字节内容的最大值,所以一般情况下使用这种手法都是用%hn的
三、%n赋值到底是赋值给哪里的?
答:赋值给这块栈上的地址里
画个图:
是以栈上的地址为目标而不是以栈为目标,如果定位到的栈里没有合法地址,程序就会趋势
来到题目中:
先拿栈顶这里试试水:
输入一个%64c%6$n
可以成功将该处赋值为64
接下来就是考虑利用这个漏洞将某处篡改为shell地址进行劫持了,这个题开了partial RELRO,got表不可写的,所以不能劫持got表;我这题是篡改的return地址,接下来就写一下这个思路的分析。
———————————————————————————————————————————————————————
非栈上的格式化字符串漏洞:
如果格式化字符串是在栈上的,我们就可以先将目标地址写到栈上再对目标地址赋值,但是这里是在bss段上的,没办法直接任意写
对于这种情况可以使用一个连环劫持的手法
我们可以利用一个这样的结构:
如图,这两块栈的构造是
A: 栈地址1-->栈地址2-->栈地址3(其他地址)
B: 栈地址2-->栈地址3(其他地址)
(实际利用中找到 栈地址1-->栈地址2-->栈地址3 这样的三连环就能用了)
根据我画的图里的两个白色箭头,通过这个结构可以用%n$n直接修改到两个位置,定位栈A就可以修改address,而图中的a又是在address里的,通过,通过这样一个连环控制就可以实现任意地址写了,这里的逻辑关系稍微有些绕,需要好好理清楚,本质上是很简单的。
接下来实操看看,我们试着利用这个三连环将迭代变量篡改成一个奇怪的值
在这里栈地址3的后四位我们都可以利用格式化字符串漏洞去篡改,
篡改的目标后四位是0xde48,写一个%56904c%11$hn就ok了
可以看到通过定位栈A成功把栈B的指向篡改到了de48的位置
同时可以看到,在df38这里的内容也是成功的同步为de48
那么此时定位栈B(就是截图这里)会发生什么?篡改的会是de48处的内容,我们定位它篡改一下试试:
%1911c%37$hn
成功将de48处的内容改为了0x777(当然,是低位)
———————————————————————————————————————————————————————
做题
好了,通过上面这一段解释,应该(maybe?)能明白利用三连环结构构造任意地址写的手法了,接下来就考虑题目应该怎么打了,思路很简单:先在栈A处篡改内容为返回地址,然后再定位栈B去篡改返回地址的内容
就像这样
选择这块栈即可
我们要先定位这个位置然后将"栈地址3"篡改为返回地址,由于栈地址的偏移地址会随机化,所以这里要知道返回地址的后四位就得先拿到一个栈地址,这里正好泄露这个栈A就得了,拿到的是0xdf38
减去0xe0就是返回地址了,然后可以用 address & 0xffff 这个运算取出一个地址的后四位
然后就是用前面说过的方法填到栈上了
成功篡改栈地址3为返回地址
这时再定位这里篡改的就是返回地址里的内容了
那么现在有一个新的问题,这题我选择打onegadget,而这个地址在libc里的偏移是有五位的,比如这里libc_main是0x719e14c20840,而onegadget地址应该是0x719e14cxxxxx,也就是说篡改应该改五位,但是开头也说了用%c最大也只能改到后四位(低2字节),所以这里是要改两次的
改最后的四位和常识相似正常填地址正常篡改就得了,那改倒数第二个四位呢?其实我们可以先把地址+2放上去再改,画图好理解一点:
在内存里大概就是这样的感觉(按小端序画的)
我们用de48这个地址改的是蓝色部分(地址的最低两字节),+2后改的是绿色部分(地址的倒数第3到4字节)
所以我们就需要两次篡改去把onegadget的后八位字节分两次写进去
可以用这种方法将地址切成三段
Python |
先将中间四位地址写到对应位置
同理再把后四位写到对应位置
这样就成功在return地址填入我们的onegadget了
完整exp:
Python |
萌新刚开始写博客,有的地方可能写的很乱,欢迎大佬指正,围观的师傅们有不明白的也可以评论区留言