XCTF-pwn1-WP

Posted on Nov 5, 2020

今天的课特别的多,没有多少的空闲时间,原本可以做题的C程课也被写一个愚蠢的排序测试程序占用了。

其实今天没有做完这道题,因为服务器维护了,但是我已经总体上完成了这道题,就差连接服务器了,所以就当我做完了这题吧。题解也只能明天再来完善了。我现在对CTF-pwn的大致感觉就是痛并快乐着,同时深深的感到自己的能力仍然不足,总体上来说还是要继续好好学习。虽然pwn这条路可能很难走,但总比做自己没兴趣的ACM强。

我们来说这道题,有三个知识点:

  • canary泄露
  • 使用gadget
  • 利用libc

这是我第三次绕过canary,第一次是使用格式化字符串进行的泄露,第二次是通过数组越界直接避免了对canary的修改。而这一次则是通过栈泄露获得canary。我们会发现,要实现栈泄露,需要多个条件:

  • 存在栈溢出的漏洞(这是显然的,如果没法栈溢出,那也就没有绕过canary的必要了)
  • 存在合适的输出函数,需要在我们进行一次栈溢出之后还能够输出的函数,且该函数需要能够输出我们需要的区段。
  • 同函数中多次的栈溢出机会,第一次栈溢出只能实现泄露canary,无法控制程序执行流程,我们还需要第二次的栈溢出来实现对流程的控制。

上面的三点可能需要结合下面的exp来理解。

我们先检查一下安全措施:

发现安全措施都开得差不多了。

先跑一下看看程序大致在做什么

提供了输入和输出和退出的功能,并且可以无限进行。再到ida里看一下

我们发现这里存在溢出点,于是我们就可以考虑构造payload。canary的首位一般为\x00,这样设置的目的是在字符串输出的时候截断,避免puts这样的函数把canary输出出来。那么我们只要构造一个payload把这个\x00覆盖掉就行了。所以就有payload='a'*(0x90-0x8),这样的话,我们可以看到

方框中的就是canary了,其首位变成了0a,也就是'\n',然后我们就可以接收之。

对于64位程序,由于多了很多寄存器,前六个参数会依次使用寄存器传递(rdi, rsi, rdx, rcx, r8, r9),我们需要通过rdi来传递地址,这个时候就需要ropgadget了

这也是我第一次使用gadget来传参

这样我们就获得了canary,就可以肆无忌惮的栈溢出了。

然后我们发现,在程序中并没有后门可以利用,附件中又给了一个libc,自然的我们会想到利用libc中的system函数来调用shell。然后我就发现很奇怪的是使用libc来调用system("/bin/sh")是无效的(这是相对保险的方法),网络上的说法也有很多,现在我还不是特别了解原因。有说是题目给的libc是假的,也有说是溢出长度不够,这也是一个坑,以后再研究。

解决的方法是使用onegadget来获得偏移地址(并不能保证不需要使用寄存器传参)

这就是最终的exp。