Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2ac8deb

Browse files
committed
Major code refactoring - moved to one location only (getIdentifiedDBMS() in common.py) the retrieval of identified/fingerprinted DBMS.
Minor bug fixes thanks to previous refactoring too.
1 parent a1d1f69 commit 2ac8deb

37 files changed

Lines changed: 342 additions & 314 deletions

lib/controller/checks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import time
1313

1414
from lib.core.agent import agent
15+
from lib.core.common import aliasToDbmsEnum
1516
from lib.core.common import beep
1617
from lib.core.common import extractRegexResult
1718
from lib.core.common import findDynamicContent
@@ -430,7 +431,7 @@ def checkSqlInjection(place, parameter, value):
430431
for detailKey, detailValue in test.details.items():
431432
if detailKey == "dbms" and injection.dbms is None:
432433
injection.dbms = detailValue
433-
kb.dbms = detailValue
434+
kb.dbms = aliasToDbmsEnum(detailValue)
434435
elif detailKey == "dbms_version" and injection.dbms_version is None:
435436
injection.dbms_version = detailValue
436437
kb.dbmsVersion = [ detailValue ]

lib/controller/handler.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
See the file 'doc/COPYING' for copying permission
88
"""
99

10-
from lib.core.common import getErrorParsedDBMSes
10+
from lib.core.common import getIdentifiedDBMS
1111
from lib.core.common import popValue
1212
from lib.core.common import pushValue
1313
from lib.core.data import conf
@@ -63,18 +63,11 @@ def setHandler():
6363
( SYBASE_ALIASES, SybaseMap, SybaseConn ),
6464
]
6565

66-
inferencedDbms = (getErrorParsedDBMSes()[0] if getErrorParsedDBMSes() else '') or kb.dbms
67-
68-
for injection in kb.injections:
69-
if hasattr(injection, "dbms") and injection.dbms:
70-
inferencedDbms = injection.dbms
71-
break
72-
73-
if inferencedDbms is not None:
66+
if getIdentifiedDBMS() is not None:
7467
for i in xrange(len(dbmsObj)):
7568
dbmsAliases, _, _ = dbmsObj[i]
7669

77-
if inferencedDbms.lower() in dbmsAliases:
70+
if getIdentifiedDBMS().lower() in dbmsAliases:
7871
if i > 0:
7972
pushValue(dbmsObj[i])
8073
dbmsObj.remove(dbmsObj[i])

lib/core/agent.py

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from lib.core.common import getCompiledRegex
1515
from lib.core.common import getErrorParsedDBMSes
16+
from lib.core.common import getIdentifiedDBMS
1617
from lib.core.common import isDBMSVersionAtLeast
1718
from lib.core.common import isTechniqueAvailable
1819
from lib.core.common import randomInt
@@ -33,13 +34,6 @@ class Agent:
3334
This class defines the SQL agent methods.
3435
"""
3536

36-
def __init__(self):
37-
kb.misc = advancedDict()
38-
kb.misc.delimiter = randomStr(length=6)
39-
kb.misc.start = ":%s:" % randomStr(length=3, lowercase=True)
40-
kb.misc.stop = ":%s:" % randomStr(length=3, lowercase=True)
41-
kb.misc.space = ":%s:" % randomStr(length=1, lowercase=True)
42-
4337
def payloadDirect(self, query):
4438
if query.startswith("AND "):
4539
query = query.replace("AND ", "SELECT ", 1)
@@ -211,8 +205,8 @@ def cleanupPayload(self, payload, origvalue=None, query=None):
211205
payload = payload.replace("[ORIGVALUE]", origvalue)
212206

213207
if "[INFERENCE]" in payload:
214-
if kb.dbms is not None:
215-
inference = queries[kb.dbms].inference
208+
if getIdentifiedDBMS() is not None:
209+
inference = queries[getIdentifiedDBMS()].inference
216210

