资讯详情

Gixy HTTP Splitting 插件实战:检测 Nginx 配置中的 CRLF 注入与 HTTP 响应拆分漏洞

📅 2026/9/25 3:21:36 | 华诺云谱 👁 阅读
Gixy HTTP Splitting 插件实战:检测 Nginx 配置中的 CRLF 注入与 HTTP 响应拆分漏洞
静态分析应用安全【免费下载链接】gixyNginx configuration static analyzer项目地址https://gitcode.com/gh_mirrors/gi/gixy点击查看免费下载导读HTTP SplittingHTTP 拆分是 Nginx 配置中一类常见的输入校验缺陷引发的注入攻击攻击者利用换行符\n或回车符\r向请求或响应中注入额外内容进而污染代理转发的请求头或用户收到的响应头。本文以 Gixy 官方文档 docs/en/plugins/httpsplitting.md 为骨架结合http_splitting插件的源码实现gixy/plugins/http_splitting.py与测试用例tests/plugins/simply/http_splitting/完整讲解该漏洞的成因、三类高危排查要点、一条可复现的利用链以及插件底层变量能力分析的检测原理最后给出可直接落地的修复方案与 Gixy 命令行使用方式。读完本文你将能够独立审计自己的 Nginx 配置识别并消除所有可能触发 CRLF 注入的指令写法。HTTP Splitting 是什么HTTP Splitting 是一类利用不正确的输入校验improper input validation发起的攻击通常有两个攻击方向HTTP Request Splitting请求拆分目标通常是位于 Nginx 背后的 Web 应用。攻击者在请求中植入换行符使 Nginx 生成的、转发给上游的请求被拆分成多个请求从而注入伪造的请求头或请求体。HTTP Response Splitting响应拆分目标通常是 Nginx 的用户浏览器。攻击者通过注入换行符污染 Nginx 生成的响应使响应被拆分成多个响应进而注入伪造的响应头如 Set-Cookie为 XSS、会话固定Session Fixation等攻击铺路。漏洞的本质成因是攻击者能够把换行符\n或回车符\r插入到由 Nginx 创建的请求或响应中。HTTP 协议用 CRLF\r\n分隔头部因此任何未经过滤的换行符一旦流入头部字段就等于给了攻击者另起一行的能力。如何定位这类漏洞三个排查要点官方文档给出了三个必须始终关注的排查方向检查用于创建请求的指令中使用的变量。rewrite、return、add_header、proxy_set_header、proxy_pass这类指令负责构造发往客户端的响应头或发往上游的请求头其中引用的变量可能包含 CRLF 字符需要逐一审视。重点关注$uri与$document_uri变量及其使用位置。这两个变量保存的是 URL 解码后的值decoded URL-encoded value。攻击者可以先把%0d%0aURL 编码的 CRLF写进请求路径Nginx 在规范化路径时会将其解码为真正的\r\n从而使这两个变量天然携带换行符。警惕从排他范围exclusive range正则中捕获的变量例如(?Pmyvar[^.])。[^.]表示除了点号之外的任意字符它并不排除换行符因此捕获组的值可能包含\n或\r。漏洞示例一个来自排他范围的完整利用链文档给出了一段存在漏洞的典型配置server { listen 80 default; location ~ /v1/((?action[^.]*)\.json)?$ { add_header X-Action $action; return 200 OK; } }该配置用命名捕获组(?action[^.]*)从请求路径中提取 action并把它的值直接写入add_header X-Action $action的响应头。注意[^.]*是一个排他范围它只排除了点号并不排除换行符。攻击者发送如下请求即可完成利用GET /v1/see%20below%0d%0ax-crlf-header:injected.json HTTP/1.0 Host: localhost HTTP/1.1 200 OK Server: nginx/1.11.10 Date: Mon, 13 Mar 2017 21:21:29 GMT Content-Type: application/octet-stream Content-Length: 2 Connection: close X-Action: see below x-crlf-header:injected OK攻击者在请求路径中写入%0d%0aURL 编码的 CRLF成功在响应中注入了额外的x-crlf-header: injected响应头。这个攻击之所以成立文档总结了四个环环相扣的原因add_header指令不会对输入值做编码或校验它假设配置作者清楚自己行为的后果Nginx 在处理 location 之前会对路径值做规范化normalize%0d%0a在此过程中被解码为真实换行符$action的值来自一个排他范围正则[^.]*该范围不排除换行符最终$action的值实际等于see below\r\nx-crlf-header:injected一旦被用于构造响应头换行符之前的see below成为X-Action头的值换行符之后的x-crlf-header:injected则成为注入的新响应头。Gixy 如何检测插件源码原理http_splitting插件位于 gixy/plugins/http_splitting.py它被 Gixy 注册为高危HIGH级别问题其summary为Possible HTTP-Splitting vulnerability.description为Using variables that can contain \n or \r may lead to http injection.检测覆盖的指令集合与文档中的排查清单完全一致directives [rewrite, return, add_header, proxy_set_header, proxy_pass]插件的核心审计逻辑在audit()方法中处理流程如下通过_get_value()从指令中提取出值value部分。proxy_pass取第一个参数URL 本身rewrite、return、add_header、proxy_set_header等取第二个参数真正的值见_get_value的实现。这也解释了为何纯数字形式的return 403不会被报告——它没有第二个参数对应测试 return_403_fp.conf。调用compile_script(value)实现在 gixy/core/variable.py把 Nginx 脚本字符串拆分成字面量 变量的序列该函数用正则\$([1-9]|[a-z_][a-z0-9_]*|\{[a-z0-9_]\})提取形如$uri、$1、${var}的变量引用。对每个变量调用var.can_contain(\n)/var.can_contain(\r)gixy/core/variable.py判断该变量的可能取值集合中是否包含危险字符。命中则生成 Issuereason形如At least variable $action can contain \n并把directive与var.providers变量的来源指令链gixy/core/variable.py一起上报从而在报告中还原变量到底来自哪个正则捕获组或哪个set指令。服务端代理指令的差异化检查源码中有一个容易被忽视的细节——服务端proxy 侧与非服务端指令的检查范围不同server_side directive.name.startswith(proxy_) for var in compile_script(value): char if var.can_contain(\n): char \\n elif not server_side and var.can_contain(\r): char \\r else: continue即proxy_pass与proxy_set_header以proxy_开头的指令只检查\n而rewrite、return、add_header只检查\n与\r两者。这与两处注入的实际危害面相关请求拆分场景对换行符的敏感度更高而响应头场景 CRLF 都要防。对应测试 proxy_pass_cr_fp.confproxy_pass http://10.10.10.10/$1;$1来自(.*)即验证了代理场景下\r不报这一行为。底层变量可能包含能力分析can_contain是本次检测的关键它的判断依据来自 gixy/core/regexp.py 实现的 Nginx 正则能力分析器边界集boundary变量若被set指令或其他边界约束限定先检查边界字符集正则捕获组变量若来自 location 正则的捕获组则对捕获组对应的正则 Token 树调用can_contain。例如[^.]会被解析为InToken加上NegateToken其语义是点号之外的任意字符而换行符不在排除列表内因此can_contain(\n)返回 True——这正是排他范围容易中招的根本原因。与之对比.json中的.对应AnyToken其CATEGORIES[ANY]明确排除了字符 10\n详见 gixy/core/regexp.py依赖变量链变量若由其他变量拼接而成如set $x $uri$y则递归检查其依赖链上任意一环是否可能包含危险字符。这套分析机制让 Gixy 不必真正执行 Nginx就能从正则与变量依赖的静态结构上推断出某个变量的取值里可能混入\n/\r这也是它能覆盖$uri、$document_uri以及各类捕获组的原理所在。测试用例对照哪些写法会报、哪些不会仓库为http_splitting插件提供了完整的样例配置tests/plugins/simply/http_splitting/可直接对照学习其中_fp后缀表示不应触发误报false positive的用例配置文件内容要点预期结果add_header_uri.confadd_header X-Uri $uri;报告$uri含解码后换行proxy_set_header_ducument_uri.confproxy_set_header X-Original-Uri $document_uri;报告proxy_pass_ducument_uri.confproxy_pass http://upstream$document_uri;报告rewrite_uri.confrewrite ^ http://some$uri;报告proxy_pass_lf.confproxy_pass http://10.10.10.10/$1;$1来自([^/])报告[^/]可含\nproxy_pass_cr_fp.confproxy_pass http://10.10.10.10/$1;$1来自(.*)不报.不含\n且代理场景不查\rdont_report_not_resolved_var_fp.conf无法解析的变量不报return_403_fp.confreturn 403;不报无第二个参数此外还有 proxy_from_location_var.conf、rewrite_uri_after_var.conf、proxy_pass_lf.conf 等覆盖变量来自 location 捕获组变量出现在 URI 尾部等复杂场景的用例读者可在本地运行测试逐一验证测试入口见 tests/plugins/simply/test_simply.py插件级期望配置见 config.json其中声明了severity: HIGH。如何修复文档给出了三条可操作性很强的修复建议优先使用安全变量。用$request_uri代替$uri就是一个典型做法$request_uri保存的是原始未解码的请求 URI攻击者写入的%0d%0a在其中保持编码状态不会被解码成真实换行符因而天然免疫此类注入。在排他范围中显式禁止换行符号。例如把/some/(?action[^/])改写为/some/(?action[^/\s])。\s会把空白字符包括换行\n、回车\r一并排除在捕获范围之外从源头上掐断 CRLF 流入捕获组变量的路径。这是对排他范围不排除换行这一根因的定点修复。对$uri做显式校验。如果你确实需要在指令中使用$uri只有在你非常清楚自己在做什么的情况下才建议这样做应额外添加校验逻辑确保其值不包含换行符后再进入任何用于构造请求/响应头的指令。用 Gixy 命令行实际检测Gixy 安装后默认分析/etc/nginx/nginx.conf也可显式指定配置文件路径pip install gixy gixy /etc/nginx/nginx.conf对于本文开头的漏洞配置README 中的输出示例展示了http_splitting的完整报告README.mdProblem: [http_splitting] Possible HTTP-Splitting vulnerability. Description: Using variables that can contain \n may lead to http injection. Reason: At least variable $action can contain \n Pseudo config: location ~ /v1/((?action[^.]*)\.json)?$ { add_header X-Action $action; } ... High: 1输出会同时给出问题摘要、描述、触发原因以及定位到具体指令的伪配置片段方便直接对照修复。如果希望临时跳过该插件例如确认其他插件的问题可使用--skips参数相关命令行实现见 gixy/cli/main.pygixy --skips http_splitting /etc/nginx/nginx.conf报告中各问题的严重级别默认按 HIGH 判定见 gixy/plugins/http_splitting.py 中的severity gixy.severity.HIGH也可通过-l/-ll/-lll控制最低报告级别。所有可用参数可通过gixy --help查看。小结HTTP Splitting 是 Nginx 配置静态审计中最值得优先处理的高危问题之一。它的触发链路可以概括为排他范围或解码型变量$uri/$document_uri提供危险字符 → 攻击者用 URL 编码绕过 → Nginx 规范化时解码 → 换行符流入add_header/proxy_pass等指令构造的头字段。Gixy 的http_splitting插件通过指令值变量提取 正则能力分析 依赖链追溯三条机制自动完成这一审计对应的检测代码、测试样例与官方文档均在本仓库内可查。将本文的修复建议落实到配置中即可系统性消除此类注入面。赞分享静态分析应用安全【免费下载链接】gixyNginx configuration static analyzer项目地址https://gitcode.com/gh_mirrors/gi/gixy点击查看免费下载相关推荐10分钟越狱老设备palera1n完整操作指南10分钟越狱老设备palera1n完整操作指南 你的 iPhone 7 停在 iOS 15 再也动不了却还想要 Sileo 和 tweak——palera1CLI固件10分钟跑通大麦抢票脚本从克隆到空跑只需6条命令10分钟跑通大麦抢票脚本从克隆到空跑只需6条命令 开票瞬间已抢完三个字比你的手指先到一步。开源项目 ticket purchase 把选城市、挑场次、选GUI 自动化RPANotesnook 将笔记固定到 Android 通知栏Pin to Notifications完整指南Notesnook 将笔记固定到 Android 通知栏Pin to Notifications完整指南 Notesnook 是一款完全开源、端到端加密的笔前端移动开发桌面应用应用安全上一篇MAS 免费激活从此不用再管到期提醒下一篇响应式数据转换RxKotlin的scan与reduce操作符应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