Major enhancement to the engine to parse XML files and matches on DBMS banner

and HTTP response headers.
Initial web application technology fingerprint (for the moment based only on
X-Powered-By HTTP response header and not shown yet to the user).
Minor layout adjustments.
This commit is contained in:
Bernardo Damele 2008-11-17 17:41:02 +00:00
parent 66fb3c3033
commit 7d0724843f
13 changed files with 222 additions and 133 deletions

View File

@ -130,7 +130,11 @@ def formatDBMSfp(versions=None):
return "%s %s" % (kb.dbms, " and ".join([version for version in versions])) 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 This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string. and return its values formatted as a human readable string.
@ -142,31 +146,40 @@ def formatOSfp(info):
infoStr = "" infoStr = ""
# Example of 'info' dictionary: # Examples of kb.bannerFp dictionary:
#
# { # {
# 'distrib': 'Ubuntu', # "distrib": set(["2000"]),
# 'release': '8.10', # "dbmsVersion": "8.00.194",
# 'codename': 'Intrepid', # "dbmsRelease": "2000",
# 'version': '5.0.67', # "dbmsServicePack": "0",
# 'type': 'Linux' # "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 return infoStr
elif info['type'] != "None": else:
infoStr += "back-end DBMS operating system: %s" % info['type'] infoStr += "back-end DBMS operating system: %s" % __formatOSfpString(kb.bannerFp["type"])
if 'distrib' in info and info['distrib'] != "None": if "distrib" in kb.bannerFp:
infoStr += " %s" % info['distrib'] infoStr += " %s" % __formatOSfpString(kb.bannerFp["distrib"])
if 'release' in info and info['release'] != "None": if "release" in kb.bannerFp:
infoStr += " %s" % info['release'] infoStr += " %s" % __formatOSfpString(kb.bannerFp["release"])
if 'sp' in info and info['sp'] != "None": if "sp" in kb.bannerFp:
infoStr += " %s" % info['sp'] infoStr += " %s" % __formatOSfpString(kb.bannerFp["sp"])
if 'codename' in info and info['codename'] != "None": if "codename" in kb.bannerFp:
infoStr += " (%s)" % info['codename'] infoStr += " (%s)" % __formatOSfpString(kb.bannerFp["codename"])
return infoStr return infoStr
@ -248,7 +261,7 @@ def getDirectories():
if kb.docRoot: if kb.docRoot:
directories.add(kb.docRoot) directories.add(kb.docRoot)
pagePath = re.search('^/(.*)/', conf.path) pagePath = re.search("^/(.*)/", conf.path)
if kb.docRoot and pagePath: if kb.docRoot and pagePath:
pagePath = pagePath.groups()[0] pagePath = pagePath.groups()[0]

View File

@ -453,6 +453,7 @@ def __setKnowledgeBaseAttributes():
kb.dbms = None kb.dbms = None
kb.dbmsDetected = False kb.dbmsDetected = False
kb.dbmsVersion = None kb.dbmsVersion = None
kb.bannerFp = {}
kb.headersFp = {} kb.headersFp = {}
kb.htmlFp = [] kb.htmlFp = []
kb.injParameter = None kb.injParameter = None

View File