217211
if "dbms_version" in inference:
218212
if isDBMSVersionAtLeast(inference.dbms_version):
@@ -223,11 +217,6 @@ def cleanupPayload(self, payload, origvalue=None, query=None):
223217
inferenceQuery = inference.query
224218

225219
payload = payload.replace("[INFERENCE]", inferenceQuery)
226-
227-
elif hasattr(kb.misc, "testedDbms") and kb.misc.testedDbms is not None:
228-
inferenceQuery = queries[kb.misc.testedDbms].inference.query
229-
payload = payload.replace("[INFERENCE]", inferenceQuery)
230-
231220
else:
232221
errMsg = "invalid usage of inference payload without "
233222
errMsg += "knowledge of underlying DBMS"
@@ -275,17 +264,17 @@ def nullAndCastField(self, field):
275264

276265
# SQLite version 2 does not support neither CAST() nor IFNULL(),
277266
# introduced only in SQLite version 3
278-
if kb.dbms == DBMS.SQLITE:
267+
if getIdentifiedDBMS() == DBMS.SQLITE:
279268
return field
280269

281270
if field.startswith("(CASE"):
282271
nulledCastedField = field
283272
else:
284-
nulledCastedField = queries[kb.dbms].cast.query % field
285-
if kb.dbms == DBMS.ACCESS:
286-
nulledCastedField = queries[kb.dbms].isnull.query % (nulledCastedField, nulledCastedField)
273+
nulledCastedField = queries[getIdentifiedDBMS()].cast.query % field
274+
if getIdentifiedDBMS() == DBMS.ACCESS:
275+
nulledCastedField = queries[getIdentifiedDBMS()].isnull.query % (nulledCastedField, nulledCastedField)
287276
else:
288-
nulledCastedField = queries[kb.dbms].isnull.query % nulledCastedField
277+
nulledCastedField = queries[getIdentifiedDBMS()].isnull.query % nulledCastedField
289278

290279
return nulledCastedField
291280

@@ -324,7 +313,7 @@ def nullCastConcatFields(self, fields):
324313

325314
fields = fields.replace(", ", ",")
326315
fieldsSplitted = fields.split(",")
327-
dbmsDelimiter = queries[kb.dbms].delimiter.query
316+
dbmsDelimiter = queries[getIdentifiedDBMS()].delimiter.query
328317
nulledCastedFields = []
329318

330319
for field in fieldsSplitted:
@@ -383,13 +372,13 @@ def getFields(self, query):
383372
def simpleConcatQuery(self, query1, query2):
384373
concatenatedQuery = ""
385374

386-
if kb.dbms == DBMS.MYSQL:
375+
if getIdentifiedDBMS() == DBMS.MYSQL:
387376
concatenatedQuery = "CONCAT(%s,%s)" % (query1, query2)
388377

389-
elif kb.dbms in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ):
378+
elif getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ):
390379
concatenatedQuery = "%s||%s" % (query1, query2)
391380

392-
elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE):
381+
elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE):
393382
concatenatedQuery = "%s+%s" % (query1, query2)
394383

395384
return concatenatedQuery
@@ -431,7 +420,7 @@ def concatQuery(self, query, unpack=True):
431420
concatenatedQuery = query
432421
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query)
433422

434-
if kb.dbms == DBMS.MYSQL:
423+
if getIdentifiedDBMS() == DBMS.MYSQL:
435424
if fieldsSelectCase:
436425
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1)
437426
concatenatedQuery += ",'%s')" % kb.misc.stop
@@ -444,7 +433,7 @@ def concatQuery(self, query, unpack=True):
444433
elif fieldsNoSelect:
445434
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.misc.start, concatenatedQuery, kb.misc.stop)
446435

447-
elif kb.dbms in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ):
436+
elif getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ):
448437
if fieldsSelectCase:
449438
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1)
450439
concatenatedQuery += "||'%s'" % kb.misc.stop
@@ -457,10 +446,10 @@ def concatQuery(self, query, unpack=True):
457446
elif fieldsNoSelect:
458447
concatenatedQuery = "'%s'||%s||'%s'" % (kb.misc.start, concatenatedQuery, kb.misc.stop)
459448

