Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/dbms/sybase/enumeration.py
2992 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import re
9
10
from lib.core.common import filterPairValues
11
from lib.core.common import isListLike
12
from lib.core.common import isTechniqueAvailable
13
from lib.core.common import readInput
14
from lib.core.common import safeSQLIdentificatorNaming
15
from lib.core.common import unArrayizeValue
16
from lib.core.common import unsafeSQLIdentificatorNaming
17
from lib.core.data import conf
18
from lib.core.data import kb
19
from lib.core.data import logger
20
from lib.core.data import paths
21
from lib.core.data import queries
22
from lib.core.dicts import SYBASE_TYPES
23
from lib.core.enums import DBMS
24
from lib.core.enums import PAYLOAD
25
from lib.core.exception import SqlmapMissingMandatoryOptionException
26
from lib.core.exception import SqlmapNoneDataException
27
from lib.core.exception import SqlmapUserQuitException
28
from lib.core.settings import CURRENT_DB
29
from lib.utils.brute import columnExists
30
from lib.utils.pivotdumptable import pivotDumpTable
31
from plugins.generic.enumeration import Enumeration as GenericEnumeration
32
from thirdparty import six
33
from thirdparty.six.moves import zip as _zip
34
35
class Enumeration(GenericEnumeration):
36
def getUsers(self):
37
infoMsg = "fetching database users"
38
logger.info(infoMsg)
39
40
rootQuery = queries[DBMS.SYBASE].users
41
42
query = rootQuery.inband.query
43
44
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
45
blinds = (False, True)
46
else:
47
blinds = (True,)
48
49
for blind in blinds:
50
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName)
51
52
if retVal:
53
kb.data.cachedUsers = list(retVal[0].values())[0]
54
break
55
56
return kb.data.cachedUsers
57
58
def getPrivileges(self, *args, **kwargs):
59
warnMsg = "on Sybase it is not possible to fetch "
60
warnMsg += "database users privileges, sqlmap will check whether "
61
warnMsg += "or not the database users are database administrators"
62
logger.warning(warnMsg)
63
64
users = []
65
areAdmins = set()
66
67
if conf.user:
68
users = [conf.user]
69
elif not len(kb.data.cachedUsers):
70
users = self.getUsers()
71
else:
72
users = kb.data.cachedUsers
73
74
for user in users:
75
user = unArrayizeValue(user)
76
77
if user is None:
78
continue
79
80
isDba = self.isDba(user)
81
82
if isDba is True:
83
areAdmins.add(user)
84
85
kb.data.cachedUsersPrivileges[user] = None
86
87
return (kb.data.cachedUsersPrivileges, areAdmins)
88
89
def getDbs(self):
90
if len(kb.data.cachedDbs) > 0:
91
return kb.data.cachedDbs
92
93
infoMsg = "fetching database names"
94
logger.info(infoMsg)
95
96
rootQuery = queries[DBMS.SYBASE].dbs
97
query = rootQuery.inband.query
98
99
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
100
blinds = [False, True]
101
else:
102
blinds = [True]
103
104
for blind in blinds:
105
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName)
106
107
if retVal:
108
kb.data.cachedDbs = next(six.itervalues(retVal[0]))
109
break
110
111
if kb.data.cachedDbs:
112
kb.data.cachedDbs.sort()
113
114
return kb.data.cachedDbs
115
116
def getTables(self, bruteForce=None):
117
if len(kb.data.cachedTables) > 0:
118
return kb.data.cachedTables
119
120
self.forceDbmsEnum()
121
122
if conf.db == CURRENT_DB:
123
conf.db = self.getCurrentDb()
124
125
if conf.db:
126
dbs = conf.db.split(',')
127
else:
128
dbs = self.getDbs()
129
130
for db in dbs:
131
dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db)
132
133
dbs = [_ for _ in dbs if _]
134
135
infoMsg = "fetching tables for database"
136
infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db if isinstance(db, six.string_types) else db[0] for db in sorted(dbs)))
137
logger.info(infoMsg)
138
139
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
140
blinds = [False, True]
141
else:
142
blinds = [True]
143
144
rootQuery = queries[DBMS.SYBASE].tables
145
146
for db in dbs:
147
for blind in blinds:
148
query = rootQuery.inband.query % db
149
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName)
150
151
if retVal:
152
for table in next(six.itervalues(retVal[0])):
153
if db not in kb.data.cachedTables:
154
kb.data.cachedTables[db] = [table]
155
else:
156
kb.data.cachedTables[db].append(table)
157
break
158
159
for db, tables in kb.data.cachedTables.items():
160
kb.data.cachedTables[db] = sorted(tables) if tables else tables
161
162
return kb.data.cachedTables
163
164
def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False):
165
self.forceDbmsEnum()
166
167
if conf.db is None or conf.db == CURRENT_DB:
168
if conf.db is None:
169
warnMsg = "missing database parameter. sqlmap is going "
170
warnMsg += "to use the current database to enumerate "
171
warnMsg += "table(s) columns"
172
logger.warning(warnMsg)
173
174
conf.db = self.getCurrentDb()
175
176
elif conf.db is not None:
177
if ',' in conf.db:
178
errMsg = "only one database name is allowed when enumerating "
179
errMsg += "the tables' columns"
180
raise SqlmapMissingMandatoryOptionException(errMsg)
181
182
conf.db = safeSQLIdentificatorNaming(conf.db)
183
184
if conf.col:
185
colList = conf.col.split(',')
186
else:
187
colList = []
188
189
if conf.exclude:
190
colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None]
191
192
for col in colList:
193
colList[colList.index(col)] = safeSQLIdentificatorNaming(col)
194
195
if conf.tbl:
196
tblList = conf.tbl.split(',')
197
else:
198
self.getTables()
199
200
if len(kb.data.cachedTables) > 0:
201
tblList = list(six.itervalues(kb.data.cachedTables))
202
203
if tblList and isListLike(tblList[0]):
204
tblList = tblList[0]
205
else:
206
errMsg = "unable to retrieve the tables "
207
errMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
208
raise SqlmapNoneDataException(errMsg)
209
210
for tbl in tblList:
211
tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True)
212
213
if bruteForce:
214
resumeAvailable = False
215
216
for tbl in tblList:
217
for db, table, colName, colType in kb.brute.columns:
218
if db == conf.db and table == tbl:
219
resumeAvailable = True
220
break
221
222
if resumeAvailable and not conf.freshQueries or colList:
223
columns = {}
224
225
for column in colList:
226
columns[column] = None
227
228
for tbl in tblList:
229
for db, table, colName, colType in kb.brute.columns:
230
if db == conf.db and table == tbl:
231
columns[colName] = colType
232
233
if conf.db in kb.data.cachedColumns:
234
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns
235
else:
236
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns}
237
238
return kb.data.cachedColumns
239
240
message = "do you want to use common column existence check? [y/N/q] "
241
choice = readInput(message, default='Y' if 'Y' in message else 'N').upper()
242
243
if choice == 'N':
244
return
245
elif choice == 'Q':
246
raise SqlmapUserQuitException
247
else:
248
return columnExists(paths.COMMON_COLUMNS)
249
250
rootQuery = queries[DBMS.SYBASE].columns
251
252
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
253
blinds = [False, True]
254
else:
255
blinds = [True]
256
257
for tbl in tblList:
258
if conf.db is not None and len(kb.data.cachedColumns) > 0 \
259
and conf.db in kb.data.cachedColumns and tbl in \
260
kb.data.cachedColumns[conf.db]:
261
infoMsg = "fetched tables' columns on "
262
infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
263
logger.info(infoMsg)
264
265
return {conf.db: kb.data.cachedColumns[conf.db]}
266
267
if dumpMode and colList:
268
table = {}
269
table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)
270
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
271
continue
272
273
infoMsg = "fetching columns "
274
infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)
275
infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)
276
logger.info(infoMsg)
277
278
for blind in blinds:
279
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
280
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.usertype' % kb.aliasName], blind=blind, alias=kb.aliasName)
281
282
if retVal:
283
table = {}
284
columns = {}
285
286
for name, type_ in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.usertype" % kb.aliasName])):
287
columns[name] = SYBASE_TYPES.get(int(type_) if hasattr(type_, "isdigit") and type_.isdigit() else type_, type_)
288
289
table[safeSQLIdentificatorNaming(tbl, True)] = columns
290
kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table
291
292
break
293
294
return kb.data.cachedColumns
295
296
def searchDb(self):
297
warnMsg = "on Sybase searching of databases is not implemented"
298
logger.warning(warnMsg)
299
300
return []
301
302
def searchTable(self):
303
warnMsg = "on Sybase searching of tables is not implemented"
304
logger.warning(warnMsg)
305
306
return []
307
308
def searchColumn(self):
309
warnMsg = "on Sybase searching of columns is not implemented"
310
logger.warning(warnMsg)
311
312
return []
313
314
def search(self):
315
warnMsg = "on Sybase search option is not available"
316
logger.warning(warnMsg)
317
318
def getHostname(self):
319
warnMsg = "on Sybase it is not possible to enumerate the hostname"
320
logger.warning(warnMsg)
321
322
def getStatements(self):
323
warnMsg = "on Sybase it is not possible to enumerate the SQL statements"
324
logger.warning(warnMsg)
325
326
return []
327
328