SSTI漏洞自动化利用与WAF绕过实战:fenjing工具深度解析

SSTI漏洞自动化利用与WAF绕过实战:fenjing工具深度解析 1. 项目概述从SSTI漏洞到WAF对抗的实战演练在Web安全测试的日常工作中服务器端模板注入SSTI漏洞因其强大的利用潜力一直是渗透测试人员和红队成员关注的重点。它不像SQL注入那样广为人知但一旦成功利用往往能直接获取服务器权限危害极大。然而随着企业安全意识的提升Web应用防火墙WAF的部署越来越普遍传统的SSTI利用Payload往往在发出请求的瞬间就被拦截测试工作常常陷入僵局。这时一个名为fenjing的工具进入了我的视野。它不仅仅是一个漏洞检测工具更是一个集成了自动化Payload生成、WAF绕过和漏洞利用的“瑞士军刀”。今天我就结合自己多次在内外网渗透测试中的实战经历来详细拆解如何使用fenjing高效、隐蔽地完成从SSTI漏洞发现到绕过WAF成功利用的全过程。无论你是刚开始接触Web安全的爱好者还是苦于WAF拦截的资深安全工程师这篇指南都将提供一套清晰、可复现的实战思路。简单来说fenjing的核心价值在于“自动化”和“智能化”。它内置了对多种常见模板引擎如Jinja2、Twig、Smarty等的语法解析和Payload生成逻辑并能通过多种编码、混淆、分割等技术尝试绕过WAF的规则匹配。你不需要再手动记忆那些冗长且易被拦截的Payload也不需要花费大量时间手工Fuzz绕过姿势。fenjing试图将安全研究员在对抗WAF过程中积累的经验转化为可以自动执行的算法。接下来我将从环境准备、核心原理、实战操作到深度对抗一步步带你掌握这门“艺术”。2. 核心原理与工具设计思路拆解2.1 SSTI漏洞的本质与利用链构造要理解fenjing的强大首先得明白SSTI漏洞为什么危险以及手工利用的难点在哪里。模板引擎是为了将动态数据变量嵌入到静态页面模板中而设计的比如Jinja2中的{{ 7*7 }}会被渲染为49。漏洞的产生在于应用将用户输入未经充分过滤就直接拼接进了模板语句中进行渲染。例如一个接收name参数并渲染Hello {{name}}!的应用如果用户传入name{{config}}就可能泄露Flask的配置信息。手工利用SSTI通常遵循一个“步步为营”的链条1. 检测漏洞并识别模板引擎类型-2. 寻找并调用危险的内置函数或对象-3. 利用这些函数构造文件读写或命令执行的Payload。例如在Jinja2中我们可能会利用__class__、__mro__、__subclasses__()这条链来回溯到object基类再从其子类中找到os模块或subprocess.Popen类最终实现命令执行。这个过程不仅需要深厚的知识储备而且构造出的Payload往往很长特征明显极易被WAF识别。2.2 WAF的防御机制与fenjing的绕过哲学主流的WAF如Cloudflare、ModSecurity、阿里云盾等通常基于规则正则表达式匹配和语义分析来拦截攻击。它们会维护一个庞大的恶意特征库一旦检测到请求中含有os.system、eval、__import__等关键词或者{{、}}等模板语法与危险函数组合出现时就会触发拦截。fenjing的绕过思路正是针对这些防御机制的“七寸”进行设计关键词分割与混淆将os和system拆分成两个变量或通过字符串拼接生成避免直接匹配。多种编码方式对Payload进行URL编码、HTML实体编码、十六进制编码、Unicode编码等干扰WAF的解析。利用模板引擎特性不同引擎有特殊的语法可以替代常见写法。例如Jinja2中可以使用|attr()过滤器来替代点号.调用属性使用request.args.x来替代request.args[‘x’]以绕过对中括号的检测。Payload变异与Fuzzfenjing内置了大量绕过“模板”通过排列组合自动生成成千上万种变体进行测试从中找出能绕过当前WAF规则的那一个。它的设计哲学是将手工测试中“灵光一现”的绕过技巧转化为系统性的、可穷举的测试流程。工具负责生成和尝试所有可能性测试者则专注于目标分析和结果判断。2.3fenjing的工作流程与架构理解其工作流程能帮助我们在使用时更好地定位问题。fenjing通常以命令行交互模式运行其内部处理流程可以简化为以下几步信息收集与引擎识别用户提供目标URL和测试参数。工具可能会先发送一些无害的探测Payload如{{7*‘7’}}根据返回结果是49还是7777777来判断模板引擎类型和漏洞是否存在。Payload生成器启动根据识别的引擎类型调用对应的Payload生成模块。该模块基于一个“语法树”和“绕过规则库”来构造Payload。WAF绕过层介入生成的原始Payload会送入“绕过处理器”。这里会应用前述的各种混淆、编码、分割技术产生一批候选Payload。智能发包与检测工具将候选Payload依次发送给目标并分析HTTP响应。它不仅仅看返回状态码因为WAF可能返回200但内容被阻断更会智能分析响应内容中是否包含了Payload执行的“证据”比如计算结果的回显、特定错误信息、或者通过盲注技术判断的布尔值。结果报告与利用将成功的Payload报告给用户并可能进一步提供交互式Shell或文件管理功能。3. 环境准备与工具部署详解3.1 本地测试环境搭建在直接对真实目标进行测试前强烈建议在本地搭建一个包含漏洞和WAF的模拟环境。这既能让你熟悉工具流程又不会产生法律风险。这里我提供一个基于Docker的快速搭建方案。首先我们创建一个存在SSTI漏洞的Flask应用。新建一个app.py文件from flask import Flask, request, render_template_string import os app Flask(__name__) app.route(/) def index(): name request.args.get(name, Guest) # 这里存在SSTI漏洞用户输入被直接渲染 template fh1Hello {name}!/h1 return render_template_string(template) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)这个应用非常简单从URL参数name获取值并直接拼接到模板字符串中渲染构成了一个典型的Jinja2 SSTI漏洞。接下来我们使用docker-compose来部署一个带有ModSecurity WAF的Nginx作为反向代理保护我们的漏洞应用。创建docker-compose.ymlversion: 3 services: vuln-app: build: . ports: - 5000:5000 nginx-waf: image: owasp/modsecurity-crs:nginx ports: - 80:80 volumes: - ./modsecurity.conf:/etc/modsecurity.d/modsecurity.conf - ./crs-setup.conf:/etc/modsecurity.d/crs-setup.conf depends_on: - vuln-app同时需要准备一个简单的Dockerfile来构建漏洞应用以及ModSecurity的配置文件modsecurity.conf和crs-setup.conf。在modsecurity.conf中确保开启了检测引擎SecRuleEngine On并加载OWASP CRS核心规则集。这样一个受WAF保护的SSTI漏洞靶场就准备好了。运行docker-compose up即可启动。注意在真实学习中你可以从Vulhub、DVWA等知名漏洞靶场项目中找到更标准的SSTI漏洞环境它们通常包含了多种模板引擎的漏洞场景。3.2fenjing的安装与基础配置fenjing是一个Python工具推荐在Python 3.7环境中使用。安装非常简单pip install fenjing对于追求最新功能的用户也可以从GitHub克隆源码安装git clone https://github.com/ProjectAnte/fenjing.git cd fenjing pip install -e .安装完成后在命令行输入fenjing --help可以看到完整的参数列表。核心参数包括-u/--url: 指定目标URL。-p/--param: 指定存在漏洞的参数名。--method: 请求方法GET/POST。--headers: 自定义请求头用于绕过一些基础认证或添加UA伪装。--cookies: 维持会话的Cookies。--proxy: 设置代理方便使用Burp Suite等工具拦截观察流量。--full: 启用完整扫描模式尝试获取Shell。一个最基础的检测命令形如fenjing -u “http://target.com/?nametest -p name。但在实战前有几点配置心得配置心得一代理设置是必备步骤。务必通过--proxy http://127.0.0.1:8080将流量导向Burp Suite。这样你可以清晰地看到fenjing发送的每一个Payload的形态观察WAF的拦截和绕过情况这对于理解工具行为和后续手动微调至关重要。配置心得二善用自定义Header。有些WAF或应用会检查User-Agent甚至X-Forwarded-For等头。使用--headers “User-Agent: Mozilla/5.0…“可以将其伪装成普通浏览器流量。在某些情况下添加一个看似随机的X-Client-IP头可能有助于绕过简单的IP黑名单规则。4. 实战演练分步击破SSTI与WAF4.1 第一阶段漏洞探测与引擎指纹识别实战开始假设我们的目标是http://test.local/vuln?input123。我们不确定是否存在漏洞也不清楚后端模板引擎。首先使用fenjing进行初步探测fenjing -u “http://test.local/vuln?input123 -p input --proxy http://127.0.0.1:8080工具会自动发送一批无害的探测Payload例如{{7*7}}- 如果返回49可能是Jinja2/Twig。${7*7}- 如果返回49可能是Elasticsearch / Thymeleaf。% 7*7 %- 如果返回49可能是ERBRuby。${{7*7}}- 如果返回49可能是AngJS。在Burp Suite中你会看到一系列这样的请求。观察响应如果某个Payload的计算结果被回显比如页面中出现了49那么基本可以确定SSTI漏洞存在并且工具也能大概率识别出引擎类型。踩坑记录有时应用会对输入进行部分过滤或编码导致回显不明显。例如结果可能出现在HTML注释、JavaScript代码段或者被urlencode后输出。此时需要仔细查看响应源码而不仅仅是渲染后的页面。fenjing的智能检测会分析响应文本但人工复核永远是必要的。4.2 第二阶段绕过WAF获取初始信息确认漏洞后fenjing会进入更积极的攻击模式。但此时直接使用{{config}}这样的经典Payload很可能触发WAF返回403或一个通用的拦截页面。fenjing的优势在这里体现。它会开始尝试各种绕过技术。例如对于{{config}}字符串拼接{{“co”“nfig”}}或{{“c”“o”“n”“f”“i”“g”}}属性访问替代{{config|attr(“__class__”)}}虽然这里不适用但展示了|attr的用法利用请求对象在某些框架中可以通过{{request.application.__self__._get_data_for_json.__globals__[‘config’]}}这类更迂回的链式调用。fenjing的生成器会基于引擎类型尝试构造大量此类变体。这个阶段的目标可能不是直接执行命令而是先读取一些关键配置信息为后续利用铺路。例如成功获取到{{config}}后你可能从中发现SECRET_KEY、数据库连接信息、服务器路径等。实操技巧如果工具跑了一段时间仍未成功可以暂停观察Burp中已被拦截的Payload特征。例如你发现所有包含__class__的请求都被拦了但包含|attr的没有。那么可以尝试给fenjing命令增加一个--test参数如果支持或者手动构造几个Payload验证猜想再将有效的绕过思路反馈给工具的后续测试有时需要手动调整源码或等待新版本。4.3 第三阶段构造命令执行与交互式Shell在能够成功执行简单表达式后下一步就是突破沙箱或限制实现命令执行。fenjing会自动尝试构造从模板上下文到危险函数的调用链。以Jinja2为例手工链可能长这样{{””.__class__.__base__.__subclasses__()[X].__init__.__globals__[‘os’].popen(‘id’).read()}}你需要找到os模块所在的子类索引X这通常需要遍历。fenjing会自动完成这个遍历过程。在WAF面前这个长链会被拆解得“支离破碎”。fenjing可能生成如下形式的Payload{% set a “__cla” %}{% set b “ss__” %}{{””|attr(ab)|attr(“__base__”)|attr(“__subclasses__”)()|attr(“__getitem__”)(132)|attr(“__init__”)|attr(“__globals__”)|attr(“get”)(“os”)|attr(“popen”)(“whoami”)|attr(“read”)()}}它通过{% set %}定义变量进行分割使用|attr过滤器进行属性调用用__getitem__替代中括号索引。这种写法极大地增加了WAF规则匹配的难度。当命令执行成功后fenjing可能会返回命令执行的结果。更高级的用法是使用--full参数尝试自动上传一个Web Shell或建立反向Shell连接。深度对抗心得在一些防护极其严格的环境中即使如此混淆的Payload也可能被基于语义分析或机器学习的WAF拦截。此时需要结合更多上下文参数污染将Payload拆分到多个参数中。例如?arg1{{””.__class__}}arg2{{__base__}}然后在模板中组合。这需要了解应用如何拼接多个输入。请求方法混合将部分数据放在POST Body部分放在URL参数或Cookie中。时间延迟盲注如果没有任何回显fenjing可能会尝试使用基于时间延迟的盲注Payload如{{””.__class__.__base__.__subclasses__()[X].__init__.__globals__[‘time’].sleep(5) if condition else ”}}通过响应时间来判断是否执行成功。这虽然慢但极其隐蔽。利用WAF规则盲区有些WAF默认只检查前N个字节或某些特定参数。尝试将Payload放在不常见的HTTP头如X-Forwarded-Host或JSON/XML格式的POST数据中有时能奇效。5. 高级技巧与深度对抗策略5.1 手动微调Payload以应对定制化WAF完全依赖自动化工具有时会失灵特别是面对企业自研或深度定制的WAF规则时。这时就需要我们根据拦截情况手动干预Payload的构造。案例在一次测试中我发现目标WAF对request对象访问args属性进行了严格拦截。无论怎么分割request.args.x都会被拦。但是我注意到应用使用了Flask框架。Flask中除了request.args还可以通过request.values来同时获取GET和POST参数而request.values这个特征可能不在WAF规则库里。于是我手动构造了Payload{{request.values.get(‘cmd’)}}并通过另一个参数?cmdwhoami传递命令成功绕过了防御。策略总结信息收集是关键尽可能多地了解目标应用的技术栈框架、中间件、模板引擎版本。fenjing的探测结果是一个起点通过查看HTTP响应头、错误信息、静态资源等可以获取更多线索。研究模板引擎的“偏门”特性每个模板引擎都有一些不常用但功能强大的特性。比如Jinja2的namespace对象、内置的range、cycler等函数有时能用来构造无数字符串或绕过过滤。上下文感知观察漏洞点所在的模板上下文。是否导入了某些自定义模块是否有可用的全局函数或对象直接利用这些已有的“跳板”往往比从零开始构造链更短也更不易被检测。5.2 结合其他工具进行协同测试fenjing并非孤军奋战。将它与其他工具结合能形成更强大的测试矩阵。与Burp Suite的Intruder结合当fenjing识别出某个基础Payload有效但被WAF拦截时可以将这个Payload复制到Burp Intruder中使用Cluster bomb攻击类型对Payload中的多个位置如函数名、字符串分割方式进行同步Fuzz效率可能比工具的单线程序列测试更高。使用tplmap进行交叉验证tplmap是另一款经典的SSTI自动化利用工具。有时fenjing绕不过的WAF用tplmap的某个特定Payload可能成功反之亦然。两者可以互为补充。自定义字典与脚本将fenjing生成的被拦截的Payload收集起来分析其共同特征。然后编写简单的Python脚本针对这些特征进行定向变异如随机插入空白字符、换行符、特定注释符等生成一个自定义的Fuzz字典再交由Intruder进行测试。5.3 防御视角如何防范此类自动化攻击作为一名安全测试者了解攻击手段的最终目的是为了更好的防御。从防御角度看应对fenjing这类自动化工具需要多层布防输入验证与过滤治本严格禁止用户输入直接进入模板渲染。如果需要动态渲染应使用安全的模板变量替换或者使用白名单机制只允许特定的、无害的字符或模板语句。沙箱化模板执行环境如果业务必须使用动态模板应在一个严格的沙箱环境中执行移除或禁用危险的内置函数和模块如os、subprocess、eval、exec等。WAF规则精细化通用WAF规则可能不够。需要针对业务使用的模板引擎定制化防护规则。例如可以监控短时间内对同一参数发送大量不同变异Payload的请求这很可能是自动化工具在扫描。输出编码即使模板注入成功如果执行结果在输出到页面时被正确地进行HTML编码那么系统命令的结果可能会以纯文本形式显示而非被执行这能在一定程度上缓解危害但并非根本解决因为攻击者仍可能通过带外通道获取数据。代码审计与安全意识在开发阶段就引入安全代码规范定期进行代码审计避免SSTI漏洞的产生。6. 常见问题排查与实战心得记录在实际使用fenjing的过程中你肯定会遇到各种各样的问题。下面是我总结的一些常见情况及其应对方法。问题现象可能原因排查与解决思路工具运行后无任何输出或立刻退出。1. Python环境或依赖问题。2. 目标URL无法访问。3. 参数格式错误。1. 检查Python版本python –version确保3.7。使用pip list grep fenjing确认安装成功。2. 用curl或浏览器手动访问目标URL确认网络连通性和服务状态。3. 仔细检查-u参数后的URL是否用引号括好尤其当包含符号时-p参数是否正确。工具能识别漏洞但生成的Payload全部被WAF拦截。1. WAF规则非常严格通用绕过无效。2. 工具生成的Payload特征仍被识别。3. 漏洞点有额外的过滤或编码。1. 开启代理逐一分析被拦截的Payload。寻找未被拦截的“漏网之鱼”分析其特点。2. 尝试使用–delay参数增加请求间隔模拟人工操作。3. 切换到–level更高的扫描级别如果支持尝试更冷门的绕过方式。4. 考虑是否存在时间盲注的可能观察是否有timeout参数可配置。Payload执行成功但无回显。1. 命令执行结果未输出到响应中盲注。2. 存在输出长度限制或截断。3. 执行环境受限如无回显函数。1. 尝试使用DNS外带或HTTP请求外带数据。fenjing的–full模式可能会尝试这类方式。2. 尝试执行sleep 5等命令通过响应时间判断是否执行成功时间盲注。3. 尝试写入一个文件到Web目录再通过浏览器访问该文件查看结果。工具误报将正常回显识别为漏洞。1. 应用本身会对输入进行数学运算或字符串变换。2. 响应中偶然包含了与Payload相同的数字。1. 使用更复杂的检测Payload如{{7*’7’}}在Jinja2中会得到7777777而纯数学计算或巧合的概率极低。2. 人工验证尝试注入一个绝对唯一的字符串如{{“ssti_test_xyz”}}查看是否原样输出。运行过程中被目标IP封禁。工具发送请求频率过高触发目标速率限制或入侵防御系统IPS。1. 立即停止扫描。2. 后续测试时务必使用–delay或–timeout参数降低请求频率如–delay 2表示每个请求间隔2秒。3. 使用代理池如果工具支持来切换源IP。最后的心得分享fenjing这类自动化工具极大地提升了SSTI漏洞测试的效率但它绝不是“银弹”。它封装的是已知的、模式化的攻击手法。面对顶尖的、深度定制的防御体系真正起决定性作用的依然是测试者对漏洞原理、模板引擎特性、编程语言和网络协议的深入理解以及那份在反复受挫中依然能冷静分析、另辟蹊径的耐心和创造力。工具解放了我们的双手但思考和策略永远无法被自动化替代。每次测试结束后花时间复盘一下工具成功或失败的Payload理解其背后的绕过原理这份积累才是你安全能力成长的真正阶梯。