Minor enhancement to fingerprint the web server operating system and

the web application technology by parsing also HTTP response Server
header.
Refactor libraries and plugins that parses XML to fingerprint and show
on standard output the information.
Updated changelog.
This commit is contained in:
Bernardo Damele 2008-11-18 17:42:46 +00:00
parent 7d0724843f
commit 727664aea7
15 changed files with 588 additions and 207 deletions

View File

@ -1,11 +1,14 @@
sqlmap (0.6.3-1) stable; urgency=low
* Major bug fix to correctly handle httplib.BadStatusLine exception;
* Minor enhancement to support stacked queries which will be used
sometimes by takeover functionality and time based blind SQL injection
technique;
* Major enhancement to support stacked queries when the web application
supports it which will be used in the long run by takeover
functionality;
* Minor enhancement to test if the injectable parameter is affected by
a time based blind SQL injection technique;
* Minor enhancement to fingerprint the web server operating system and
the web application technology by parsing some HTTP response headers;
* Minor enhancement to fingerprint the back-end DBMS operating system by
parsing the DBMS banner value when both -f and -b are provided;
parsing the DBMS banner value when -b option is provided;
* Minor enhancement to be able to specify the number of seconds to wait
between each HTTP request providing option --delay #;
* Minor enhancement to be able to enumerate table columns and dump table
@ -16,6 +19,7 @@ sqlmap (0.6.3-1) stable; urgency=low
HTTP headers (Accept, Accept-Encoding, etc);
* Minor improvements to sqlmap Debian package files: sqlmap uploaded
to official Debian project repository;
* Major bug fix to correctly handle httplib.BadStatusLine exception;
* Minor bug fix to handle session.error and session.timeout in HTTP
requests;
* Minor bug fix so that when the user provide a SELECT statement to be

View File