@ -46,9 +46,22 @@ class BannerHandler(ContentHandler):
self.__regexp = None self.__regexp = None
self.__match = None self.__match = None
self.__position = 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): def startElement(self, name, attrs):
@ -57,22 +70,23 @@ class BannerHandler(ContentHandler):
self.__match = re.search(self.__regexp, self.__banner, re.I | re.M) self.__match = re.search(self.__regexp, self.__banner, re.I | re.M)
if name == "info" and self.__match: 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.__sp = sanitizeStr(attrs.get("sp"))
self.info['type'] = sanitizeStr(attrs.get("type")) if self.__version.isdigit():
self.info['distrib'] = sanitizeStr(attrs.get("distrib")) self.__feedInfo("version", self.__match.group(int(self.__version)))
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.__sp.isdigit(): 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.__regexp = None
self.__match = None self.__match = None
self.__position = None self.__version = None
class MSSQLBannerHandler(ContentHandler): class MSSQLBannerHandler(ContentHandler):
@ -90,7 +104,14 @@ class MSSQLBannerHandler(ContentHandler):
self.__version = "" self.__version = ""
self.__servicePack = "" 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): def startElement(self, name, attrs):
@ -114,9 +135,9 @@ class MSSQLBannerHandler(ContentHandler):
def endElement(self, name): def endElement(self, name):
if name == "signature": if name == "signature":
if re.search(" %s[\.\ ]+" % self.__version, self.__banner): if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
self.info['dbmsRelease'] = self.__release self.__feedInfo("dbmsRelease", self.__release)
self.info['dbmsVersion'] = self.__version self.__feedInfo("dbmsVersion", self.__version)
self.info['dbmsServicePack'] = self.__servicePack self.__feedInfo("dbmsServicePack", self.__servicePack)
self.__version = "" self.__version = ""
self.__servicePack = "" self.__servicePack = ""
@ -137,9 +158,6 @@ def bannerParser(banner):
DBMS banner based upon the data in XML file DBMS banner based upon the data in XML file
""" """
banner = sanitizeStr(banner)
info = {}
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
xmlfile = paths.MSSQL_XML xmlfile = paths.MSSQL_XML
elif kb.dbms == "MySQL": elif kb.dbms == "MySQL":
@ -154,24 +172,9 @@ def bannerParser(banner):
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
handler = MSSQLBannerHandler(banner) handler = MSSQLBannerHandler(banner)
parse(xmlfile, handler) parse(xmlfile, handler)
info = handler.info
handler = BannerHandler(banner) handler = BannerHandler(banner)
parse(paths.GENERIC_XML, handler) parse(paths.GENERIC_XML, handler)
for title, value in handler.info.items():
info[title] = value
else: else:
handler = BannerHandler(banner) handler = BannerHandler(banner)
parse(xmlfile, handler) parse(xmlfile, handler)
info = handler.info
if "type" not in info or info["type"] == "None":
parse(paths.GENERIC_XML, handler) 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

View File

@ -26,10 +26,68 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re import re
from xml.sax import parse
from xml.sax.handler import ContentHandler
from lib.core.common import checkFile from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import paths 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): def headersParser(headers):
@ -39,17 +97,23 @@ def headersParser(headers):
and the web application technology and the web application technology
""" """
topHeaders = ( # TODO: ahead here
"cookie", topHeaders = {
"microsoftsharepointteamservices", #"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
"server", #"microsoftsharepointteamservices": "%s/microsoftsharepointteamservices.xml" % paths.SQLMAP_XML_BANNER_PATH,
"servlet-engine", #"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
"www-authenticate", #"servlet-engine": "%s/servlet-engine.xml" % paths.SQLMAP_XML_BANNER_PATH,
"x-aspnet-version", #"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
"x-powered-by", #"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: for header in headers:
if header in topHeaders: if header in topHeaders.keys():
# TODO: fill me value = headers[header]
pass xmlfile = topHeaders[header]
checkFile(xmlfile)
handler = HeadersHandler(value)
parse(xmlfile, handler)
parse(paths.GENERIC_XML, handler)

View File

@ -124,12 +124,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self): def getFingerprint(self):
value = "" value = ""
info = None
formatInfo = None formatInfo = None
if self.banner: if self.banner:
info = bannerParser(self.banner) formatInfo = formatOSfp()
formatInfo = formatOSfp(info)
if formatInfo: if formatInfo:
value += "%s\n" % formatInfo value += "%s\n" % formatInfo
@ -145,10 +143,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
formatInfo = None formatInfo = None
value += "active fingerprint: %s" % actVer value += "active fingerprint: %s" % actVer
if info: if kb.bannerFp:
release = info["dbmsRelease"] release = kb.bannerFp["dbmsRelease"]
version = info["dbmsVersion"] version = kb.bannerFp["dbmsVersion"]
servicepack = info["dbmsServicePack"] servicepack = kb.bannerFp["dbmsServicePack"]
if release and version and servicepack: if release and version and servicepack:
banVer = "Microsoft SQL Server %s " % release 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(): if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0]) setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
if conf.getBanner: self.getPrematureBanner("@@VERSION")
self.banner = inject.getValue("@@VERSION")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
@ -197,8 +194,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
else: else:
setDbms("Microsoft SQL Server") setDbms("Microsoft SQL Server")
if conf.getBanner: self.getPrematureBanner("@@VERSION")
self.banner = inject.getValue("@@VERSION")
return True return True
else: else:

View File

