PHP拒绝服务***


所有主流语言中都存在的重大的复杂***漏洞。PHP在处理表单时有漏洞,但现在每个Web程序都在使用JSON API,仍然很容易受到复杂的***。


它是怎么起作用的


在通常的情况下,哈希表被优化的速度非常快。但如果有人将互相冲突的键值插入,性能就会突然变得很糟糕。


640?&tp=webp&wxfrom=5&wx_lazy=1


如果哈希表使用开放的地址来实现,一个冲突的键值会针对链接列表中的所有元素做出检查。如果你插入了n个元素,为了公平性你就得检查 1+2+3+..+(n-1) 个元素(复杂度为O(n2))。


0?&tp=webp&wxfrom=5&wx_lazy=1


如果你想早知道更多关于这个在PHP里是怎么起作用的,你还可以读读这篇信息量比较丰富的文章。


使用POST数据作为***


为了方便访问,PHP把所有的POST字段都存放在$POST图里。

<!--?php echo $_POST ["param"]; ?-->

下面的POST请求是针对上卖弄的PHP页面的,会导致5个键值冲。如果你发送了2^16个键值,这时的计算量就相当于要让i7处理器忙上30秒钟。

curl--data"4vq=key1&4wP2=key2&5Uq=key3&5VP=key4&64q=key5"http://localhost:8080/index.php

尽管在一些语言(比如Python)里哈希函数已经为了防止此类的***而做出了相应的修改,PHP通过在php.ini配置文件里简单地引入了一个max_input_vars指令解决了这个漏洞问题。


默认情况下,该指令被设置为1000,这意味着你在一个请求中不能发送超过1000个表单字段。1000个冲突不是真正的问题,因为它与正常情况下请求相比速度只慢了1/3.


使用JSON API作为***


由于Web已经进化到一个到处都是API的大网,我们可能已经忘记,在用户使用输入和数组的地方PHP仍然存在着哈希冲入漏洞***。


Web API通常支持JSON,因此使用标准PHP库的json_decode方法。这将默认解析所有在JSON文件里的键值到PHP图中,引起许多冲突。


下面是一个很简单的返回发送者姓名和邮件地址的API:

<!--?php
header('Content-Type: application/json');
$body = file_get_contents('php://input');
$params = json_decode($body);
$response = array('name' =--> $params->{'name'}, 'email' => $params->{'email'});
echo json_encode($response);
?>

如果我们把一个修改后的JSON请求发送给这个API,结果和POST参数会有一样的影响。

curl -v -X POST \
-H "Accept: application/json" \
-H "Content-type: application/json" \
-d '{"4vq":"key1", "4wP2":"key2", "5Uq":"key3", "5VP":"key4", "64q":"key5" }' \
http://example.com/api.php

测试


我将json_decode和导致一个可怕的二次函数的时间画了出来。在 2^16个键之后异常值出现了,原因是一个不同的哈希掩码,在当前阵列在数组增长超过 2^16个元素时,我们的冲突预计会引起16位哈希掩码的冲突。


640?&tp=webp&wxfrom=5&wx_lazy=1


如果把上面的JSON API样例托管在一个实际的服务器上,并且做出一些***,我们也会得到同样的结果。函数会达到平衡,因为Apache服务器处理每条请求的时间被限制在30秒以内。


640?&tp=webp&wxfrom=5&wx_lazy=1


我在AWS上跑了一个测试,其中有一个***者(蓝色)和一个受害者(×××),并且为CPU占用率截了图。你能很容易就看明白,尽管***者除了发送POST请求外其他几乎什么事情都没有做,受害者为网页页面提供提供服务的性能还是会受到影响。


640?&tp=webp&wxfrom=5&wx_lazy=1


其他潜在的***载体


有趣的是,解析XML并没有使用内部的哈希图。


640?&tp=webp&wxfrom=5&wx_lazy=1


我确定还有很多用户数据和哈希表一起被调用的其他种情况