460-
if kb.dbms == DBMS.ORACLE and " FROM " not in concatenatedQuery and ( fieldsSelect or fieldsNoSelect ):
449+
if getIdentifiedDBMS() == DBMS.ORACLE and " FROM " not in concatenatedQuery and ( fieldsSelect or fieldsNoSelect ):
461450
concatenatedQuery += " FROM DUAL"
462451

463-
elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE):
452+
elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE):
464453
if fieldsSelectTop:
465454
topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
466455
concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.misc.start), 1)
@@ -511,13 +500,13 @@ def forgeInbandQuery(self, query, position, count, comment, prefix, suffix, char
511500
"""
512501

513502
if query.startswith("SELECT "):
514-
query = query[len("SELECT "):]
503+
query = query[len("SELECT "):]
515504

516505
inbandQuery = self.prefixQuery("UNION ALL SELECT ", prefix=prefix)
517506

518507
if query.startswith("TOP"):
519-
topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1)
520-
query = query[len("TOP %s " % topNum):]
508+
topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1)
509+
query = query[len("TOP %s " % topNum):]
521510
inbandQuery += "TOP %s " % topNum
522511

523512
intoRegExp = re.search("(\s+INTO (DUMP|OUT)FILE\s+\'(.+?)\')", query, re.I)
@@ -526,7 +515,7 @@ def forgeInbandQuery(self, query, position, count, comment, prefix, suffix, char
526515
intoRegExp = intoRegExp.group(1)
527516
query = query[:query.index(intoRegExp)]
528517

529-
if kb.dbms == DBMS.ORACLE and inbandQuery.endswith(" FROM DUAL"):
518+
if getIdentifiedDBMS() == DBMS.ORACLE and inbandQuery.endswith(" FROM DUAL"):
530519
inbandQuery = inbandQuery[:-len(" FROM DUAL")]
531520

532521
for element in range(count):
@@ -546,7 +535,7 @@ def forgeInbandQuery(self, query, position, count, comment, prefix, suffix, char
546535
conditionIndex = query.index(" FROM ")
547536
inbandQuery += query[conditionIndex:]
548537

549-
if kb.dbms == DBMS.ORACLE or DBMS.ORACLE in getErrorParsedDBMSes():
538+
if getIdentifiedDBMS() == DBMS.ORACLE:
550539
if " FROM " not in inbandQuery:
551540
inbandQuery += " FROM DUAL"
552541

@@ -565,7 +554,7 @@ def forgeInbandQuery(self, query, position, count, comment, prefix, suffix, char
565554
else:
566555
inbandQuery += char
567556

568-
if kb.dbms == DBMS.ORACLE:
557+
if getIdentifiedDBMS() == DBMS.ORACLE:
569558
inbandQuery += " FROM DUAL"
570559

571560
inbandQuery = self.suffixQuery(inbandQuery, comment, suffix)
@@ -595,21 +584,21 @@ def limitQuery(self, num, query, field=None):
595584
"""
596585

597586
limitedQuery = query
598-
limitStr = queries[kb.dbms].limit.query
587+
limitStr = queries[getIdentifiedDBMS()].limit.query
599588
fromIndex = limitedQuery.index(" FROM ")
600589
untilFrom = limitedQuery[:fromIndex]
601590
fromFrom = limitedQuery[fromIndex+1:]
602591
orderBy = False
603592

604-
if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE ):
605-
limitStr = queries[kb.dbms].limit.query % (num, 1)
593+
if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE ):
594+
limitStr = queries[getIdentifiedDBMS()].limit.query % (num, 1)
606595
limitedQuery += " %s" % limitStr
607596

608-
elif kb.dbms == DBMS.FIREBIRD:
609-
limitStr = queries[kb.dbms].limit.query % (num+1, num+1)
597+
elif getIdentifiedDBMS() == DBMS.FIREBIRD:
598+
limitStr = queries[getIdentifiedDBMS()].limit.query % (num+1, num+1)
610599
limitedQuery += " %s" % limitStr
611600

