0x01前言
回顾了下以前的代码审计
三个白帽,很经典
现在估计都没有了吧。
0x02 分析
<?php
include 'db.inc.php';
foreach(array('_GET','_POST','_COOKIE') as $key){
foreach($$key as $k => $v){
if(is_array($v)){
errorBox("hello,sangebaimao!");
}else{
$k[0] !='_'?$$k = addslashes($v):$$k = "";
}
}
}
function filter($str){
$rstr = "";
for($i=0;$i<strlen($str);$i++){
if(ord($str[$i])>31 && ord($str[$i])<127){
$rstr = $rstr.$str[$i];
}
}
$rstr = str_replace('\'','',$rstr);
return $rstr;
}
if(!empty($message)){
if(preg_match("/\b(select|insert|update|delete)\b/i",$message)){
die("hello,sangebaimao!");
}
if(filter($message) !== $message){
die("hello,sangebaimao!");
}
$sql="insert guestbook(`message`) value('$message');";
mysql_query($sql);
$sql = "select * from guestbook order by id limit 0,5;";
$result = mysql_query($sql);
if($result){
while($row = mysql_fetch_array($result)){
$id = $row['id'];
$message = $row['message'];
echo "|$id|=>|$message|<br/>";
}
}
$message = stripcslashes($message);
$sql = "delete from guestbook where id=$id or message ='$message';";
if(!mysql_query($sql)){
print(mysql_error());
$sql = "delete from guestbook where id=$id";
mysql_query($sql);
};
}
?>
源码如题, 在我本地间的构造了一个数据库,然后就运行了。
-
不难看出,有两个过滤的地方,一个是filter函数,另外一个是正则绕过。这是对输入的绕过。 -
代码的逻辑也很简单,插入,显示,取出,删除。 -
我们插入的数据,进入第二次的查询,这就存在二次注入了。二次注入的逻辑也很简单,只要插入的数据经过过滤之后可以正常查询就好了。 -
然后就是回显的问题了,有一个print(mysql_error()); 那么就可以直接使用报错注入了
以上是对程序的简单分析。
0x03 绕过
-
关于单引号的绕过,这个地方比较特别,程序中有一个
m
e
s
s
a
g
e
=
s
t
r
i
p
c
s
l
a
s
h
e
s
(
message = stripcslashes(
message=stripcslashes(message);关于这个函数的作用可以简要要说明一下: 反引用一个使用 [addcslashes()](https://www.php.net/manual/zh/function.addcslashes.php) 转义的字符串
返回反转义后的字符串。可识别类似 C 语言的 *\n*,*\r*,... 八进制以及十六进制的描述。
stripcslashes('H\xaello') == 'H'.chr(0xAE).'llo'
既然可以转义,直接让他来转义\x27 就可以使用单引号了。 -
关于正则的绕过 可以看出正则表达式中有\b 先来看看\b的作用,\b的作用是匹配单词的边界。所谓的单词的边界就是特殊符号的边界。 绕过的思路就来了,假设我们想使用select 在select前后加点单词就可以了。 这里提一个mysql的tips /*!*/ 只在mysql中有用,在别的数据库中这只是注释,但是在mysql,/*!select 1*/可以成功执行,在语句前可以加上5位数字,代表版本号,表示只有在大于该版本的mysql中不作为注释.
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.9-log |
+-----------+
1 row in set (0.00 sec)
mysql> select /*!50709version()*/;
+-----------+
| version() |
+-----------+
| 5.7.9-log |
+-----------+
1 row in set (0.00 sec)
-
关于报错注入
UpdateXML(xml_target, xpath_expr, new_xml)
updatexml函数有三个参数,作用是xml替换,把xml_target中被xpath_expr匹配到的部分使用new_xml替换
这个报错注入的原理是利用updatexml的参数错误,首先不能有语法错误,要不然注入的语句根本无法执行,语法正确后,先去执行concat(0x27,(/*!00000select version()*/)),得到'5.5.42-log,作为第二个参数传入updatexml函数中,而updatexml第二个参数为xml的匹配表达式,单引号为非法字符,因此报错,输出错误内容'5.5.42-log, 因此得到了你想要得到的数据
payload
?message=aaa\x27 and updatexml(0,concat(0x27,()),0)%23
|