@ -182,12 +182,10 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self): def getFingerprint(self):
value = "" value = ""
info = None
formatInfo = None formatInfo = None
if self.banner: if self.banner:
info = bannerParser(self.banner) formatInfo = formatOSfp()
formatInfo = formatOSfp(info)
if formatInfo: if formatInfo:
value += "%s\n" % formatInfo value += "%s\n" % formatInfo
@ -208,9 +206,9 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
comVer = formatDBMSfp([comVer]) comVer = formatDBMSfp([comVer])
value += "\n%scomment injection fingerprint: %s" % (blank, comVer) value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
if info: if kb.bannerFp:
# TODO: move to the XML banner file # TODO: move to the XML banner file
banVer = info['version'] banVer = kb.bannerFp['version']
if re.search("-log$", self.banner): if re.search("-log$", self.banner):
banVer += ", logging enabled" banVer += ", logging enabled"
@ -241,8 +239,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
if int(kb.dbmsVersion[0]) >= 5: if int(kb.dbmsVersion[0]) >= 5:
self.has_information_schema = True self.has_information_schema = True
if conf.getBanner: self.getPrematureBanner("VERSION()")
self.banner = inject.getValue("VERSION()")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
@ -270,8 +267,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("MySQL 5") setDbms("MySQL 5")
self.has_information_schema = True self.has_information_schema = True
if conf.getBanner: self.getPrematureBanner("VERSION()")
self.banner = inject.getValue("VERSION()")
if not conf.extensiveFp: if not conf.extensiveFp:
kb.dbmsVersion = [">= 5.0.0"] kb.dbmsVersion = [">= 5.0.0"]
@ -318,8 +314,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("MySQL 4") setDbms("MySQL 4")
kb.dbmsVersion = ["< 5.0.0"] kb.dbmsVersion = ["< 5.0.0"]
if conf.getBanner: self.getPrematureBanner("VERSION()")
self.banner = inject.getValue("VERSION()")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True

View File

@ -118,12 +118,10 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self): def getFingerprint(self):
value = "" value = ""
info = None
formatInfo = None formatInfo = None
if self.banner: if self.banner:
info = bannerParser(self.banner) formatInfo = formatOSfp()
formatInfo = formatOSfp(info)
if formatInfo: if formatInfo:
value += "%s\n" % formatInfo value += "%s\n" % formatInfo
@ -139,8 +137,8 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
formatInfo = None formatInfo = None
value += "active fingerprint: %s" % actVer value += "active fingerprint: %s" % actVer
if info: if kb.bannerFp:
banVer = info['version'] banVer = kb.bannerFp['version']
banVer = formatDBMSfp([banVer]) banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, 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: if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle") setDbms("Oracle")
if conf.getBanner: self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
@ -183,8 +180,7 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("Oracle") setDbms("Oracle")
if conf.getBanner: self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True

View File

@ -118,12 +118,10 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self): def getFingerprint(self):
value = "" value = ""
info = None
formatInfo = None formatInfo = None
if self.banner: if self.banner:
info = bannerParser(self.banner) formatInfo = formatOSfp()
formatInfo = formatOSfp(info)
if formatInfo: if formatInfo:
value += "%s\n" % formatInfo value += "%s\n" % formatInfo
@ -139,8 +137,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
formatInfo = None formatInfo = None
value += "active fingerprint: %s" % actVer value += "active fingerprint: %s" % actVer
if info: if kb.bannerFp:
banVer = info['version'] banVer = kb.bannerFp['version']
banVer = formatDBMSfp([banVer]) banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, 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: if conf.dbms in PGSQL_ALIASES:
setDbms("PostgreSQL") setDbms("PostgreSQL")
if conf.getBanner: self.getPrematureBanner("VERSION()")
self.banner = inject.getValue("VERSION()")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True
@ -186,8 +183,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("PostgreSQL") setDbms("PostgreSQL")
if conf.getBanner: self.getPrematureBanner("VERSION()")
self.banner = inject.getValue("VERSION()")
if not conf.extensiveFp: if not conf.extensiveFp:
return True return True

View File

@ -41,6 +41,7 @@ from lib.core.exception import sqlmapUndefinedMethod
from lib.core.exception import sqlmapUnsupportedFeatureException from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject from lib.request import inject
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
@ -72,6 +73,13 @@ class Enumeration:
pass pass
def getPrematureBanner(self, query):
if conf.getBanner:
self.banner = inject.getValue(query)
bannerParser(self.banner)
def getBanner(self): def getBanner(self):
infoMsg = "fetching banner" infoMsg = "fetching banner"
logger.info(infoMsg) logger.info(infoMsg)

View File