612-
elif kb.dbms == DBMS.ORACLE:
601+
elif getIdentifiedDBMS() == DBMS.ORACLE:
613602
if " ORDER BY " in limitedQuery and "(SELECT " in limitedQuery:
614603
orderBy = limitedQuery[limitedQuery.index(" ORDER BY "):]
615604
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
@@ -621,7 +610,7 @@ def limitQuery(self, num, query, field=None):
621610
limitedQuery = limitedQuery % fromFrom
622611
limitedQuery += "=%d" % (num + 1)
623612

624-
elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE):
613+
elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE):
625614
forgeNotIn = True
626615

627616
if " ORDER BY " in limitedQuery:
@@ -635,7 +624,7 @@ def limitQuery(self, num, query, field=None):
635624
limitedQuery = limitedQuery.replace("DISTINCT %s" % notDistinct, notDistinct)
636625

637626
if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "):
638-
topNums = re.search(queries[kb.dbms].limitregexp.query, limitedQuery, re.I)
627+
topNums = re.search(queries[getIdentifiedDBMS()].limitregexp.query, limitedQuery, re.I)
639628

640629
if topNums:
641630
topNums = topNums.groups()
@@ -681,7 +670,7 @@ def forgeCaseStatement(self, expression):
681670
@rtype: C{str}
682671
"""
683672

684-
return queries[kb.dbms if kb.dbms else kb.misc.testedDbms].case.query % expression
673+
return queries[getIdentifiedDBMS()].case.query % expression
685674

686675
def addPayloadDelimiters(self, inpStr):
687676
"""

lib/core/common.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,15 +218,15 @@ def formatDBMSfp(versions=None):
218218
versions = kb.dbmsVersion
219219

220220
if isinstance(versions, basestring):
221-
return "%s %s" % (kb.dbms, versions)
221+
return "%s %s" % (getIdentifiedDBMS(), versions)
222222
elif isinstance(versions, (list, set, tuple)):
223-
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
223+
return "%s %s" % (getIdentifiedDBMS(), " and ".join([version for version in versions]))
224224
elif not versions:
225225
warnMsg = "unable to extensively fingerprint the back-end "
226226
warnMsg += "DBMS version"
227227
logger.warn(warnMsg)
228228

229-
return kb.dbms
229+
return getIdentifiedDBMS()
230230

231231
def formatFingerprintString(values, chain=" or "):
232232
strJoin = "|".join([v for v in values])
@@ -627,7 +627,7 @@ def parsePasswordHash(password):
627627
if not password or password == " ":
628628
password = "NULL"
629629

630-
if kb.dbms == DBMS.MSSQL and password != "NULL" and isHexEncodedString(password):
630+
if getIdentifiedDBMS() == DBMS.MSSQL and password != "NULL" and isHexEncodedString(password):
631631
hexPassword = password
632632
password = "%s\n" % hexPassword
633633
password += "%sheader: %s\n" % (blank, hexPassword[:6])
@@ -928,25 +928,25 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
928928
def getDelayQuery(andCond=False):
929929
query = None
930930

931-
if kb.dbms in (DBMS.MYSQL, DBMS.PGSQL):
931+
if getIdentifiedDBMS() in (DBMS.MYSQL, DBMS.PGSQL):
932932
if not kb.data.banner:
933933
conf.dbmsHandler.getVersionFromBanner()
934934

935935
banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
936936