@ -130,15 +130,34 @@ def formatDBMSfp(versions=None):
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
def __formatOSfpString(values):
return " or ".join([v for v in values])
def __formatFingerprintString(values, chain="or"):
string = "|".join([v for v in values])
return string.replace("|", " %s " % chain)
def formatOSfp():
def formatFingerprint(target, info):
"""
This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string.
Examples of info dictionary:
{
"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"])
}
@return: detected back-end operating system based upon fingerprint
techniques.
@rtype: C{str}
@ -146,40 +165,25 @@ def formatOSfp():
infoStr = ""
# Examples of kb.bannerFp dictionary:
#
# {
# "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 kb.bannerFp or "type" not in kb.bannerFp:
if not info or "type" not in info:
return infoStr
else:
infoStr += "back-end DBMS operating system: %s" % __formatOSfpString(kb.bannerFp["type"])
infoStr += "%s operating system: %s" % (target, __formatFingerprintString(info["type"]))
if "distrib" in kb.bannerFp:
infoStr += " %s" % __formatOSfpString(kb.bannerFp["distrib"])
if "distrib" in info:
infoStr += " %s" % __formatFingerprintString(info["distrib"])
if "release" in kb.bannerFp:
infoStr += " %s" % __formatOSfpString(kb.bannerFp["release"])
if "release" in info:
infoStr += " %s" % __formatFingerprintString(info["release"])
if "sp" in kb.bannerFp:
infoStr += " %s" % __formatOSfpString(kb.bannerFp["sp"])
if "sp" in info:
infoStr += " %s" % __formatFingerprintString(info["sp"])
if "codename" in kb.bannerFp:
infoStr += " (%s)" % __formatOSfpString(kb.bannerFp["codename"])
if "codename" in info:
infoStr += " (%s)" % __formatFingerprintString(info["codename"])
if "technology" in info:
infoStr += "\nweb application technology: %s" % __formatFingerprintString(info["technology"], "and")
return infoStr

View File

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

View File

@ -33,60 +33,7 @@ from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
class BannerHandler(ContentHandler):
"""
This class defines methods to parse and extract information from
the given DBMS banner based upon the data in XML file
"""
def __init__(self, banner):
self.__banner = sanitizeStr(banner)
self.__regexp = None
self.__match = None
self.__version = None
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):
if name == "regexp":
self.__regexp = sanitizeStr(attrs.get("value"))
self.__match = re.search(self.__regexp, self.__banner, 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.__version = sanitizeStr(attrs.get("version"))
self.__sp = sanitizeStr(attrs.get("sp"))
if self.__version.isdigit():
self.__feedInfo("version", self.__match.group(int(self.__version)))
if self.__sp.isdigit():
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
self.__regexp = None
self.__match = None
self.__version = None
from lib.parse.handler import FingerprintHandler
class MSSQLBannerHandler(ContentHandler):
@ -172,9 +119,10 @@ def bannerParser(banner):
if kb.dbms == "Microsoft SQL Server":
handler = MSSQLBannerHandler(banner)
parse(xmlfile, handler)
handler = BannerHandler(banner)
handler = FingerprintHandler(banner, kb.bannerFp)
parse(paths.GENERIC_XML, handler)
else:
handler = BannerHandler(banner)
handler = FingerprintHandler(banner, kb.bannerFp)
parse(xmlfile, handler)
parse(paths.GENERIC_XML, handler)

95
lib/parse/handler.py Normal file
View File

@ -0,0 +1,95 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import re
from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr
from lib.core.data import kb
class FingerprintHandler(ContentHandler):
"""
This class defines methods to parse and extract information from
the given DBMS banner based upon the data in XML file
"""
def __init__(self, banner, info):
self.__banner = sanitizeStr(banner)
self.__regexp = None
self.__match = None
self.__dbmsVersion = None
self.__techVersion = None
self.__info = info
def __feedInfo(self, key, value):
value = sanitizeStr(value)
if value in ( None, "None" ):
return
if key in ( "dbmsVersion" ):
self.__info[key] = value
else:
if key not in self.__info.keys():
self.__info[key] = set()
self.__info[key].add(value)
def startElement(self, name, attrs):
if name == "regexp":
self.__regexp = sanitizeStr(attrs.get("value"))
self.__match = re.search(self.__regexp, self.__banner, 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.__dbmsVersion = sanitizeStr(attrs.get("dbms_version"))
self.__techVersion = sanitizeStr(attrs.get("tech_version"))
self.__sp = sanitizeStr(attrs.get("sp"))
if self.__dbmsVersion.isdigit():
self.__feedInfo("dbmsVersion", self.__match.group(int(self.__dbmsVersion)))
if self.__techVersion.isdigit():
self.__feedInfo("technology", "%s %s" % (attrs.get("technology"), self.__match.group(int(self.__techVersion))))
else:
self.__feedInfo("technology", attrs.get("technology"))
if self.__sp.isdigit():
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
self.__regexp = None
self.__match = None
self.__dbmsVersion = None
self.__techVersion = None

View File

@ -27,67 +27,11 @@ 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
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
from lib.parse.handler import FingerprintHandler
def headersParser(headers):
@ -97,11 +41,16 @@ def headersParser(headers):
and the web application technology
"""
if kb.headersCount > 3:
return
kb.headersCount += 1
# 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,
"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,
@ -114,6 +63,6 @@ def headersParser(headers):
value = headers[header]
xmlfile = topHeaders[header]
checkFile(xmlfile)
handler = HeadersHandler(value)
handler = FingerprintHandler(value, kb.headersFp)
parse(xmlfile, handler)
parse(paths.GENERIC_XML, handler)

View File

@ -29,7 +29,7 @@ import time
from lib.core.agent import agent
from lib.core.common import dataToStdout
from lib.core.common import formatDBMSfp
from lib.core.common import formatOSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.common import readInput
@ -43,7 +43,6 @@ from lib.core.session import setDbms
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MSSQL_SYSTEM_DBS
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
@ -123,14 +122,17 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
formatInfo = None
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
formatInfo = formatOSfp()
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if formatInfo:
value += "%s\n" % formatInfo
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
@ -140,7 +142,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
return value
blank = " " * 15
formatInfo = None
value += "active fingerprint: %s" % actVer
if kb.bannerFp:

View File

@ -29,7 +29,7 @@ import re
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatDBMSfp
from lib.core.common import formatOSfp
from lib.core.common import formatFingerprint
from lib.core.common import getDirectories
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
@ -44,7 +44,6 @@ from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import MYSQL_SYSTEM_DBS
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
@ -181,14 +180,17 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
formatInfo = None
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
formatInfo = formatOSfp()
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if formatInfo:
value += "%s\n" % formatInfo
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
@ -199,7 +201,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
comVer = self.__commentCheck()
blank = " " * 15
formatInfo = None
value += "active fingerprint: %s" % actVer
if comVer:
@ -208,7 +209,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
if kb.bannerFp:
# TODO: move to the XML banner file
banVer = kb.bannerFp['version']
banVer = kb.bannerFp["dbmsVersion"]
if re.search("-log$", self.banner):
banVer += ", logging enabled"

View File

@ -27,7 +27,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
from lib.core.common import formatDBMSfp
from lib.core.common import formatOSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.data import conf
from lib.core.data import kb
@ -37,7 +37,6 @@ from lib.core.session import setDbms
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import ORACLE_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from plugins.generic.enumeration import Enumeration
@ -117,14 +116,17 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
formatInfo = None
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
formatInfo = formatOSfp()
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if formatInfo:
value += "%s\n" % formatInfo
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
@ -134,11 +136,10 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
actVer = formatDBMSfp()
blank = " " * 15
formatInfo = None
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp['version']
banVer = kb.bannerFp["dbmsVersion"]
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)

View File

@ -27,7 +27,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
from lib.core.common import formatDBMSfp
from lib.core.common import formatOSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.data import conf
@ -38,7 +38,6 @@ from lib.core.session import setDbms
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import PGSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from plugins.generic.enumeration import Enumeration
@ -117,14 +116,17 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
value = ""
formatInfo = None
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
formatInfo = formatOSfp()
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if formatInfo:
value += "%s\n" % formatInfo
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
@ -134,11 +136,10 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
actVer = formatDBMSfp()
blank = " " * 15
formatInfo = None
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp['version']
banVer = kb.bannerFp["dbmsVersion"]
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)

View File

@ -26,12 +26,27 @@
<info type="Windows" distrib="2000"/>
</regexp>
<regexp value="Microsoft.*4\.0">
<info type="Windows" distrib="NT 4.0"/>
</regexp>
<regexp value="Microsoft.*3\.0">
<info type="Windows" distrib="NT 4.0"/>
</regexp>
<regexp value="Microsoft.*2\.0">
<info type="Windows" distrib="NT 4.0"/>
</regexp>
<!-- Linux -->
<regexp value="Linux">
<info type="Linux"/>
</regexp>
<regexp value="CentOS">
<info type="Linux" distrib="CentOS"/>
</regexp>
<regexp value="Cobalt">
<info type="Linux" distrib="Cobalt"/>
</regexp>
@ -61,7 +76,7 @@
</regexp>
<regexp value="Red[\-\_\ ]*Hat">
<info type="Linux" distrib="RedHat"/>
<info type="Linux" distrib="Red Hat"/>
</regexp>
<regexp value="SuSE">
@ -72,7 +87,6 @@
<info type="Linux" distrib="Ubuntu"/>
</regexp>
<!-- Unices -->
<regexp value="FreeBSD">
<info type="FreeBSD"/>

View File