@ -6,37 +6,26 @@
<info type="Windows"/> <info type="Windows"/>
</regexp> </regexp>
<regexp value="Microsoft.*7\.0"> <regexp value="Service Pack (\d)">
<info type="Windows" distrib="Vista"/> <info sp="1"/>
</regexp> </regexp>
<regexp value="Microsoft.*7\.0.*Service Pack (\d)"> <regexp value="Microsoft.*7\.0">
<info type="Windows" distrib="Vista" sp="1"/> <info type="Windows" distrib="Vista"/>
</regexp> </regexp>
<regexp value="Microsoft.*6\.0"> <regexp value="Microsoft.*6\.0">
<info type="Windows" distrib="2003"/> <info type="Windows" distrib="2003"/>
</regexp> </regexp>
<regexp value="Microsoft.*6\.0.*Service Pack (\d)">
<info type="Windows" distrib="2003" sp="1"/>
</regexp>
<regexp value="Microsoft.*5\.1"> <regexp value="Microsoft.*5\.1">
<info type="Windows" distrib="XP"/> <info type="Windows" distrib="XP"/>
</regexp> </regexp>
<regexp value="Microsoft.*5\.1.*Service Pack (\d)">
<info type="Windows" distrib="XP" sp="1"/>
</regexp>
<regexp value="Microsoft.*5\.0"> <regexp value="Microsoft.*5\.0">
<info type="Windows" distrib="2000"/> <info type="Windows" distrib="2000"/>
</regexp> </regexp>
<regexp value="Microsoft.*5\.0.*Service Pack (\d)">
<info type="Windows" distrib="2000" sp="1"/>
</regexp>
<!-- Linux --> <!-- Linux -->
<regexp value="Linux"> <regexp value="Linux">
@ -83,6 +72,7 @@
<info type="Linux" distrib="Ubuntu"/> <info type="Linux" distrib="Ubuntu"/>
</regexp> </regexp>
<!-- Unices --> <!-- Unices -->
<regexp value="FreeBSD"> <regexp value="FreeBSD">
<info type="FreeBSD"/> <info type="FreeBSD"/>

View File

@ -6,11 +6,13 @@
<info version="1"/> <info version="1"/>
</regexp> </regexp>
<!-- Windows --> <!-- Windows -->
<regexp value="^([\d\.\-]+)[\-\_\ ].*nt$"> <regexp value="^([\d\.\-]+)[\-\_\ ].*nt$">
<info version="1" type="Windows"/> <info version="1" type="Windows"/>
</regexp> </regexp>
<!-- Debian --> <!-- Debian -->
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+potato"> <regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+potato">
<info version="1" type="Linux" distrib="Debian" release="2.1" codename="Potato"/> <info version="1" type="Linux" distrib="Debian" release="2.1" codename="Potato"/>
@ -36,6 +38,7 @@
<info version="1" type="Linux" distrib="Debian" codename="Testing"/> <info version="1" type="Linux" distrib="Debian" codename="Testing"/>
</regexp> </regexp>
<!-- Ubuntu --> <!-- Ubuntu -->
<regexp value="(5\.0\.67)-0ubuntu6"> <regexp value="(5\.0\.67)-0ubuntu6">
<info version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/> <info version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/>

View File

@ -6,6 +6,7 @@
<info version="1"/> <info version="1"/>
</regexp> </regexp>
<!-- Ubuntu --> <!-- Ubuntu -->
<regexp value="PostgreSQL\s+(8\.2\.7)\s+on\s+.*?\s+\(Ubuntu 4\.2\.3-2ubuntu4\)"> <regexp value="PostgreSQL\s+(8\.2\.7)\s+on\s+.*?\s+\(Ubuntu 4\.2\.3-2ubuntu4\)">
<info version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/> <info version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<regexp value="PHP[\-\_\/\ ]([\d\.]+)">
<info technology="PHP" tech_version="1"/>
</regexp>
<regexp value="JSP[\-\_\/\ ]([\d\.]+)">
<info technology="JSP" tech_version="1"/>
</regexp>
<regexp value="ASP">
<info technology="ASP" type="Windows" distrib="2000|XP|2003|2008|Vista"/>
</regexp>
<regexp value="ASP\.NET">
<info technology="ASP.NET" type="Windows" distrib="2000|XP|2003|2008|Vista"/>
</regexp>
<regexp value="(JBoss|Servlet|Tomcat)[\-\_\/\ ]([\d\.]+)">
<info technology="Tomcat" tech_version="2"/>
</regexp>
</root>