937-
if banVer is None or (kb.dbms == DBMS.MYSQL and banVer >= "5.0.12") or (kb.dbms == DBMS.PGSQL and banVer >= "8.2"):
938-
query = queries[kb.dbms].timedelay.query % conf.timeSec
937+
if banVer is None or (getIdentifiedDBMS() == DBMS.MYSQL and banVer >= "5.0.12") or (getIdentifiedDBMS() == DBMS.PGSQL and banVer >= "8.2"):
938+
query = queries[getIdentifiedDBMS()].timedelay.query % conf.timeSec
939939
else:
940-
query = queries[kb.dbms].timedelay.query2 % conf.timeSec
941-
elif kb.dbms == DBMS.FIREBIRD:
942-
query = queries[kb.dbms].timedelay.query
940+
query = queries[getIdentifiedDBMS()].timedelay.query2 % conf.timeSec
941+
elif getIdentifiedDBMS() == DBMS.FIREBIRD:
942+
query = queries[getIdentifiedDBMS()].timedelay.query
943943
else:
944-
query = queries[kb.dbms].timedelay.query % conf.timeSec
944+
query = queries[getIdentifiedDBMS()].timedelay.query % conf.timeSec
945945

946946
if andCond:
947-
if kb.dbms in ( DBMS.MYSQL, DBMS.SQLITE ):
947+
if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.SQLITE ):
948948
query = query.replace("SELECT ", "")
949-
elif kb.dbms == DBMS.FIREBIRD:
949+
elif getIdentifiedDBMS() == DBMS.FIREBIRD:
950950
query = "(%s)>0" % query
951951

952952
return query
@@ -1763,7 +1763,7 @@ def aliasToDbmsEnum(value):
17631763
retVal = None
17641764

17651765
for key, item in dbmsDict.items():
1766-
if value in item[0]:
1766+
if value.lower() in item[0]:
17671767
retVal = key
17681768
break
17691769

@@ -2040,6 +2040,18 @@ def getErrorParsedDBMSes():
20402040

20412041
return kb.htmlFp
20422042

2043+
def getIdentifiedDBMS():
2044+
dbms = None
2045+
2046+
if kb.dbms is not None:
2047+
dbms = kb.dbms
2048+
elif conf.dbms is not None:
2049+
dbms = conf.dbms
2050+
elif getErrorParsedDBMSes() is not None:
2051+
dbms = getErrorParsedDBMSes()[0]
2052+
2053+
return aliasToDbmsEnum(dbms)
2054+
20432055
def showHttpErrorCodes():
20442056
"""
20452057
Shows all HTTP error codes raised till now

lib/core/enums.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class DBMS:
3131
MSSQL = "Microsoft SQL Server"
3232
MYSQL = "MySQL"
3333
ORACLE = "Oracle"
34-
PGSQL = "PostgreSQL"
34+
PGSQL = "PostgreSQL"
3535
SQLITE = "SQLite"
3636
SYBASE = "Sybase"
3737

lib/core/option.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from lib.core.common import parseTargetUrl
3535
from lib.core.common import paths
3636
from lib.core.common import randomRange
37+
from lib.core.common import randomStr
3738
from lib.core.common import readCachedFileContent
3839
from lib.core.common import readInput
3940
from lib.core.common import runningAsAdmin
@@ -46,6 +47,7 @@
4647
from lib.core.data import queries
4748
from lib.core.datatype import advancedDict
4849
from lib.core.datatype import injectionDict
50+
from lib.core.enums import DBMS
4951
from lib.core.enums import HTTPMETHOD
5052
from lib.core.enums import PAYLOAD
5153
from lib.core.enums import PRIORITY
@@ -1165,6 +1167,12 @@ def __setKnowledgeBaseAttributes(flushAll=True):
11651167
kb.threadException = False
11661168
kb.threadData = {}
11671169

1170+
kb.misc = advancedDict()
1171+
kb.misc.delimiter = randomStr(length=6)
1172+
kb.misc.start = ":%s:" % randomStr(length=3, lowercase=True)
1173+
kb.misc.stop = ":%s:" % randomStr(length=3, lowercase=True)
1174+
kb.misc.space = ":%s:" % randomStr(length=1, lowercase=True)
1175+
11681176
if flushAll:
11691177
kb.keywords = set(getFileItems(paths.SQL_KEYWORDS))
11701178
kb.tamperFunctions = []

0 commit comments

Comments
 (0)