HTTP参数污染
在刷sqli-labs 29时遇到了http参数污染,就想着趁火打劫来学习一下
HTTP Parameter Pollution
,简称HPP,是一种注入型漏洞,如果Web应用中存在这样的漏洞,可以被攻击者利用来进行客户端或者服务器端的攻击,通过 HPP 参数污染可以实现绕过 waf 来进行攻击
漏洞原理
浏览器与服务器进行交互时,浏览器提交 GET/POST 请求参数,这些参数会以 “名称-值对” 的形式出现。通常在一个请求中,同样名称的参数只会出现一次,但是在 HTTP 协议中是允许同样名称的参数出现多次的
但不同服务器处理方式会不一样
如Goole和Bing的例子:
Goole将两次输入的参数值进行拼接(未覆盖)
Bing将第二次输入覆盖第一次输入
覆盖方式
WAF绕过
HPP其实严格意义上讲并不属于一种漏洞,它是利用了不同服务器对于参数获取的结果不同而导致了可以利用某些漏洞。HPP的特性让它在 WAF 绕过、逻辑漏洞挖掘上具有奇效
SQL绕过
如:
1 | ?id=1&id=-1 union select 1,2,database() |
XSS绕过(待)
文件上传(待)
逻辑漏洞
HPP 参数污染在逻辑漏洞挖掘中也是一个大杀器
任意URL跳转
https://www.example.com?u=https://hackun.com
,由于后端做了限制,当我们把u
改成别的不同源的域名(如https://ikunmma.com
)时会报错,但是我们可以利用HPP,将请求地址变成https://www.example.com?u=https://hackun.com&u=https://ikunmma.com
时,由于服务器逻辑错误
使用第一个u
做校验参数,而第二个u
参数做跳转目的地址。于是这样便可成功绕过限制,形成任意 URL 跳转
任意密码重置(短信爆破)
一般重置密码的时候,会发送短信到用户手机
比如GET/POST传递的参数为:phone=13888888888
我们一般会去想,能不能发送验证码到自己的手机,于是可以构造成: phone=13888888888,12345678901
或者 phone=13888888888;12345678901
或者 phone={13888888888,12345678901}
等等一些情况,有时候能通过,但是有些时候会出现 号码不合法 的情况,此时便可以考虑利用 HPP —— phone=13888888888&phone=12345678901
,如果恰好服务器用第一个号码验证是否存在该用户,而使用第二个号码发送短信时,我们便可以接管该用户
防御
- 设备层面,让WAF或其他网关设备(比如IPS)在检查URL时,对同一个参数被多次赋值的情况进行特殊处理。由于HTTP协议允许相同参数在URL中多次出现,因此这种特殊处理需要注意避免误杀的情况;
- 代码层面,编写WEB程序时,要通过合理的
$_GET
方法获取URL中的参数值,而尝试获取 Web服务器返回给程序的其他值时要慎重处理,结合其他漏洞的产生进行组合排查
例题
sqli-labs 29
单引号闭合,http参数污染
这里应该是我的靶场出了点问题,竟然没过滤(都是Protected By The World’s Best Firewall,但是可以正常查询)
去看了题目的源码,发现还有login.php
和hacked.php
代码
只能手动进入login.php
测试了下单引号双引号闭合,都跳转到hacked.php
看了下login.php
:
WAF白名单函数whitelist($input)
1 | //WAF implimentation with a whitelist approach..... only allows input to be Numeric. |
其中:
1 | $match = preg_match("/^\d+$/", $input); |
/^\d+$/
的含义:
^
:字符串开头\d+
:至少一个数字$
:字符串结尾
整个正则要求 输入必须是全数字组成
1 | header('Location: hacked.php') |
重定向到hacked.php
HTTP 参数污染(HPP) 行为模拟 java_implimentation($query_string)
1 | // The function below immitates the behavior of parameters when subject to HPP (HTTP Parameter Pollution). |
该方法将 GET 读入的整行参数使用 explode()
方法对 “&
” 进行分割,返回一个分割后的数组。接着方法通过 substr(
) 方法提取对 “&
” 分割后的第一个元素的前 2 个字符,若这 2 个字符是 “id
”,则再次使用 substr()
方法提取等号后面的值返回。注意该方法提取的是 2 个同名变量中的第一个,因此它无法对第二个同名变量进行操作
搭建在apache服务器上的php服务对于传入多个相同名字的参数,服务器只解析最后一个,由于注入 2 个同名参数时,java_implimentation()
方法返回的参数是第一个 id 参数,此时这个过滤就被我们绕过了,所以$_GET['id']
变量实际上是最后一个id参数
总结:
1.全数字输入才能绕过WAF
2.我们可以通过注入两个同名的参数 id,第一个参数用于绕过 WAF,第二个参数用于注入
payload:
1 | ?id=1&id=-1'union select 1,2,3--+ |
参考: