首先对栈溢出原理与ret2text题型进行介绍,介绍搬自ctfwiki。
栈溢出原理
介绍
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃,重则可以使攻击者控制程序执行流程。此外,我们也不难发现,发生栈溢出的基本前提是:
程序必须向栈上写入数据。
写入的数据大小没有被良好地控制。
ret2text
原理
ret2text 即控制程序执行程序本身已有的的代码 (即, .text 段中的代码) 。其实,这种攻击方法是一种笼统的描述。我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码 (也就是 gadgets),这就是我们所要说的 ROP。
这时,我们需要知道对应返回的代码的位置。当然程序也可能会开启某些保护,我们需要想办法去绕过这些保护。
题目分析:
首先查看一下文件保护机制:

可以看出程序是 32 位程序,且仅开启了栈不可执行保护。接下来我们使用 IDA 反编译该程序:



可以看出程序在welcome函数中使用了 gets 函数,显然存在栈溢出漏洞,主函数只执行了welcome函数。
又发现getFlag函数中存在调用system("/bin/sh")的代码,那么如果我们直接控制程序返回至 system的地址 ,那么就可以得到系统的 shell 了。
下面就是我们如何构造 payload 了,首先需要确定的是我们能够控制的内存的起始地址距离welcome函数的返回地址的字节数,这个字节数可以利用ida查看相应参数后进行计算,对于本题则是找s数组对应的参数,同时由于是64位程序,最后得出的偏移量应该+8。
对pwn程序进行gdb调试,执行到gets函数,根据在ida中得到的s关于rsp的偏移和当前rsp和rbp的地址,可以计算出s相对于栈底(rbp)的偏移量,进而可以得到s相对于welcome返回地址的偏移量。当然,也可以直接利用ida中给出的s相对于rbp的偏移量来得出相对于返回地址的偏移量。

得到偏移量后则可以进一步构造栈溢出,将welcome函数的返回地址覆盖为我们想要执行的system("/bin/sh")的地址,但是需要注意,如果覆盖为getFlag函数地址,会使栈进行偏移,此时利用之前计算出来的偏移量无法构成栈溢出来解题,所以直接将返回地址覆盖为system的地址可以较简单的得到flag。
最后的exp如下
from pwn import *
r=remote('121.36.4.0',1008)
sys_addr=???
payload=b'a'*(???)+p64(sys_addr)
r.sendline(payload)
r.interactive()