@ -1,46 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- Generic -->
<regexp value="^([\d\.\-]+)[\-\_\ ].*">
<info version="1"/>
<info dbms_version="1"/>
</regexp>
<!-- Windows -->
<regexp value="^([\d\.\-]+)[\-\_\ ].*nt$">
<info version="1" type="Windows"/>
<info dbms_version="1" type="Windows"/>
</regexp>
<!-- Debian -->
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+potato">
<info version="1" type="Linux" distrib="Debian" release="2.1" codename="Potato"/>
<info dbms_version="1" type="Linux" distrib="Debian" release="2.1" codename="Potato"/>
</regexp>
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+woody">
<info version="1" type="Linux" distrib="Debian" release="3.0" codename="Woody"/>
<info dbms_version="1" type="Linux" distrib="Debian" release="3.0" codename="Woody"/>
</regexp>
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+sarge">
<info version="1" type="Linux" distrib="Debian" release="3.1" codename="Sarge"/>
<info dbms_version="1" type="Linux" distrib="Debian" release="3.1" codename="Sarge"/>
</regexp>
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+etch">
<info version="1" type="Linux" distrib="Debian" release="4.0" codename="Etch"/>
<info dbms_version="1" type="Linux" distrib="Debian" release="4.0" codename="Etch"/>
</regexp>
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+(sid|unstable)">
<info version="1" type="Linux" distrib="Debian" codename="Unstable"/>
<info dbms_version="1" type="Linux" distrib="Debian" codename="Unstable"/>
</regexp>
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+testing">
<info version="1" type="Linux" distrib="Debian" codename="Testing"/>
<info dbms_version="1" type="Linux" distrib="Debian" codename="Testing"/>
</regexp>
<!-- Ubuntu -->
<regexp value="(5\.0\.67)-0ubuntu6">
<info version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/>
<info dbms_version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/>
</regexp>
</root>

View File

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- Generic -->
<regexp value="^Oracle\s+.*Release\s+([\d\.]+)\s+">
<info version="1"/>
<info dbms_version="1"/>
</regexp>
</root>

View File

@ -1,14 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- Generic -->
<regexp value="PostgreSQL\s+([\w\.]+)">
<info version="1"/>
<info dbms_version="1"/>
</regexp>
<!-- Ubuntu -->
<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 dbms_version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid"/>
</regexp>
</root>

369
xml/banner/server.xml Normal file
View File

