Major code refactoring - centralized all kb.dbms* info for both retrieval and set.

This commit is contained in:
Bernardo Damele
2011-01-19 23:06:15 +00:00
parent 4bdc19d879
commit bade0e3124
39 changed files with 915 additions and 810 deletions

View File

@@ -78,12 +78,14 @@ from lib.core.settings import MIN_TIME_RESPONSES
from lib.core.settings import TIME_DEFAULT_DELAY
from lib.core.settings import TIME_STDEV_COEFF
from lib.core.settings import DYNAMICITY_MARK_LENGTH
from lib.core.settings import UNKNOWN_DBMS_VERSION
from lib.core.threads import getCurrentThreadData
class UnicodeRawConfigParser(RawConfigParser):
"""
RawConfigParser with unicode writing support
"""
def write(self, fp):
"""
Write an .ini-format representation of the configuration state.
@@ -109,10 +111,10 @@ class UnicodeRawConfigParser(RawConfigParser):
fp.write("\n")
class DynamicContentItem:
"""
Represents line in content page with dynamic properties (candidate for removal prior detection phase)
Represents line in content page with dynamic properties (candidate
for removal prior detection phase)
"""
def __init__(self, lineNumber, pageTotal, lineContentBefore, lineContentAfter):
@@ -121,7 +123,6 @@ class DynamicContentItem:
self.lineContentBefore = lineContentBefore
self.lineContentAfter = lineContentAfter
def paramToDict(place, parameters=None):
"""
Split the parameters into names and values, check if these parameters
@@ -203,110 +204,6 @@ def paramToDict(place, parameters=None):
return testableParameters
def formatDBMSfp(versions=None):
"""
This function format the back-end DBMS fingerprint value and return its
values formatted as a human readable string.
@return: detected back-end DBMS based upon fingerprint techniques.
@rtype: C{str}
"""
while versions and None in versions:
versions.remove(None)
if not versions and kb.dbmsVersion and kb.dbmsVersion[0] != UNKNOWN_DBMS_VERSION and kb.dbmsVersion[0] != None:
versions = kb.dbmsVersion
if isinstance(versions, basestring):
return "%s %s" % (getIdentifiedDBMS(), versions)
elif isinstance(versions, (list, set, tuple)):
return "%s %s" % (getIdentifiedDBMS(), " and ".join([version for version in versions]))
elif not versions:
warnMsg = "unable to extensively fingerprint the back-end "
warnMsg += "DBMS version"
logger.warn(warnMsg)
return getIdentifiedDBMS()
def formatFingerprintString(values, chain=" or "):
strJoin = "|".join([v for v in values])
return strJoin.replace("|", chain)
def formatFingerprint(target, info):
"""
This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string.
Example of info (kb.headersFp) dictionary:
{
'distrib': set(['Ubuntu']),
'type': set(['Linux']),
'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
'release': set(['8.10'])
}
Example of info (kb.bannerFp) dictionary:
{
'sp': set(['Service Pack 4']),
'dbmsVersion': '8.00.194',
'dbmsServicePack': '0',
'distrib': set(['2000']),
'dbmsRelease': '2000',
'type': set(['Windows'])
}
@return: detected back-end operating system based upon fingerprint
techniques.
@rtype: C{str}
"""
infoStr = ""
if info and "type" in info:
infoStr += "%s operating system: %s" % (target, formatFingerprintString(info["type"]))
if "distrib" in info:
infoStr += " %s" % formatFingerprintString(info["distrib"])
if "release" in info:
infoStr += " %s" % formatFingerprintString(info["release"])
if "sp" in info:
infoStr += " %s" % formatFingerprintString(info["sp"])
if "codename" in info:
infoStr += " (%s)" % formatFingerprintString(info["codename"])
if "technology" in info:
infoStr += "\nweb application technology: %s" % formatFingerprintString(info["technology"], ", ")
return infoStr
def getErrorParsedDBMSesFormatted():
"""
This function parses the knowledge base htmlFp list and return its
values formatted as a human readable string.
@return: list of possible back-end DBMS based upon error messages
parsing.
@rtype: C{str}
"""
htmlParsed = ""
if len(kb.htmlFp) == 0:
return None
elif len(kb.htmlFp) == 1:
htmlParsed = kb.htmlFp[0]
elif len(kb.htmlFp) > 1:
htmlParsed = " or ".join([htmlFp for htmlFp in kb.htmlFp])
return htmlParsed
def getDocRoot(webApi=None):
docRoot = None
pagePath = directoryPath(conf.path)
@@ -626,14 +523,14 @@ def parsePasswordHash(password):
if not password or password == " ":
password = "NULL"
if getIdentifiedDBMS() == DBMS.MSSQL and password != "NULL" and isHexEncodedString(password):
if backend.getIdentifiedDbms() == DBMS.MSSQL and password != "NULL" and isHexEncodedString(password):
hexPassword = password
password = "%s\n" % hexPassword
password += "%sheader: %s\n" % (blank, hexPassword[:6])
password += "%ssalt: %s\n" % (blank, hexPassword[6:14])
password += "%smixedcase: %s\n" % (blank, hexPassword[14:54])
if kb.dbmsVersion[0] not in ( "2005", "2008" ):
if not backend.isVersionWithin(("2005", "2008")):
password += "%suppercase: %s" % (blank, hexPassword[54:])
return password
@@ -927,25 +824,25 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
def getDelayQuery(andCond=False):
query = None
if getIdentifiedDBMS() in (DBMS.MYSQL, DBMS.PGSQL):
if backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
if not kb.data.banner:
conf.dbmsHandler.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None
if banVer is None or (getIdentifiedDBMS() == DBMS.MYSQL and banVer >= "5.0.12") or (getIdentifiedDBMS() == DBMS.PGSQL and banVer >= "8.2"):
query = queries[getIdentifiedDBMS()].timedelay.query % conf.timeSec
if banVer is None or (backend.getIdentifiedDbms() == DBMS.MYSQL and banVer >= "5.0.12") or (backend.getIdentifiedDbms() == DBMS.PGSQL and banVer >= "8.2"):
query = queries[backend.getIdentifiedDbms()].timedelay.query % conf.timeSec
else:
query = queries[getIdentifiedDBMS()].timedelay.query2 % conf.timeSec
elif getIdentifiedDBMS() == DBMS.FIREBIRD:
query = queries[getIdentifiedDBMS()].timedelay.query
query = queries[backend.getIdentifiedDbms()].timedelay.query2 % conf.timeSec
elif backend.getIdentifiedDbms() == DBMS.FIREBIRD:
query = queries[backend.getIdentifiedDbms()].timedelay.query
else:
query = queries[getIdentifiedDBMS()].timedelay.query % conf.timeSec
query = queries[backend.getIdentifiedDbms()].timedelay.query % conf.timeSec
if andCond:
if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.SQLITE ):
if backend.getIdentifiedDbms() in ( DBMS.MYSQL, DBMS.SQLITE ):
query = query.replace("SELECT ", "")
elif getIdentifiedDBMS() == DBMS.FIREBIRD:
elif backend.getIdentifiedDbms() == DBMS.FIREBIRD:
query = "(%s)>0" % query
return query
@@ -1524,7 +1421,6 @@ def getUnicode(value, encoding=None):
else:
return unicode(value) # encoding ignored for non-basestring instances
# http://boredzo.org/blog/archives/2007-01-06/longest-common-prefix-in-python-2
def longestCommonPrefix(*sequences):
if len(sequences) == 1:
@@ -1902,8 +1798,8 @@ def isDBMSVersionAtLeast(version):
retVal = None
if kb.dbmsVersion and kb.dbmsVersion[0] != UNKNOWN_DBMS_VERSION and kb.dbmsVersion[0] != None:
value = kb.dbmsVersion[0].replace(" ", "").rstrip('.')
if backend.getVersion() and backend.getVersion() != UNKNOWN_DBMS_VERSION:
value = backend.getVersion().replace(" ", "").rstrip('.')
while True:
index = value.find('.', value.find('.') + 1)
@@ -2004,7 +1900,7 @@ def arrayizeValue(value):
return value
def getInjectionTests():
def getSortedInjectionTests():
"""
Returns prioritized test list by eventually detected DBMS from error
messages
@@ -2019,14 +1915,14 @@ def getInjectionTests():
retVal = SORTORDER.LAST
elif 'details' in test and 'dbms' in test.details:
if test.details.dbms in getErrorParsedDBMSes():
if test.details.dbms in backend.getErrorParsedDBMSes():
retVal = SORTORDER.SECOND
else:
retVal = SORTORDER.THIRD
return retVal
if getErrorParsedDBMSes():
if backend.getErrorParsedDBMSes():
retVal = sorted(retVal, key=priorityFunction)
return retVal
@@ -2064,34 +1960,218 @@ def unicodeToSafeHTMLValue(value):
return retVal
def getErrorParsedDBMSes():
"""
Returns array with parsed DBMS names till now
class format:
@staticmethod
def humanize(values, chain=" or "):
strJoin = "|".join([v for v in values])
This functions is called to:
return strJoin.replace("|", chain)
1. Sort the tests, getInjectionTests() - detection phase.
2. Ask user whether or not skip specific DBMS tests in detection phase,
lib/controller/checks.py - detection phase.
3. Sort the fingerprint of the DBMS, lib/controller/handler.py -
fingerprint phase.
"""
# Get methods
@staticmethod
def getDbms(versions=None):
"""
Format the back-end DBMS fingerprint value and return its
values formatted as a human readable string.
return kb.htmlFp
@return: detected back-end DBMS based upon fingerprint techniques.
@rtype: C{str}
"""
def getIdentifiedDBMS():
dbms = None
if versions is None and backend.getVersionList():
versions = backend.getVersionList()
if kb.misc.forcedDbms is not None:
dbms = kb.misc.forcedDbms
elif kb.dbms is not None:
dbms = kb.dbms
elif conf.dbms is not None:
dbms = conf.dbms
elif len(getErrorParsedDBMSes()) > 0:
dbms = getErrorParsedDBMSes()[0]
if versions is None:
return backend.getDbms()
else:
return "%s %s" % (backend.getDbms(), " and ".join([v for v in versions]))
return aliasToDbmsEnum(dbms)
@staticmethod
def getErrorParsedDBMSes():
"""
Parses the knowledge base htmlFp list and return its values
formatted as a human readable string.
@return: list of possible back-end DBMS based upon error messages
parsing.
@rtype: C{str}
"""
htmlParsed = ""
if len(kb.htmlFp) == 0:
return None
elif len(kb.htmlFp) == 1:
htmlParsed = kb.htmlFp[0]
elif len(kb.htmlFp) > 1:
htmlParsed = " or ".join([htmlFp for htmlFp in kb.htmlFp])
return htmlParsed
@staticmethod
def getOs(target, info):
"""
Formats the back-end operating system fingerprint value
and return its values formatted as a human readable string.
Example of info (kb.headersFp) dictionary:
{
'distrib': set(['Ubuntu']),
'type': set(['Linux']),
'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
'release': set(['8.10'])
}
Example of info (kb.bannerFp) dictionary:
{
'sp': set(['Service Pack 4']),
'dbmsVersion': '8.00.194',
'dbmsServicePack': '0',
'distrib': set(['2000']),
'dbmsRelease': '2000',
'type': set(['Windows'])
}
@return: detected back-end operating system based upon fingerprint
techniques.
@rtype: C{str}
"""
infoStr = ""
if info and "type" in info:
infoStr += "%s operating system: %s" % (target, format.humanize(info["type"]))
if "distrib" in info:
infoStr += " %s" % format.humanize(info["distrib"])
if "release" in info:
infoStr += " %s" % format.humanize(info["release"])
if "sp" in info:
infoStr += " %s" % format.humanize(info["sp"])
if "codename" in info:
infoStr += " (%s)" % format.humanize(info["codename"])
if "technology" in info:
infoStr += "\nweb application technology: %s" % format.humanize(info["technology"], ", ")
return infoStr
class backend:
# Set methods
@staticmethod
def setDbms(dbms):
kb.dbms = aliasToDbmsEnum(dbms)
@staticmethod
def setVersion(version):
if isinstance(version, basestring):
kb.dbmsVersion = [ version ]
@staticmethod
def setVersionList(versionsList):
if isinstance(versionsList, list):
kb.dbmsVersion = versionsList
elif isinstance(version, basestring):
backend.setVersion(versionsList)
else:
logger.error("invalid format of versionsList")
@staticmethod
def forceDbms(dbms):
kb.misc.forcedDbms = aliasToDbmsEnum(dbms)
@staticmethod
def flushForcedDbms():
kb.misc.forcedDbms = None
# Get methods
@staticmethod
def getForcedDbms():
return aliasToDbmsEnum(kb.misc.forcedDbms)
@staticmethod
def getDbms():
return aliasToDbmsEnum(kb.dbms)
@staticmethod
def getErrorParsedDBMSes():
"""
Returns array with parsed DBMS names till now
This functions is called to:
1. Sort the tests, getSortedInjectionTests() - detection phase.
2. Ask user whether or not skip specific DBMS tests in detection phase,
lib/controller/checks.py - detection phase.
3. Sort the fingerprint of the DBMS, lib/controller/handler.py -
fingerprint phase.
"""
return kb.htmlFp
@staticmethod
def getIdentifiedDbms():
dbms = None
if backend.getForcedDbms() is not None:
dbms = backend.getForcedDbms()
elif backend.getDbms() is not None:
dbms = kb.dbms
elif conf.dbms is not None:
dbms = conf.dbms
elif len(backend.getErrorParsedDBMSes()) > 0:
dbms = backend.getErrorParsedDBMSes()[0]
return aliasToDbmsEnum(dbms)
@staticmethod
def getVersion():
if len(kb.dbmsVersion) > 0:
return kb.dbmsVersion[0]
else:
return None
@staticmethod
def getVersionList():
if len(kb.dbmsVersion) > 0:
return kb.dbmsVersion
else:
return None
# Comparison methods
@staticmethod
def isDbms(dbms):
return backend.getDbms() is not None and backend.getDbms() == aliasToDbmsEnum(dbms)
@staticmethod
def isDbmsWithin(aliases):
return backend.getDbms() is not None and backend.getDbms().lower() in aliases
@staticmethod
def isVersion(version):
return backend.getVersion() is not None and backend.getVersion() == version
@staticmethod
def isVersionWithin(versionList):
if backend.getVersionList() is None:
return False
for dbmsVersion in backend.getVersionList():
if dbmsVersion == UNKNOWN_DBMS_VERSION:
continue
elif dbmsVersion in versionList:
return True
return False
@staticmethod
def isVersionGreaterOrEqualThan(version):
return backend.getVersion() is not None and str(backend.getVersion()) >= str(version)
def showHttpErrorCodes():
"""