雷池-宝塔sql-post构造差异化注入

📅 2026/8/18 19:36:23
雷池-宝塔sql-post构造差异化注入
免责声明本文全部实验操作均在本人完全可控的自建本地靶场环境完成文章仅用于网络安全原理学习与技术研究。根据《中华人民共和国网络安全法》未经授权对任何第三方系统进行探测、命令执行、文件写入等操作属于违法行为。严禁复制、使用本文中的 Payload、代码应用到未获得授权的设备上。若读者将文中内容用于非法用途一切法律责任由行为人本人承担与本文作者无关。个人水平有限如有不足欢迎指正。————————————————环境准备在宝塔面板创建 PHP 站点部署 Web 靶场源码配置网站运行环境。雷池 WAF 新增防护应用配置反向代理指向靶站修改本机 hosts 文件将测试域名解析至雷池服务实现流量经过 WAF 再访问靶场。www.leichi1.com部署在9.2.7版本的雷池中www.leichi.com部署在9.3.11版本的雷池中1.用户访问 www.leichi.com域名解析指向雷池 IP2.HTTP 请求抵达雷池 80 端口3.雷池校验流量合法请求反向代理转发4.请求发送至宝塔 192.168.143.160:805.宝塔 Nginx 站点 listen 80 承接请求运行网站程序6.生成页面响应沿着原链路依次返回给访问用户请求参数中检测到 union select 这类 SQL 注入敏感特征词在请求传递至后端程序前直接阻断请求不将数据包交给数据库执行请求直接被拦截。在阅读本篇文章前建议先理解Part Header 和 Part BodyPart Header 和 Part Body 的分界标记Part Header 和 Part Body 的分界标记\r\n\r\n例如--a\r\n ← 开启一段参数块 Content-Disposition: ...\r\n ← Part Header分段头部 \r\n ← 和上一行组合 → \r\n\r\n【分界符】 Content-Disposition: ...\r\n ← Part Body参数内容 \r\n union select 1,2#\r\n ← Part Body --a--\r\n ← 请求结束边界遇到 --boundary--a新建一个参数区块持续读取行直到碰到第一次出现的 \r\n\r\n。在它之前Part Header头部域在它之后Part Body参数真正的值一旦跨过 \r\n\r\n分界永久生效后面无论再出现多少个 \r\n、\r\n\r\n全都属于内容本身不会再次充当分界。1.普通POST传参form actionpost.php methodpost 用户名:input nameuname 密码:input namepass input typesubmit /formContent-Type: application/x-www-form-urlencoded正文编码类型告诉服务器请求体是 URL 编码表单参数普通表单 POST 标识区别于文件上传 multipart/form-data2.文件上传form actionupload.php methodpost enctypemultipart/form-data input typefile nameupfile / button typesubmit上传文件/button /formContent-Type: multipart/form-data;报文类型文件上传格式content内容boundary----geckoformboundary5eb5728e8924ed80e39382da15daa242boundary 分隔符用来切分请求体内多个字段前后必须完全一致。3.multipart/form-data传递POST参数?php echo file_get_contents(php://input); var_dump($_POST); var_dump($_FILES); ?未提供 filename 参数时该 multipart 字段会被 PHP 当作普通表单字段解析并存入 $_POST。filename 参数不完整或格式未被 PHP 正确识别时该字段仍会按照普通表单字段处理因此数据进入 $_POST。filename 参数被 PHP 正确识别后该字段会被当作文件上传字段处理相关信息及文件内容会进入 $_FILES。总结multipart/form-data 本身并不意味着数据一定进入 $_FILES。PHP 会根据 Content-Disposition 中是否存在并正确识别 filename 来判断该字段是普通 POST 参数还是文件上传参数。什么是构造差异化构造差异化 解析差异WAF雷池和后端 Web 服务宝塔 PHP对同一条 HTTP 请求、同一串载荷解析规则不一样 攻击者利用两边理解不一致构造特殊请求WAF 认为是正常请求直接放行后端服务器识别出恶意代码并执行。WAF 绕过思路利用 POST 请求解析差异使 WAF 与后端 PHP 对同一个请求产生不同的解析结果。构造 multipart/form-data 请求时通过调整字段格式、filename 等信息使 WAF 解析出的参数与 PHP 最终解析出的 $_POST 或 $_FILES 数据不一致。如果 WAF 检查的是一种解析结果而后端实际使用的是另一种解析结果就可能形成 WAF 检测与后端处理之间的差异从而达到绕过检测的目的。一些 WAF 为了降低误报率通常不会深入检测文件上传字段中的具体内容而是重点检测普通 POST 参数。因此如果 WAF 无法准确判断 multipart/form-data 中的字段最终是进入 $_POST 还是 $_FILES就可能产生 WAF 与 PHP 之间的解析差异。利用这种差异可以构造一个请求使 WAF 认为相关数据属于文件上传内容从而不对其中的攻击内容进行检测而 PHP 在解析请求时却将这部分数据识别为普通 POST 参数并存入 $_POST。之后后端程序按照普通参数对其进行处理就可能导致原本被 WAF 拦截的攻击数据得到执行。1.00截断filename数据包中在分号后插入十六进制00空字节\0破坏了filename2.txt字段结构。PHP 解析头部时遇到空字节发生截断无法识别 filename 参数不再判定该区块为文件上传数据最终将内容当做普通表单参数存入$_POST$_FILES为空。这是测试的界面早年简单 WAF 不会处理 \0完整读取整行看见 filename现在大多数 WAF 在解析 HTTP 头部时同样会把 \0 当作字符串截断符。WAF 解析后只得到 nameuname;看不见 filename不会切换到上传数据包检测模式照常严格检测 Body里的 union select直接命中 SQL 规则拦截。而这种由于 WAF 没有检测出差异化所以并没有拦截识别形式是文件上传的形式检测策略发生切换不再深度扫描 Part Body 里的文本载荷。未设置 WAF 的能成功filename 被 00 截断、解析失效PHP 不再认为这是文件直接把这段内容当做普通 POST 参数存入 $_POST。2.双写上传描述行未设置waf时确实能实现PHP 在解析 multipart/form-data 的每个区块时遍历区块内头部行只采用第一条合法的 Content-Disposition区块内后续出现的其他 Content-Disposition 头部直接忽略、丢弃大量 WAF 为了性能、降低误报有一条策略文件上传块只检测文件名扩展名、文件头部特征不深度扫描文件正文内容。本例中文件名是 2.txt扩展名安全WAF 直接放行正文不会对正文执行 SQL 注入特征匹配。注意这里的\r\n是第7行整行没有额外换行waf检测到第8行且文件后缀名不危险于是被当作文件上传不检测文件内容php取第7行于是被绕过多加空行也会被拦截在 multipart 单个 Part 中一旦解析器读到 \r\n\r\n代表Part Header 区域 彻底结束后面全部是 Part Body正文。WAF同样遵循 multipart 标准状态机解析读取第一条 Content-Disposition: nameuname碰到空行 \r\n\r\n头部结束WAF 不再继续读取后续内容作为本 Part 头部后续 Content-Disposition...filename1.txt 被识别成普通正文数据WAF 识别当前 Part 只是普通表单参数无 filename会对正文完整执行 SQL 注入检测 union select 1,2# 命中 SQL 特征 → 直接拦截加上--a绕过php把后面的--a都当作post提交 闭合单引号而没有找到数据于是回显union select。但是waf并没有waf可能第一次也是认识是post提交但是在检测内容时又发现截断字符串于是认为又是一个新的part检测为文件上传于是形成差异化。构造假的part注意变成php则不能绕过WAF识别到filename2.php触发文件上传相关高危后缀规则直接拦截整条请求不再继续判断是否绕过 SQL 注入检测。3.双写整个part开头WAF解析逻辑报文中第二段参数携带filename字段WAF 会将该分段识别为文件上传区块仅检测文件相关内容忽略此分段内的参数载荷不检测 SQL 注入特征第一段uname内容无攻击特征流量直接放行。PHP解析逻辑PHP 没有将携带filename的分段视作文件而是读取该分段内的文本内容赋值给$_POST[uname]后端代码直接取用该变量拼接 SQL 语句注入语句成功传入数据库执行。成功构造差异化。可能waf取了第910行的开头检测为文件上传于是没检测内容。形成差异化。如果多了一个空行php解析时从第9行全部当作body而waf不认为继续匹配匹配到第10行判断为文件上传于是不验证文件内容实现绕过。构造假的part部分WAF识别到filename2.php触发文件上传相关高危后缀规则直接拦截整条请求不再继续判断是否绕过 SQL 注入检测。4.构造假的part部分WAF 处理逻辑WAF识别第二个Part带有filename判定为文件区块跳过该 Part 内 SQL 注入特征检测第一个 Part 无攻击载荷流量放行。无害后缀不会触发文件上传拦截规则。PHP 解析逻辑PHP解析 multipart 表单时从第9行开始由于存在两个\r\n全部当作body部分将第二个 Part 的注入载荷赋值给$_POST[uname]后端代码直接拼接 SQL 语句注入成功执行。更换后缀后缀名违规4.15.两个boundary边界字符串PHP后端解析 multipart 时读取第一个 boundarya用--a切分报文。Part2--a分割出的 unameDumb最终 $_POST[uname]Dumb。无waf有waf该载荷依靠重复 boundaryboundarya;boundaryb制造解析分歧PHP取第一个 boundary a解析--a分段读取恶意注入语句理想绕过场景WAF 取最后一个 boundary b只读取--b分段内无害admin看不到注入语句。拦截根本原因当前这套 WAF 防护策略升级不再只依靠 boundary 切割报文后局部检测WAF 会全文检索整个请求包体不区分分段直接匹配到特征 union select或者 WAF 可以同时识别两组 boundary完整解析出两个 Part成功捕获第二段注入载荷。经过测试不论ab这两part中的哪一个filename写错都会被拦截改后缀名也是两个multipart也不行6.两个content-Type无waf7.空的boundary未设置waf能成功老旧 WAF 对空 boundary 处理逻辑混乱部分 WAF 拿到boundary空值无法正常分割报文部分 WAF 正则错误抓取--当作分隔符 WAF 仅解析到第一段无害内容Dumb看不到下方注入语句形成解析差异 HPP。被拦截8.空格boundary无waf9.逗号绕过很多老旧 WAF 解析Content-Type头存在缺陷遇到 boundarya,a 里的逗号 错误把逗号当成参数分隔符只截取前面的 a。于是 WAF 认为边界是 a分隔符--a、结束符 --a--WAF视角读到 --a 就判定分段结束只检测第一段无害内容 Dumb--a-- 被 WAF 当成整个数据包结尾不会读取后面注入语句。10.\t截断绕过在第7行完整的文件上传的开头加上\t。因为开头带有制表符PHP 判定这一行不是合法头部字段直接当成普通正文内容丢弃尝试在适当的地方加上制表符绕过在filename前加上制表符绕过成功老旧 WAF 采用宽松正则匹配依旧识别出 filename将当前分段判定为文件上传段触发文件内容免检测策略不对流量中的 SQL 语句进行检测。PHP严格解析 HTTP 头部参数名称参数名不能包含空白字符无法识别filename\t为合法 filename 参数不认为这是文件分段。PHP 继续向下解析第二条合法Content-Disposition头部成功读取携带注入语句的 uname 参数。由于 WAF 和 PHP 对同一个数据包解析结果不一致产生 解析差异实现 WAF 绕过。制表符放在 filename开头\t filename允许参数名前存在空白自动忽略前缀空白正常识别参数 filenamePHP 认为这是标准文件分段正文会被当成文件内容无法读取注入参数注入直接失败。所以不能放在开头。制表符放在 filename单词中间file\tname单词直接被拆成两段字符串不再包含连续 filenameWAF 正则匹配不到连续 filename 字符串不会判定为文件分段。WAF 不会触发 “文件内容免检测”直接扫描正文 SQL 语句流量被拦截。绕过条件不成立。1.参数名中加入00\t高级同一个字段重复定义WAF会认为这是在尝试绕过检测或协议违规拦截原因文件上传第二条分段头部增加了 完整filename1.txt使得第二个name分段同样具备filename字段被 WAF 识别为文件上传分段。WAF 不再提前终止解析完整扫描所有分段WAF 识别到第二段分段内存在 SQL 注入语句 union select直接触发拦截规则。对比能够成功的数据包第二条分段不能携带 filename。变量名前加00绕过waf少了filename没绕过waf认为第二个为post严格检测内容发现sql注入加入\t绕过分段2没有filenameWAF认为这是普通字段可能不触发文件内容扫描SQL注入未被发现 成功绕过当两个分段都带有 filename 时WAF将两个分段都识别为文件上传触发高强度的内容检测从而发现并拦截了分段2中的SQL注入载荷。bounary进阶boundary 的名称是可以前后加入任意内容的无waf时识别到a部分有waf时也识别到了a部分]括号无waf时有waf时检测第二端发现有差异化为psot于是检测内容于是被拦截加固建议总结与防御建议本文介绍的多种 WAF 绕过思路核心都指向同一个本质WAF 与后端 PHP 对同一条 multipart/form-data 请求的解析结果不一致。攻击者通过构造特殊字段格式让 WAF 误判为“文件上传”而豁免内容检测同时让 PHP 将载荷解析为普通 POST 参数并执行从而形成解析差异差异化。下面按绕过方式总结核心原理并给出对应的防御与检测建议。