@ -0,0 +1,369 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- Apache -->
<regexp value="Apache$">
<info technology="Apache"/>
</regexp>
<regexp value="Apache/([\w\.]+)">
<info technology="Apache" tech_version="1"/>
</regexp>
<regexp value="Apache[\-\_\ ]AdvancedExtranetServer/([\w\.]+)">
<info technology="Apache" tech_version="1"/>
</regexp>
<!-- Apache: CentOS -->
<!-- TODO: add Centos 4.6, 4.7, 5.1 and 5.2 -->
<regexp value="Apache/2.0.46 \(CentOS\)">
<info type="Linux" distrib="CentOS" elease="3.7"/>
</regexp>
<regexp value="Apache/2.0.52 \(CentOS\)">
<info type="Linux" distrib="CentOS" release="4.3 or 4.4"/>
</regexp>
<regexp value="Apache/2.0.46 \(CentOS\)">
<info type="Linux" distrib="CentOS" release="5"/>
</regexp>
<!-- Apache: Fedora -->
<!-- TODO: add Fedora 8, 9 and 10 -->
<regexp value="Apache/2.0.47 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="1"/>
</regexp>
<regexp value="Apache/2.0.50 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="1" updated="True"/>
</regexp>
<regexp value="Apache/2.0.49 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="2"/>
</regexp>
<regexp value="Apache/2.0.51 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="2" updated="True"/>
</regexp>
<regexp value="Apache/2.0.52 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="3"/>
</regexp>
<regexp value="Apache/2.0.53 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="3" updated="True"/>
</regexp>
<regexp value="Apache/2.0.54 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="4"/>
</regexp>
<regexp value="Apache/2.2.0 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="5"/>
</regexp>
<regexp value="Apache/2.2.2 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="5" updated="True"/>
</regexp>
<regexp value="Apache/2.2.3 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="6"/>
</regexp>
<regexp value="Apache/2.2.4 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="7"/>
</regexp>
<regexp value="Apache/2.2.6 \(Fedora\)">
<info type="Linux" distrib="Fedora" release="6 or 7" updated="True"/>
</regexp>
<!-- Apache: Red Hat -->
<!-- TODO: add Red Hat 5, 5.1, 5.2 and 5.3 -->
<regexp value="Apache/1.2.6 Red Hat">
<info type="Linux" distrib="Red Hat" release="5.1"/>
</regexp>
<regexp value="Apache/1.3.3 \(Unix\)\s+\(Red Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="5.2"/>
</regexp>
<regexp value="Apache/1.3.6 \(Unix\)\s+\(Red Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="6.0"/>
</regexp>
<regexp value="Apache/1.3.9 \(Unix\) \(Red Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="6.1"/>
</regexp>
<regexp value="Apache/1.3.12 \(Unix\) \(Red Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="7.0"/>
</regexp>
<regexp value="Apache/1.3.19 \(Unix\) \(Red-Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="7.1"/>
</regexp>
<regexp value="Apache/1.3.20 \(Unix\) \(Red-Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="7.2"/>
</regexp>
<regexp value="Apache/1.3.23 \(Unix\) \(Red-Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="7.3"/>
</regexp>
<regexp value="Apache/1.3.27 \(Unix\) \(Red-Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="7.1 or 7.2 or 7.3" updated="True"/>
</regexp>
<regexp value="Apache/2.0.40 \(Red Hat Linux\)">
<info type="Linux" distrib="Red Hat" release="8.0 or 9"/>
</regexp>
<regexp value="Apache/1.3.22 \(Unix\) \(Red-Hat/Linux\)">
<info type="Linux" distrib="Red Hat" release="Enterprise 2.1"/>
</regexp>
<regexp value="Apache/2.0.46 \(Red Hat\)">
<info type="Linux" distrib="Red Hat" release="Enterprise 3"/>
</regexp>
<regexp value="Apache/2.0.52 \(Red Hat\)">
<info type="Linux" distrib="Red Hat" release="Enterprise 4"/>
</regexp>
<!-- Apache: Debian -->
<!-- TODO: add Debian testing, unstable and experimental -->
<regexp value="Apache/1.0.5 \(Unix\) Debian/GNU">
<info type="Linux" distrib="Debian" release="1.1"/>
</regexp>
<regexp value="Apache/1.1.1 \(Unix\) Debian/GNU">
<info type="Linux" distrib="Debian" release="1.2"/>
</regexp>
<regexp value="Apache/1.1.3 \(Unix\) Debian/GNU">
<info type="Linux" distrib="Debian" release="1.3"/>
</regexp>
<regexp value="Apache/1.3.0 \(Unix\) Debian/GNU">
<info type="Linux" distrib="Debian" release="2.0"/>
</regexp>
<regexp value="Apache/1.3.3 \(Unix\) Debian/GNU">
<info type="Linux" distrib="Debian" release="2.1"/>
</regexp>
<regexp value="Apache/1.3.9 \(Unix\) Debian\/GNU">
<info type="Linux" distrib="Debian" release="2.2"/>
</regexp>
<regexp value="Apache/1.3.26 \(Debian GNU\/Linux\)">
<info type="Linux" distrib="Debian" release="3.0"/>
</regexp>
<regexp value="Apache/1.3.33 \(Debian GNU\/Linux\)">
<info type="Linux" distrib="Debian" release="3.1"/>
</regexp>
<regexp value="Apache/2.0.54 \(Debian GNU\/Linux\)">
<info type="Linux" distrib="Debian" release="3.1"/>
</regexp>
<regexp value="Apache/2.2.3 \(Debian\)">
<info type="Linux" distrib="Debian" release="4.0"/>
</regexp>
<regexp value="Apache/2.2.6 \(Debian\)">
<info type="Linux" distrib="Debian" release="4.0" updated="True"/>
</regexp>
<!-- Apache: Ubuntu -->
<regexp value="Apache/2.0.50 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="4.10"/>
</regexp>
<regexp value="Apache/2.0.53 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="5.04"/>
</regexp>
<regexp value="Apache/2.0.54 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="5.10"/>
</regexp>
<regexp value="Apache/2.0.55 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="6.06 or 6.10"/>
</regexp>
<regexp value="Apache/2.2.3 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="7.04"/>
</regexp>
<regexp value="Apache/2.2.4 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="7.10"/>
</regexp>
<regexp value="Apache/2.2.8 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="8.04"/>
</regexp>
<regexp value="Apache/2.2.9 \(Ubuntu\)">
<info type="Linux" distrib="Ubuntu" release="8.10"/>
</regexp>
<!-- Apache: Mandrake / Mandriva -->
<!-- TODO: add Mandriva 2007.1, 2008.0, 2008.1 and 2009.0 -->
<regexp value="Apache/1.3.6 \(Unix\)\s+\(Mandrake/Linux\)">
<info type="Linux" distrib="Mandrake" release="6.0"/>
</regexp>
<regexp value="Apache/1.3.9 \(Unix\)\s+\(NetRevolution Advanced Server/Linux-Mandrake\)">
<info type="Linux" distrib="Mandrake" release="6.1 or 7.0"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.12 \(NetRevolution/Linux-Mandrake\)">
<info type="Linux" distrib="Mandrake" release="7.1"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.14 \(Linux-Mandrake/">
<info type="Linux" distrib="Mandrake" release="7.2"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.19 \(Linux-Mandrake/">
<info type="Linux" distrib="Mandrake" release="8.0"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.20 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="8.1"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.23 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="8.2"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.26 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="9.0"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.27 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="9.1"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/2.0.44 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="9.1"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.28 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="9.2"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/2.0.47 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="9.1 or 9.2"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.29 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="10.0"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/2.0.48 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="10.0"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/1.3.31 \(Linux-Mandrake/">
<info type="Linux" distrib="Mandrake" release="10.1"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/2.0.50 \(Mandrake Linux/">
<info type="Linux" distrib="Mandrake" release="10.0 or 10.1"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/2.0.53 \(Mandriva Linux/">
<info type="Linux" distrib="Mandrake" release="10.2"/>
</regexp>
<regexp value="Apache-AdvancedExtranetServer/2.0.54 \(Mandriva Linux/">
<info type="Linux" distrib="Mandrake" release="2006.0"/>
</regexp>
<regexp value="Apache/2.2.3 \(Mandriva Linux/">
<info type="Linux" distrib="Mandrake" release="2007"/>
</regexp>
<!-- Apache: SuSE -->
<!-- TODO: add SuSE 10.1, 10.2, 10.3 and 11.0 -->
<regexp value="Apache/1.3.6 \(Unix\) \(SuSE/Linux\)">
<info type="Linux" distrib="SuSE" release="6.1"/>
</regexp>
<regexp value="Apache/1.3.9 \(Unix\) \(SuSE/Linux\)">
<info type="Linux" distrib="SuSE" release="6.2"/>
</regexp>
<regexp value="Apache/1.3.12 \(Unix\) \(SuSE/Linux\)">
<info technology="operating-system.type" type="str" value="Linux"/>
<info type="Linux" distrib="SuSE" release="6.4 or 7.0"/>
</regexp>
<regexp value="Apache/1.3.17 \(Unix\) \(SuSE/Linux\)">
<info type="Linux" distrib="SuSE" release="7.1"/>
</regexp>
<regexp value="Apache/1.3.19 \(Unix\) \(SuSE/Linux\)">
<info type="Linux" distrib="SuSE" release="7.2"/>
</regexp>
<regexp value="Apache/1.3.20 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="7.3"/>
</regexp>
<regexp value="Apache/1.3.23 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="8.0"/>
</regexp>
<regexp value="Apache/1.3.26 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="8.1"/>
</regexp>
<regexp value="Apache/1.3.27 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="8.2"/>
</regexp>
<regexp value="Apache/1.3.28 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="9.0"/>
</regexp>
<regexp value="Apache/2.0.40 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="8.1"/>
</regexp>
<regexp value="Apache/2.0.44 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="8.2"/>
</regexp>
<regexp value="Apache/2.0.47 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="9.0"/>
</regexp>
<regexp value="Apache/2.0.49 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="9.1"/>
</regexp>
<regexp value="Apache/2.0.50 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="9.2"/>
</regexp>
<regexp value="Apache/2.0.53 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="9.3"/>
</regexp>
<regexp value="Apache/2.0.54 \(Linux/SuSE\)">
<info type="Linux" distrib="SuSE" release="10.0"/>
</regexp>
</root>