canary绕过感悟随记(pwn入门)

canary绕过感悟

最近接触到了修改TLS结构体来绕过canary,翻了翻之前刚开始学习canary基础时的随记,感觉蛮好的,就分享下吧。

canary的位置在哪里?打程序时canary在s也就是ebp的前面,也就是说,得先把canary打下来,才能继续把s也就是ebp打下来,来到r的位置,也就是来到eip的位置.然后就可以控制程序了,跳转到我们想跳转的地方,执行shell获得权限后cat flag.
为了防住我们,加了一个保护,就是说,在打到r,还没到r,打到s之前的路上设置了一个屏障,它会先判断你,输入的数据和它内部储存的数据是不是一样的,只有一样的才放你过去.
那么,我们要想打到r的位置,就必须得把canary的值给泄露出来,先打到canary的位置.在把我们泄露出的canary给它,放我们过去,然后,我们就可以一路打到r的位置,控制程序了.
所以核心就是如何让程序泄露出canary,并且我们可以拿到程序泄露出的值.
谈谈canary的大小:
经验之谈,对于64位的机子canary就是固定的8字节, 地址为16位,对于32位的机子canary就是固定的4字节,地址为8位
对于利用格式化字符串漏洞获取canary
如果是32位的就用4个a或者4个其他字符后面加-%x
如果是64位的就用8个a或者8个其他字符后面加-%p
加-可以有效的把他们分隔开,毕竟我们要数它的数值.
先拓展一点知识:32位的就用aaaa+n%x
%p可以打印出地址,我们可以吧canary的地址连带着给打印出来
64位的就用aaaaaaaa+%p
比如64位的机子,如果确定了canary位置的数值是16那么使用%p$16就可以只把canary的值打出来.
对于覆盖截断字符获取canary,就是最后记得加一个a字符上去覆盖就行了.
谈下怎么接收canary:
有两条接收的方式
canary = u32(p.recv[0x65:0x68].rjust(4, b'\x00'))
这个适用于覆盖截断字符获取canary
canary = int(p.recv().split(b'-')[-2], 16)
这个适用于利用格式化字符串漏洞获取canary
下面我来详细解释一下这两种接收方式:
对于canary = u32(p.recv[0x65:0x68].rjust(4, b'\x00'))
简单来说就是首先接收数据,仅仅接收0x65 ,0x66 ,0x673个字节的数据,接收的数据不够4字节的部分用\x00从最右边开始填充。
下面我来仔细谈谈每一部分的含义:
[0x65:0x68]代表的意思就是说左闭右开,接收3个指定字节的数据,指定在打到了65,66,67这3个字节位置,而canary就是0x70-0xC= 0x64开始的四个字节,因为最低字节已经被覆写,且默认为\x00,因此只要获取0x65,0x66,0x67三个字节的值,再拼接一个\x00就可以得到Canary了
这个是假设总共要打70个长度,canary在0xc的位置,你刚开始打程序打到canary的位置总共是打了0x70-0xc计算一下就是0x64的位置了,那么,32位的机子.canary的值为4个字节,所以我们接收0x65,0x66,0x67就可以接收到canary前面的3个字节了.[0x65:0x68]左闭右开可以达到要求,而canary规定最后一个字节为\x00,用rjust(4,b'\x00')可以达到要求.
rjust(4,b'\x00')这个的意思就是说,总共接收4个字节的数据,先接收完所有数据。在不够4个字节的部分全都接上\x00。\x00这就是canary屁股上的值规定的那个值。
ljust和rjust都是用来填充的函数,l  代表left,从左边填充,r  代表right从右边填充,由于canary的最后两位一定是\x00所以选择rjust从右边填充,这个4就是代表只接收4个字节就行了,同时如果不够4个字节的部分在最右边全部用\x00填充
这里有一张图片比较清晰的解释了这两个函数的作用和用法。
需要补充一点的就是由于这个发送给靶机的字节是按照小端序发送的,所以这个打印出来的数据其实是左右相反的,这就是为什么rjust的aaaa在最左边,ljust的aaa在最右边,按照小端序来排的,但是实际上,rjust,right,右边,是从最右边开始填充不够0x78也就是栈溢出偏移量的字节a的,一直填充到够了(0x70+8)的字节到达r的位置.ljust就相反,从左边开始填充,rjust是从最右边开始填充字节a的,所以被填充的a是最后被靶机收到的,先被靶机接收到的是shellcode的值,但是shellcode的值填不满(0x70+8)的空间,剩下的就交给字节a填充到达r的位置了,然后在r的位置放上可以返回到shellcode位置的地址执行shellcode就可以提权拿到flag了,其实这也是一种题目的解题思路哦。

 9faeb1ca0a6d493490ff124584b972c6.jpg

 用u32是因为没有用%x或者%p,如果用了%x或者%p就不需要这样子操作了,就得前面加上int了.
