### 简要描述:
验证encrypt_key.
这个会上首页吗。。 好紧张。。
### 详细说明:
首先说一下 官方的demo站竟然还没打补丁。
我进去的时候已经看见里面有几个马儿了。。 打下补丁 清下马儿把。
来看看0604出的补丁修改了哪里。
在plugins/phpdisk_client/client_sub.php
```
switch ($action){
case 'upload_file':
//write_file(PHPDISK_ROOT.'system/2.txt',var_export($_POST,true));
//write_file(PHPDISK_ROOT.'system/3.txt',var_export($_FILES,true));
$sign_md5 = md5($uid.$settings[encrypt_key]);
if(!$sign and $sign_md5<>$sign){
echo 'Sign Error!';
exit;
}
```
在这里上传的时候验证了
```
$sign_md5 = md5($uid.$settings[encrypt_key]);
if(!$sign and $sign_md5<>$sign){
echo 'Sign Error!';
exit;
```
如果不相等则退出. $uid倒还容易搞 来看看$settings[encrypt_key]
```
'encrypt_key' => 'Bw5xe2XIlwwj',
```
我擦 这么复杂?
再来看看是如何生成这个的。
```
function make_key(){
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var tmp = "";
var code = "";
for(var i=0;i<12;i++){
code += chars.charAt(Math.ceil(Math.random()*100000000)%chars.length);
}
document.getElementById('encrypt_key').value = code;
}
```
这么多字符中随机取12个。 我擦 放弃逆这个了。
在plugins/phpdisk_client/client_sub.php中
```
$agent = $_SERVER['HTTP_USER_AGENT'];
if($agent!='phpdisk-client'){
exit('<a href="http://faq.phpdisk.com/search?w=p403&err=code" target="_blank">[PHPDisk Access Deny] Invalid Entry!</a>');
}
$u_info = trim(gpc('u_info','P',''));
parse_str(pd_encode(base64_decode($u_info),'DECODE'));
```
parse_str(pd_encode(base64_decode($u_info),'DECODE'));
这里调用了自定义的pd_encode 来解密
如果可以逆到key 就可以自己通过key来生成一个加密的 然后解密之后就可以变量覆盖。
```
function pd_encode($string, $operation = 'ENCODE',$key = ''){
global $settings;
$ckey_length = 4;
$key = md5($key ? $key : ($settings['encrypt_key'] ? $settings['encrypt_key'] : 'PHPDisk=Rc9o'));
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d',0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$arr = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $arr[$i] + $rndkey[$i]) % 256;
$tmp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $arr[$a]) % 256;
$tmp = $arr[$a];
$arr[$a] = $arr[$j];
$arr[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($arr[($arr[$a] + $arr[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
return $keyc.str_replace('=', '', base64_encode($result));
}
}
```
调用了那12位的key。。 对算法不懂 放弃了。。
那就找找有没有哪里调用这函数来进行加密的。
如果要加密的可控的话也行
。
那就来找找在哪里调用了这函数来进行加密了的。
在plugins/phpdisk_client/client_main.php中
```
if($action && $action<>'download'){
$agent = $_SERVER['HTTP_USER_AGENT'];
if($agent!='phpdisk-client'){
exit('<a href="http://faq.phpdisk.com/search?w=p403&err=code" target="_blank">[PHPDisk Access Deny] Invalid Entry!</a>');
}
}
// checked username and pwd...
$username = trim(gpc('username','GP',''));
$password = trim(gpc('password','GP',''));
$username = is_utf8() ? convert_str('gbk','utf-8',$username) : $username;
$password = is_utf8() ? convert_str('gbk','utf-8',$password) : $password;
$rs = $db->fetch_one_array("select * from {$tpf}users where username='$username' and password='$password'");
if(!$rs){
$str = '网盘登录出错:用户名或密码不正确,请重新输入';
if(is_utf8()){
echo convert_str('utf-8','gbk',$str);
}else{
echo $str;
}
exit;
}else{
if($rs[is_locked]){
$str = '网盘登录出错:用户名被锁定';
if(is_utf8()){
echo convert_str('utf-8','gbk',$str);
}else{
echo $str;
}
exit;
```
验证了user agent 可以修改一下就行了
然后去注册一个号就行了。 再往下面看。
```
case 'loadset':
if($settings['open_multi_server']){
$server_host = @$db->result_first("select server_host from {$tpf}servers where server_id>1 order by is_default desc limit 1");
}
$server_host = $server_host ? trim($server_host) : $settings[phpdisk_url];
$sign = md5($uid.$settings[encrypt_key]);
echo 'true'.LF;
echo $server_host.LF;
echo '0'.LF;
echo base64_encode(pd_encode('username='.$username.'&password='.$password.'&sign='.$sign)).LF;
echo $settings[client_api_key];
exit;
break;
```
这里调用了pd_encode 不是DECODE 是ENCODE。 看看里面的。
```
echo base64_encode(pd_encode('username='.$username.'&password='.$password.'&sign='.$sign)).LF;
$sign = md5($uid.$settings[encrypt_key]);
```
。。可以看到 自己把做验证的带入到了pd_encode里面 然后输出了。。
这特么的太爽了。
### 漏洞证明:
首先注册一个号
[<img src="https://images.seebug.org/upload/201406/0811534358218dd43b562b84cc05f71d391c9240.jpg" alt="p5.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201406/0811534358218dd43b562b84cc05f71d391c9240.jpg)
由于密码他这里没有md5。 所以自己把自己的密码进行md5一次后再放进去。
然后得到加密字符串。
MjdjNWpzd0lOYTFtQTd6R1l1alkxRlhlS2ZiYnc4azV1VFIyNHFXLzluZ1p1K2JFOVdqZlRTbVJXMXZLL0FYb21ScGlVMU5wcU1hSjZXOHYzZXk4MnpOWU1pdk1oV2Zzb0RTQk9tNHdCYWpjeHNUWG9sZUtMK0s5VzlrMUJhNzkrOXgrSVV2dTZrVitscURFZk16djJtM0lsWjV6OUZvSE9JU0lUZw==
然后在client_sub.php中
```
$u_info = trim(gpc('u_info','P',''));
parse_str(pd_encode(base64_decode($u_info),'DECODE'));
```
解密后 就注册了$sign变量。
就通过了这个验证 就能继续上传任意文件了。
[<img src="https://images.seebug.org/upload/201406/0811570144aba4016e4e827d0222d18962a3af94.jpg" alt="p10.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201406/0811570144aba4016e4e827d0222d18962a3af94.jpg)
sign错误 把刚才的加密字符串复制进去。
[<img src="https://images.seebug.org/upload/201406/0811575471651db67922f4b44a09e2920a796378.jpg" alt="p11.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201406/0811575471651db67922f4b44a09e2920a796378.jpg)
上传成功。
[<img src="https://images.seebug.org/upload/201406/08115853e731a7516a168990bfa342429c1be3fe.jpg" alt="p12.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201406/08115853e731a7516a168990bfa342429c1be3fe.jpg)
嗯。
_________________________________________________________________________
测试一下demo。
[<img src="https://images.seebug.org/upload/201406/08120008e5ce19cf392b1e3153b9d901b6b438a9.jpg" alt="p13.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201406/08120008e5ce19cf392b1e3153b9d901b6b438a9.jpg)
成功得到加密字符串。
在测试过程中发现不用这加密的也能上传成功。
看看原因。
[<img src="https://images.seebug.org/upload/201406/08120139827943c0ac8276ff161175424b6ebaed.jpg" alt="p14.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201406/08120139827943c0ac8276ff161175424b6ebaed.jpg)
原来官方竟然都忘记给自己的demo站打补丁了。
出于人道我给官方把补丁弄上去把。
```
switch ($action){
case 'upload_file':
//write_file(PHPDISK_ROOT.'system/2.txt',var_export($_POST,true));
//write_file(PHPDISK_ROOT.'system/3.txt',var_export($_FILES,true));
$sign_md5 = md5($uid.$settings[encrypt_key]);
if(!$sign and $sign_md5<>$sign){
echo 'Sign Error!';
exit;
}
```
不过这补丁还得继续修改 因为能像上面那样绕过。
暂无评论