diff --git a/lib/core/common.py b/lib/core/common.py
index 68f127800..b2a862c95 100644
--- a/lib/core/common.py
+++ b/lib/core/common.py
@@ -130,7 +130,11 @@ def formatDBMSfp(versions=None):
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
-def formatOSfp(info):
+def __formatOSfpString(values):
+ return " or ".join([v for v in values])
+
+
+def formatOSfp():
"""
This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string.
@@ -142,31 +146,40 @@ def formatOSfp(info):
infoStr = ""
- # Example of 'info' dictionary:
+ # Examples of kb.bannerFp dictionary:
+ #
# {
- # 'distrib': 'Ubuntu',
- # 'release': '8.10',
- # 'codename': 'Intrepid',
- # 'version': '5.0.67',
- # 'type': 'Linux'
+ # "distrib": set(["2000"]),
+ # "dbmsVersion": "8.00.194",
+ # "dbmsRelease": "2000",
+ # "dbmsServicePack": "0",
+ # "type": set(["Windows"])
+ # }
+ #
+ # {
+ # "distrib": set(["Ubuntu"]),
+ # "release": set(["8.10"]),
+ # "codename": set(["Intrepid"]),
+ # "version": "5.0.67",
+ # "type": set(["Linux"])
# }
- if not info or 'type' not in info:
+ if not kb.bannerFp or "type" not in kb.bannerFp:
return infoStr
- elif info['type'] != "None":
- infoStr += "back-end DBMS operating system: %s" % info['type']
+ else:
+ infoStr += "back-end DBMS operating system: %s" % __formatOSfpString(kb.bannerFp["type"])
- if 'distrib' in info and info['distrib'] != "None":
- infoStr += " %s" % info['distrib']
+ if "distrib" in kb.bannerFp:
+ infoStr += " %s" % __formatOSfpString(kb.bannerFp["distrib"])
- if 'release' in info and info['release'] != "None":
- infoStr += " %s" % info['release']
+ if "release" in kb.bannerFp:
+ infoStr += " %s" % __formatOSfpString(kb.bannerFp["release"])
- if 'sp' in info and info['sp'] != "None":
- infoStr += " %s" % info['sp']
+ if "sp" in kb.bannerFp:
+ infoStr += " %s" % __formatOSfpString(kb.bannerFp["sp"])
- if 'codename' in info and info['codename'] != "None":
- infoStr += " (%s)" % info['codename']
+ if "codename" in kb.bannerFp:
+ infoStr += " (%s)" % __formatOSfpString(kb.bannerFp["codename"])
return infoStr
@@ -248,7 +261,7 @@ def getDirectories():
if kb.docRoot:
directories.add(kb.docRoot)
- pagePath = re.search('^/(.*)/', conf.path)
+ pagePath = re.search("^/(.*)/", conf.path)
if kb.docRoot and pagePath:
pagePath = pagePath.groups()[0]
diff --git a/lib/core/option.py b/lib/core/option.py
index 89b992868..da8099fd0 100644
--- a/lib/core/option.py
+++ b/lib/core/option.py
@@ -453,6 +453,7 @@ def __setKnowledgeBaseAttributes():
kb.dbms = None
kb.dbmsDetected = False
kb.dbmsVersion = None
+ kb.bannerFp = {}
kb.headersFp = {}
kb.htmlFp = []
kb.injParameter = None
diff --git a/lib/parse/banner.py b/lib/parse/banner.py
index 71fc1da9b..7b4f0ea87 100644
--- a/lib/parse/banner.py
+++ b/lib/parse/banner.py
@@ -44,11 +44,24 @@ class BannerHandler(ContentHandler):
def __init__(self, banner):
self.__banner = sanitizeStr(banner)
- self.__regexp = None
- self.__match = None
- self.__position = None
+ self.__regexp = None
+ self.__match = None
+ self.__version = None
- self.info = {}
+
+ def __feedInfo(self, key, value):
+ value = sanitizeStr(value)
+
+ if value in ( None, "None" ):
+ return
+
+ if key == "version":
+ kb.bannerFp[key] = value
+ else:
+ if key not in kb.bannerFp.keys():
+ kb.bannerFp[key] = set()
+
+ kb.bannerFp[key].add(value)
def startElement(self, name, attrs):
@@ -57,22 +70,23 @@ class BannerHandler(ContentHandler):
self.__match = re.search(self.__regexp, self.__banner, re.I | re.M)
if name == "info" and self.__match:
- self.__position = sanitizeStr(attrs.get("version"))
+ self.__feedInfo("type", attrs.get("type"))
+ self.__feedInfo("distrib", attrs.get("distrib"))
+ self.__feedInfo("release", attrs.get("release"))
+ self.__feedInfo("codename", attrs.get("codename"))
+
+ self.__version = sanitizeStr(attrs.get("version"))
self.__sp = sanitizeStr(attrs.get("sp"))
- self.info['type'] = sanitizeStr(attrs.get("type"))
- self.info['distrib'] = sanitizeStr(attrs.get("distrib"))
- self.info['release'] = sanitizeStr(attrs.get("release"))
- self.info['codename'] = sanitizeStr(attrs.get("codename"))
-
- if self.__position.isdigit():
- self.info['version'] = self.__match.group(int(self.__position))
+ if self.__version.isdigit():
+ self.__feedInfo("version", self.__match.group(int(self.__version)))
if self.__sp.isdigit():
- self.info['sp'] = "Service Pack %s" % self.__match.group(int(self.__sp))
+ self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
- self.__match = None
- self.__position = None
+ self.__regexp = None
+ self.__match = None
+ self.__version = None
class MSSQLBannerHandler(ContentHandler):
@@ -90,7 +104,14 @@ class MSSQLBannerHandler(ContentHandler):
self.__version = ""
self.__servicePack = ""
- self.info = {}
+
+ def __feedInfo(self, key, value):
+ value = sanitizeStr(value)
+
+ if value in ( None, "None" ):
+ return
+
+ kb.bannerFp[key] = value
def startElement(self, name, attrs):
@@ -114,9 +135,9 @@ class MSSQLBannerHandler(ContentHandler):
def endElement(self, name):
if name == "signature":
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
- self.info['dbmsRelease'] = self.__release
- self.info['dbmsVersion'] = self.__version
- self.info['dbmsServicePack'] = self.__servicePack
+ self.__feedInfo("dbmsRelease", self.__release)
+ self.__feedInfo("dbmsVersion", self.__version)
+ self.__feedInfo("dbmsServicePack", self.__servicePack)
self.__version = ""
self.__servicePack = ""
@@ -137,9 +158,6 @@ def bannerParser(banner):
DBMS banner based upon the data in XML file
"""
- banner = sanitizeStr(banner)
- info = {}
-
if kb.dbms == "Microsoft SQL Server":
xmlfile = paths.MSSQL_XML
elif kb.dbms == "MySQL":
@@ -154,24 +172,9 @@ def bannerParser(banner):
if kb.dbms == "Microsoft SQL Server":
handler = MSSQLBannerHandler(banner)
parse(xmlfile, handler)
- info = handler.info
-
handler = BannerHandler(banner)
parse(paths.GENERIC_XML, handler)
-
- for title, value in handler.info.items():
- info[title] = value
else:
handler = BannerHandler(banner)
parse(xmlfile, handler)
- info = handler.info
-
- if "type" not in info or info["type"] == "None":
- parse(paths.GENERIC_XML, handler)
- info["type"] = handler.info["type"]
-
- if "distrib" not in info or info["distrib"] == "None":
- parse(paths.GENERIC_XML, handler)
- info["distrib"] = handler.info["distrib"]
-
- return info
+ parse(paths.GENERIC_XML, handler)
diff --git a/lib/parse/headers.py b/lib/parse/headers.py
index 00fa2dae8..f3c8dc25c 100644
--- a/lib/parse/headers.py
+++ b/lib/parse/headers.py
@@ -26,10 +26,68 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
+from xml.sax import parse
+from xml.sax.handler import ContentHandler
+
from lib.core.common import checkFile
+from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
-from lib.parse.banner import BannerHandler
+
+
+class HeadersHandler(ContentHandler):
+ """
+ This class defines methods to parse and extract information from
+ the given HTTP header based upon the data in XML file
+ """
+
+ def __init__(self, header):
+ self.__header = sanitizeStr(header)
+
+ self.__regexp = None
+ self.__match = None
+ self.__techVersion = None
+
+
+ def __feedInfo(self, key, value):
+ value = sanitizeStr(value)
+
+ if value in ( None, "None" ):
+ return
+
+ if key == "techVersion":
+ kb.headersFp[key] = value
+ else:
+ if key not in kb.headersFp.keys():
+ kb.headersFp[key] = set()
+
+ kb.headersFp[key].add(value)
+
+
+ def startElement(self, name, attrs):
+ if name == "regexp":
+ self.__regexp = sanitizeStr(attrs.get("value"))
+ self.__match = re.search(self.__regexp, self.__header, re.I | re.M)
+
+ if name == "info" and self.__match:
+ self.__feedInfo("type", attrs.get("type"))
+ self.__feedInfo("distrib", attrs.get("distrib"))
+ self.__feedInfo("release", attrs.get("release"))
+ self.__feedInfo("codename", attrs.get("codename"))
+ self.__feedInfo("technology", attrs.get("codename"))
+
+ self.__techVersion = sanitizeStr(attrs.get("tech_version"))
+ self.__sp = sanitizeStr(attrs.get("sp"))
+
+ if self.__techVersion.isdigit():
+ self.__feedInfo("techVersion", self.__match.group(int(self.__techVersion)))
+
+ if self.__sp.isdigit():
+ self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
+
+ self.__regexp = None
+ self.__match = None
+ self.__techVersion = None
def headersParser(headers):
@@ -39,17 +97,23 @@ def headersParser(headers):
and the web application technology
"""
- topHeaders = (
- "cookie",
- "microsoftsharepointteamservices",
- "server",
- "servlet-engine",
- "www-authenticate",
- "x-aspnet-version",
- "x-powered-by",
- )
+ # TODO: ahead here
+ topHeaders = {
+ #"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ #"microsoftsharepointteamservices": "%s/microsoftsharepointteamservices.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ #"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ #"servlet-engine": "%s/servlet-engine.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ #"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ #"www-authenticate": "%s/www-authenticate.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ #"x-aspnet-version": "%s/x-aspnet-version.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ "x-powered-by": "%s/x-powered-by.xml" % paths.SQLMAP_XML_BANNER_PATH,
+ }
for header in headers:
- if header in topHeaders:
- # TODO: fill me
- pass
+ if header in topHeaders.keys():
+ value = headers[header]
+ xmlfile = topHeaders[header]
+ checkFile(xmlfile)
+ handler = HeadersHandler(value)
+ parse(xmlfile, handler)
+ parse(paths.GENERIC_XML, handler)
diff --git a/plugins/dbms/mssqlserver.py b/plugins/dbms/mssqlserver.py
index 9be2dab7c..32deb7cad 100644
--- a/plugins/dbms/mssqlserver.py
+++ b/plugins/dbms/mssqlserver.py
@@ -124,15 +124,13 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
- info = None
formatInfo = None
if self.banner:
- info = bannerParser(self.banner)
- formatInfo = formatOSfp(info)
+ formatInfo = formatOSfp()
- if formatInfo:
- value += "%s\n" % formatInfo
+ if formatInfo:
+ value += "%s\n" % formatInfo
value += "back-end DBMS: "
actVer = formatDBMSfp()
@@ -145,10 +143,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
formatInfo = None
value += "active fingerprint: %s" % actVer
- if info:
- release = info["dbmsRelease"]
- version = info["dbmsVersion"]
- servicepack = info["dbmsServicePack"]
+ if kb.bannerFp:
+ release = kb.bannerFp["dbmsRelease"]
+ version = kb.bannerFp["dbmsVersion"]
+ servicepack = kb.bannerFp["dbmsServicePack"]
if release and version and servicepack:
banVer = "Microsoft SQL Server %s " % release
@@ -169,8 +167,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
- if conf.getBanner:
- self.banner = inject.getValue("@@VERSION")
+ self.getPrematureBanner("@@VERSION")
if not conf.extensiveFp:
return True
@@ -197,8 +194,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
else:
setDbms("Microsoft SQL Server")
- if conf.getBanner:
- self.banner = inject.getValue("@@VERSION")
+ self.getPrematureBanner("@@VERSION")
return True
else:
diff --git a/plugins/dbms/mysql.py b/plugins/dbms/mysql.py
index 05752ef96..768f9f0d4 100644
--- a/plugins/dbms/mysql.py
+++ b/plugins/dbms/mysql.py
@@ -182,15 +182,13 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
- info = None
formatInfo = None
if self.banner:
- info = bannerParser(self.banner)
- formatInfo = formatOSfp(info)
+ formatInfo = formatOSfp()
- if formatInfo:
- value += "%s\n" % formatInfo
+ if formatInfo:
+ value += "%s\n" % formatInfo
value += "back-end DBMS: "
actVer = formatDBMSfp()
@@ -208,9 +206,9 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
comVer = formatDBMSfp([comVer])
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
- if info:
+ if kb.bannerFp:
# TODO: move to the XML banner file
- banVer = info['version']
+ banVer = kb.bannerFp['version']
if re.search("-log$", self.banner):
banVer += ", logging enabled"
@@ -241,8 +239,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
if int(kb.dbmsVersion[0]) >= 5:
self.has_information_schema = True
- if conf.getBanner:
- self.banner = inject.getValue("VERSION()")
+ self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
@@ -270,8 +267,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("MySQL 5")
self.has_information_schema = True
- if conf.getBanner:
- self.banner = inject.getValue("VERSION()")
+ self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
kb.dbmsVersion = [">= 5.0.0"]
@@ -318,8 +314,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("MySQL 4")
kb.dbmsVersion = ["< 5.0.0"]
- if conf.getBanner:
- self.banner = inject.getValue("VERSION()")
+ self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
diff --git a/plugins/dbms/oracle.py b/plugins/dbms/oracle.py
index b72ba78c4..4a78a19a4 100644
--- a/plugins/dbms/oracle.py
+++ b/plugins/dbms/oracle.py
@@ -118,15 +118,13 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
- info = None
formatInfo = None
if self.banner:
- info = bannerParser(self.banner)
- formatInfo = formatOSfp(info)
+ formatInfo = formatOSfp()
- if formatInfo:
- value += "%s\n" % formatInfo
+ if formatInfo:
+ value += "%s\n" % formatInfo
value += "back-end DBMS: "
@@ -139,8 +137,8 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
formatInfo = None
value += "active fingerprint: %s" % actVer
- if info:
- banVer = info['version']
+ if kb.bannerFp:
+ banVer = kb.bannerFp['version']
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
@@ -156,8 +154,7 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle")
- if conf.getBanner:
- self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
+ self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp:
return True
@@ -183,8 +180,7 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("Oracle")
- if conf.getBanner:
- self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
+ self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp:
return True
diff --git a/plugins/dbms/postgresql.py b/plugins/dbms/postgresql.py
index bc24774b0..0155ff0b9 100644
--- a/plugins/dbms/postgresql.py
+++ b/plugins/dbms/postgresql.py
@@ -118,15 +118,13 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
- info = None
formatInfo = None
if self.banner:
- info = bannerParser(self.banner)
- formatInfo = formatOSfp(info)
+ formatInfo = formatOSfp()
- if formatInfo:
- value += "%s\n" % formatInfo
+ if formatInfo:
+ value += "%s\n" % formatInfo
value += "back-end DBMS: "
@@ -139,8 +137,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
formatInfo = None
value += "active fingerprint: %s" % actVer
- if info:
- banVer = info['version']
+ if kb.bannerFp:
+ banVer = kb.bannerFp['version']
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
@@ -160,8 +158,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
if conf.dbms in PGSQL_ALIASES:
setDbms("PostgreSQL")
- if conf.getBanner:
- self.banner = inject.getValue("VERSION()")
+ self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
@@ -186,8 +183,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("PostgreSQL")
- if conf.getBanner:
- self.banner = inject.getValue("VERSION()")
+ self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py
index fe903e089..91f75756d 100644
--- a/plugins/generic/enumeration.py
+++ b/plugins/generic/enumeration.py
@@ -41,6 +41,7 @@ from lib.core.exception import sqlmapUndefinedMethod
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
+from lib.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
@@ -72,6 +73,13 @@ class Enumeration:
pass
+ def getPrematureBanner(self, query):
+ if conf.getBanner:
+ self.banner = inject.getValue(query)
+
+ bannerParser(self.banner)
+
+
def getBanner(self):
infoMsg = "fetching banner"
logger.info(infoMsg)
diff --git a/xml/banner/generic.xml b/xml/banner/generic.xml
index 4e06fc708..950d9715d 100644
--- a/xml/banner/generic.xml
+++ b/xml/banner/generic.xml
@@ -6,37 +6,26 @@
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
@@ -83,6 +72,7 @@
+
diff --git a/xml/banner/mysql.xml b/xml/banner/mysql.xml
index 1c21ec89c..1d806f963 100644
--- a/xml/banner/mysql.xml
+++ b/xml/banner/mysql.xml
@@ -6,11 +6,13 @@
+
+
@@ -36,6 +38,7 @@
+
diff --git a/xml/banner/postgresql.xml b/xml/banner/postgresql.xml
index 79cde445b..aad23bfee 100644
--- a/xml/banner/postgresql.xml
+++ b/xml/banner/postgresql.xml
@@ -6,6 +6,7 @@
+
diff --git a/xml/banner/x-powered-by.xml b/xml/banner/x-powered-by.xml
new file mode 100644
index 000000000..d6d5e6a69
--- /dev/null
+++ b/xml/banner/x-powered-by.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+