.也就是说覆盖截断字符获取canary需要用到这个u32和u64的.

47f397da8d064945a9edab2ade7e40ab.jpg

 canary = int(p.recv().split(b'-')[-2], 16)
这个就适用于那个利用格式化字符串漏洞获取canary了,解释一下.split函数的作用就是去掉一些东西获取一些东西截断字符仅仅取一部分,从最后面开始截取就是-2的作用如果是+2就是从最前面开始截取
我们使用-%x或者-%p打印出来canary 的值的,那么,会带有  -  这个符号这样这个截断函数就有作用了,它会从最后开始取,取从倒数第2个-符号到最后一个-符号之间的数值,就是canary,canary是最后一个打印出来的数值
split(b'-')[-2], 16这就是说去掉了canary带有的-符号,为啥是-2呢?因为从最后开始取,负号从屁股开始取值,而最后一个是这样的''-78252d78-''canary前后都会有这个-符号,所以-2就是说取倒数第二个这个符号-和最后一个这个-之间的值,也就得到了canary,
屁股后面的这个16的意思就是表明接收到的数字是什么进制的数,16就是说接收到的数是16进制的数,如果接收到的是2进制那么屁股后面就是写2就行了,int就是把它转换成10进制.
其实刚才那个太麻烦了,因为脚本发送的东西是payload_1 = b'%x-' * ( 6 + 25)这样的,最后出来的是很多很多的字符-字符-字符-....所以要截断,其实知道了大小是31后可以直接定点打印31位的值就行了
如果使用定点打印的话,就这么写
payload_1=%31$x
然后接收利用就行了简单多了.....
canary=int(p.recv(16),16)
先说一下int的作用,int就是把16进制转换为10进制,无论是%x还是%p打印出来的都是16进制的所以都得用int来转换一下为10进制
打到了r的位置我们可以利用p32()或者p64()发送16进制的地址,也可以用p32()或者p64()来打包10进制的canary,之后p64()或p32()会把这个发送给靶机,并且发送的途中转换成靶机可以看得懂的东西.
payload_1=%31$x
canary=int(p.recv(16),16)
这里因为%x打印出来的不带有0x所以不需要把这个去掉,这里有一个细节点就是说如果是%p打印的话代码就得修改了
因为%p打印出来的最开头是0x这个格式
得把0x去掉后面的才是canary的值所以说64位的机子就要修改一下,加一个p.recvuntill('0x')去掉0x.
payload_1=%31$p
p.recvuntill('0x')
canary=int(p.recv(16),16)
把这个0x给去掉就ok了
用这个脚本也是一样的,64位的机子要去掉0x
p.recvuntill('0x')
canary = int(p.recv().split(b'-')[-2], 16)
32位的机子就不需要了.
理解透彻了,啊!!!!!!
找到了一个可以帮助我理解p32() u32()和hex()关系的东西了,哈哈哈啊哈哈哈.

39986954741649cea9c070015f02c13c.jpg

 

对于p32()和p64()以及u32()和u64()还有那个int()还是不太理解,慢慢来吧.
可能是为了美观的打印出canary到终端的屏幕上,才用了int() print  {(hex()})然后再打包.
反正10进制和16进制都是需要用p32()或者p64()打包的,打包成机器能够识别的东西才行
现在我发现机器只接受byte字节,如果你发送的是byte字节的数据就不要p32或者p64打包比如;
canary = b'\x00'
for i in range(3):
 for b in range(0, 256):
  payload = b'a' * (0x70 - 0xC) + canary + bytes(b)
  # 下面是伪代码
        if (recv没报错):
            canary += bytes(b)
            break
这里的payload中的canary就不需要那个p32()或者p64()打包了因为你打包之后的东西也就是这样子的:\x00的类型.
        canary = b'\x00'    
\x00   

这里又有一个新的脚本,也是canary格式化字符串漏洞的脚本利用%31$x的

5a69e556738a4eb3aac2fe44e54f2bcf.jpg

 下面这个是比较清晰的脚本,也是利用%31$x的

51537e5078d0495694efd1297d7c3a6f.jpg

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值