gdb 的基本使用
对函数调用栈的理解
pwntools 工具的基本用法
安装gdb:通过apt-get install build-essential安装基本的编译环境,都会带入gdb
安装peda:这是个python程序,对gdb功能进行了增强,例如带入了 checksec 程序,
用来检查文件信息
下载题目附件,是一个zip压缩包,解压后查看基本信息:

所有安全措施 CANARY/FORTIFY/NX/PIE 都关闭了,说明该题不需要复杂的绕过操作。接下来,把文件丢到IDA中,先看看 main 函数的源代码:
只是简单的输入和输出,并没看到跟 flag 相关的信息。继续看,发现还有个 secure 函数
函数中调用了 system(‘/bin/sh’)
所以猜测获取 flag 是通过执行 system 获得 shell,然后再执行命令。
思路梳理-1
从 IDA 中可以看出,pwn 程序只有这两个用户函数,其他的都是库函数。因此答案就在这两个函数中。停下来想想我们已知的内容:
main 函数调用了 gets(),且未限制长度,存在栈溢出,是解题的入口
secure 函数调用了 system('bin/sh'),是解题的出口
思路梳理-2
局部变量 s 是用户可以通过 gets() 输入的,只要达到特定的长度 L,就能覆盖掉黄色的返回地址。
让返回地址,也就是 EIP 指向 system(‘/bin/sh’) 所在语句对应的内存地址就能获得shell
对此,需要获取两个关键值:
要填充的数据长度L: 要覆盖掉 EBP
system('/bin/sh') 调用语句的内存地址
通过动态调试,就能获取到以上数据。具体步骤如下:
第一步:利用反汇编,查看变量的位置,为 [rbp-0x70]。由于是64位系统,要覆盖掉ebp,就要+8字节。因此 L = 0x70 + 8
第二步:还是用反汇编,获取到system函数的地址。由于要完整调用,所以取lea指令的位置:0x00000000004007b8,也就是0x4007b8
得到两个关键值之后,就可以写出利用代码了。
from pwn import *
host = 'challenge-ad62e4d28ecb18f6.sandbox.ctfhub.com'
port = 30077
p = process("./ret2text")
p = connect(host, port)
payload = bytes('A',encoding="utf8") * 0x78 + p64(0x4007b8)#类型不同不能拼接
p.sendline(payload)
p.interactive()

cat flag
