Loading... <!-- wp:paragraph --> <p>今天的课特别的多,没有多少的空闲时间,原本可以做题的C程课也被写一个愚蠢的排序测试程序占用了。</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>其实今天没有做完这道题,因为服务器维护了,但是我已经总体上完成了这道题,就差连接服务器了,所以就当我做完了这题吧。题解也只能明天再来完善了。我现在对CTF-pwn的大致感觉就是痛并快乐着,同时深深的感到自己的能力仍然不足,总体上来说还是要继续好好学习。虽然pwn这条路可能很难走,但总比做自己没兴趣的ACM强。</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>我们来说这道题,有三个知识点:</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul><li>canary泄露</li><li>使用gadget</li><li>利用libc</li></ul> <!-- /wp:list --> <!-- wp:paragraph --> <p>这是我第三次绕过canary,<span class="external-link"><a class="no-external-link" href="http://www.cjovi.icu/2020/11/03/mary_morton/" target="_blank"><i data-feather="external-link"></i>第一次</a></span>是使用格式化字符串进行的泄露,<span class="external-link"><a class="no-external-link" href="http://www.cjovi.icu/2020/11/04/xctf-stack2/" target="_blank"><i data-feather="external-link"></i>第二次</a></span>是通过数组越界直接避免了对canary的修改。而这一次则是通过栈泄露获得canary。我们会发现,要实现栈泄露,需要多个条件:</p> <!-- /wp:paragraph --> <!-- wp:list --> <ul><li>存在栈溢出的漏洞(这是显然的,如果没法栈溢出,那也就没有绕过canary的必要了)</li><li>存在合适的输出函数,需要在我们进行一次栈溢出之后还能够输出的函数,且该函数需要能够输出我们需要的区段。</li><li>同函数中多次的栈溢出机会,第一次栈溢出只能实现泄露canary,无法控制程序执行流程,我们还需要第二次的栈溢出来实现对流程的控制。</li></ul> <!-- /wp:list --> <!-- wp:paragraph --> <p>上面的三点可能需要结合下面的exp来理解。</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>我们先检查一下安全措施:</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":435,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/屏幕截图-2020-11-06-090031.png" alt="" class="wp-image-435"style=""></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>发现安全措施都开得差不多了。</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>先跑一下看看程序大致在做什么</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":436,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/屏幕截图-2020-11-06-091236.png" alt="" class="wp-image-436"style=""></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>提供了输入和输出和退出的功能,并且可以无限进行。再到ida里看一下</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":437,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/屏幕截图-2020-11-06-091417.png" alt="" class="wp-image-437"style=""></figure></div> <!-- /wp:image --> <!-- wp:image {"align":"center","id":438,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/屏幕截图-2020-11-06-091405.png" alt="" class="wp-image-438"style=""></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>我们发现这里存在溢出点,于是我们就可以考虑构造payload。canary的首位一般为\x00,这样设置的目的是在字符串输出的时候截断,避免puts这样的函数把canary输出出来。那么我们只要构造一个payload把这个\x00覆盖掉就行了。所以就有<code>payload='a'*(0x90-0x8)</code>,这样的话,我们可以看到</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":443,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/QQ截图20201106124942.png" alt="" class="wp-image-443"style=""></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>方框中的就是canary了,其首位变成了0a,也就是'\n',然后我们就可以接收之。</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":444,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/QQ截图20201106125107.png" alt="" class="wp-image-444"style=""></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>对于64位程序,由于多了很多寄存器,前六个参数会依次使用寄存器传递(rdi, rsi, rdx, rcx, r8, r9),我们需要通过rdi来传递地址,这个时候就需要ropgadget了</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":447,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/QQ截图20201106192013.png" alt="" class="wp-image-447"style=""><figcaption>这也是我第一次使用gadget来传参</figcaption></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>这样我们就获得了canary,就可以肆无忌惮的栈溢出了。</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>然后我们发现,在程序中并没有后门可以利用,附件中又给了一个libc,自然的我们会想到利用libc中的system函数来调用shell。然后我就发现很奇怪的是使用libc来调用system("/bin/sh")是无效的(这是相对保险的方法),网络上的说法也有很多,现在我还不是特别了解原因。有说是题目给的libc是假的,也有说是溢出长度不够,这也是一个坑,以后再研究。</p> <!-- /wp:paragraph --> <!-- wp:paragraph --> <p>解决的方法是使用<span class="external-link"><a class="no-external-link" href="https://github.com/david942j/one_gadget" target="_blank"><i data-feather="external-link"></i>onegadget</a></span>来获得偏移地址(并不能保证不需要使用寄存器传参)</p> <!-- /wp:paragraph --> <!-- wp:image {"align":"center","id":448,"sizeSlug":"large"} --> <div class="wp-block-image"><figure class="aligncenter size-large"><img src="https://www.cjovi.icu/usr/uploads/2020/11/QQ截图20201106192147-1024x905.png" alt="" class="wp-image-448"style=""></figure></div> <!-- /wp:image --> <!-- wp:paragraph --> <p>这就是最终的exp。</p> <!-- /wp:paragraph --> 最后修改:2020 年 12 月 30 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,那听听上面我喜欢的歌吧