强网2023 pwn-ez_fmt
ez_fmt
一、总结反思
这道题呢肯定是不算难的,但是当时就是没有做出来。
首先是分析出了格式化字符串漏洞的(至少漏洞点也是找对了的),想到可能要劫持libc_main上面去,(毕竟只能读一次,一次肯定是不够用的)但是,偏移量没找对。然后就是劫持完了之后应该怎么用这个问题,确实没想到。
=>后续发现得一个问题的补充:
1、这里开了ALSR,也就是说可能会导致libc的地址不准确,有一定的概率爆破的问题的存在…所以针对这种情况,后面也会继续补充一下操作的思路
2、注意版本是2.31的,我拿的22的ubuntu去打,那肯定是错的QAQ,记得patchelf改相应的libc版本,否则调试出来就会错的很离谱。(我就说我怎么调步对QAQ是这样的)
二、题目解析
1、checksec:
1 | Arch: amd64-64-little |
2、IDA:
从这里也可以看出很明显的格式化字符串漏洞,但是只有一次!!其次我们在gift函数里面看到了直接给出了栈顶函数的地址,可以确定ret的地址(找对偏移量)。再一个,给了libc文件,也给了libc_csu函数,这些都可以作为后面攻击的手段。
(走到这里其实思路就很多了,我可以在栈上打ret2libc,前提是我要泄露一个正确的基地址,我同样也可以使用one_gadget的方法直接获得shell)
【所以,以后遇上这种只有一次的格式化字符串也可以这样子思考,我们肯定是需要劫持到某一个固定的位置上去的】
思路:
1、首先没开pie,但是考虑到后面两种攻击方法,所以我无论如何都需要把一个基地址给带出来。
2、利用格式化字符串劫持到栈上(确定偏移,即到libc_start_main)这里需要两个要素,第一个是libc的基地址,第二个就是偏移,确定好了这些量以后就可以成功做到劫持了。
(怎么泄露那个基地址讷?这里我可以利用这个printf函数)
3、在完成了上面的这些操作之后,才轮得到我们进行攻击的过程(栈上攻击的常见手段)
两种思路:
1、ret2libc
2、one_gadget
三、攻击过程与原理解释
1、偏移量确定
首先要确定栈偏移量:
(我个人比较喜欢这么找-_-)
然后确定到ret函数的偏移:
这里最后算下来的结果是19(第19个参数:0xc+1+6)
(菜鸡吐槽,你要是这里看到的是libc+128,那说明你没换libc附件,赶快换吧QAQ别问,问就是搞了一下午最后偏移死活算不对)
2、利用printf函数泄露libc基地址
这里我们通过printf的格式化字符串漏洞泄露第19位的那个地址(就是上图我们对应的libc_main_start+243)
所以最后你接受得那个地址还要减去243才是我们libc_main_start得真实地址,这样算完了之后才算是真正得到了libc_base的地址。
3、对应栈上的攻击
这里开始就提供了两种攻击思路:
(1)利用one_gadget来实现
(毕竟开了ALSR,多少带点概率问题)
【简单回忆一下one_gadget,这里列出的是可以使用的,但需要满足下面的这些条件】
这里试下来用的是第二组。
(这里抄一下大佬的QAQ,我没太看懂它布栈的思路)
pay=(b’%’+str(one_gadget&0xffff).encode()+b’c%10hn’
pay+=b’%’+str(((one_gadget>>16)&0xffff)-(one_gadget&0xffff)).encode()
pay+=b’c%11$hn’).ljust(0x20,b’\x00’)
#这里是在对应参数位置,没看懂。大概明白是在进行取位运算
pay+=p64(stack+0x68)+p64(stack+0x68+2)
#没看懂QAQ
(原文链接:https://blog.csdn.net/qq_65165505/article/details/135044734)
按照这个思路下来的完整exp:
1 | from pwn import* |
(2)劫持回到read函数(改read的返回地址)
因为read输入的buf位置不变,调用前要push的返回地址永远在stack_top-8,要是buf的位置在调用栈的上面,就能改返回地址。
怎么改?
用libc_init_csu,pop把栈顶位置降低,让read的返回地址在buf的范围之中。
libc_init_csu:
read:
分析:在最开始fmt的过程中,写入输出占了16个字节。
要让pop之后栈顶仍在buf的范围中,同时ret能够准确跳回到read函数,就需要有两个pop。
前面泄露的过程基本一样,不同在于这里利用了read函数顺便带出来了libc_base,后面的打法也可以参照ret2libc的写法
1 | from pwn import* |