[翻译] The Bug challenge2018 warm-up wp

原文

前言

有幸参加西电的校内赛,从web第一题就不会,Google了一下题目源码,发现此文,看了一遍,还挺好的,故此翻译,与大家分享。

原文前言

Securify会不时发布Spot The Bug challenge,以帮助人们提高漏洞挖掘技巧。 当然,这很有趣。 在这篇博文中,你可以找到为即将到来的挑战赛的热身题的writeup! 该代码源于野外遇到的一个漏洞。(The code stems from a vulnerability that was encountered in the wild. 不太会翻orz)

该代码包含绕过HMAC检查的漏洞。请注意,这是一个热身挑战,不会给解决者提供奖金(之后的题目都会给予奖金)。

代码

此脚本为用户提供的主机执行DNS查找。它使用HMAC来确保从可信来源请求它。很好的实现,真的吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
highlight_file(__FILE__);
if(empty($_POST['hmac']) || empty($_POST['host'])){
header('HTTP/1.0 400 Bad Request');
exit;
}
$secret = getenv("SECRET");
if(isset($_POST['nonce']))
$secret = hash_hmac('sha256',$_POST['nonce'],$secret);
$hmac = hash_hmac('sha256',$_POST['host'],$secret);
if($hmac !== $_POST['hmac']){
header('HTTP/1.0 403 Forbidden');
exit;
}
echo exec("host ".$_POST['host']);
?>

漏洞细节

让我们来看看代码。

  • 第三到第六行,要求用户提交一个HMAC和主机名host
  • 一个密钥从环境变量中取得。
  • 如果用户设置了noce,密钥被更新为secret = HMAC(SHA256, nonce, secret)
  • HMAC = HMAC(SHA256, hostname, secret)生成一个HMAC。
  • 生成的HMAC与提供的HMAC比较。

让我们花点时间记住来自加密世界的两句名言:“复杂性是安全性的最大敌人”和“永远不要推出自己的密码”。有了这个,我们可以很快看到在这个设置中出了什么问题。

如果程序员跳过步骤三,仅仅使用提供的主机名和密钥生成一个HMAC,这不会有问题。在密码学中,一个nonce通常被用于避免消息重复或生成唯一密钥。然而,我们看这个自定义实现,密钥用nonce的HMAC更新了。理论上这不会被直接攻击利用。但在复杂的PHP世界中,这导致了一个严重的安全漏洞。

为了正确认识漏洞,我们可以看一下,当传入一个数组作为message被提供时,hash_hmac函数的的行为。

1
2
$hmac = hash_hmac('sha256', Array(), "SecretKey");
echo $hmac == false;

output:

1
2
3
$ php foo.php
Warning: hash_hmac() expects parameter 2 to be string, array given in /Users/stb/stb-test.php on line 3
1

我们可以看到,hash_hmac仅仅触发了一个警告并返回false。这可以通过提供一个数组作为主机名在原始代码中触发。但是,这不会绕过HMAC检查,因为使用了强比较(!==)。

1
if ($hmac !== $_POST['hmac']) {

因为强比较会比较数据类型,布尔值false不能和字符串"false"相等(但在弱比较中两者会被判定为相等)。并且,由于$_POST['hmac']不能为布尔值false,所以这条路行不通。

(好在,)我们的程序员决定增加额外的复杂性,无论出于何种原因,他在代码中添加了一个nonce

1
2
if (isset($_POST['nonce']))
$secret = hash_hmac('sha256', $_POST['nonce'], $secret);

当我们为nonce传入一个数组时会发生什么?对的,hash_hmac会返回一个布尔值false。然后,新的HMAC就会以HMAC = hash_hmac(SHA256, $_POST['host'], false)的形式生成!攻击者可以为任何信息生成一个合法的HMAC。例如:

1
hash_hmac('sha256', "securify.nl", false) = c8ef9458af67da9c9086078ad3acc8ae71713af4e27d35fd8d02d0078f7ca3f5

这个漏洞的exp url看起来类似:

1
?nonce[]=&hostname=securify.nl&hmac=c8ef9458af67da9c9086078ad3acc8ae71713af4e27d35fd8d02d0078f7ca3f5

当然,主机名参数可以执行代码,所以从这里开始游戏就结束了。

Spot The Bug 2018

我们预计今年第二季度开始时会发布Spot the Bug挑战。如果你喜欢这个挑战,你可以通过发送邮件到stb@securify.nl来订阅,我们会让你保持最新状态。

窝很可爱,请给窝钱