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

Skip to content

Commit 727664a

Browse files
committed
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.
1 parent 7d07248 commit 727664a

15 files changed

Lines changed: 588 additions & 207 deletions

File tree

doc/ChangeLog

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
sqlmap (0.6.3-1) stable; urgency=low
22

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

lib/core/common.py

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -130,56 +130,60 @@ def formatDBMSfp(versions=None):
130130
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
131131

132132

133-
def __formatOSfpString(values):
134-
return " or ".join([v for v in values])
133+
def __formatFingerprintString(values, chain="or"):
134+
string = "|".join([v for v in values])
135+
return string.replace("|", " %s " % chain)
135136

136137

137-
def formatOSfp():
138+
def formatFingerprint(target, info):
138139
"""
139140
This function format the back-end operating system fingerprint value
140141
and return its values formatted as a human readable string.
141142
143+
Examples of info dictionary:
144+
145+
{
146+
"distrib": set(["2000"]),
147+
"dbmsVersion": "8.00.194",
148+
"dbmsRelease": "2000",
149+
"dbmsServicePack": "0",
150+
"type": set(["Windows"])
151+
}
152+
153+
{
154+
"distrib": set(["Ubuntu"]),
155+
"release": set(["8.10"]),
156+
"codename": set(["Intrepid"]),
157+
"version": "5.0.67",
158+
"type": set(["Linux"])
159+
}
160+
142161
@return: detected back-end operating system based upon fingerprint
143162
techniques.
144163
@rtype: C{str}
145164
"""
146165

147166
infoStr = ""
148167

149-
# Examples of kb.bannerFp dictionary:
150-
#
151-
# {
152-
# "distrib": set(["2000"]),
153-
# "dbmsVersion": "8.00.194",
154-
# "dbmsRelease": "2000",
155-
# "dbmsServicePack": "0",
156-
# "type": set(["Windows"])
157-
# }
158-
#
159-
# {
160-
# "distrib": set(["Ubuntu"]),
161-
# "release": set(["8.10"]),
162-
# "codename": set(["Intrepid"]),
163-
# "version": "5.0.67",
164-
# "type": set(["Linux"])
165-
# }
166-
167-
if not kb.bannerFp or "type" not in kb.bannerFp:
168+
if not info or "type" not in info:
168169
return infoStr
169170
else:
170-
infoStr += "back-end DBMS operating system: %s" % __formatOSfpString(kb.bannerFp["type"])
171+
infoStr += "%s operating system: %s" % (target, __formatFingerprintString(info["type"]))
172+
173+
if "distrib" in info:
174+
infoStr += " %s" % __formatFingerprintString(info["distrib"])
171175

172-
if "distrib" in kb.bannerFp:
173-
infoStr += " %s" % __formatOSfpString(kb.bannerFp["distrib"])
176+
if "release" in info:
177+
infoStr += " %s" % __formatFingerprintString(info["release"])
174178

175-
if "release" in kb.bannerFp:
176-
infoStr += " %s" % __formatOSfpString(kb.bannerFp["release"])
179+
if "sp" in info:
180+
infoStr += " %s" % __formatFingerprintString(info["sp"])
177181

178-
if "sp" in kb.bannerFp:
179-
infoStr += " %s" % __formatOSfpString(kb.bannerFp["sp"])
182+
if "codename" in info:
183+
infoStr += " (%s)" % __formatFingerprintString(info["codename"])
180184

181-
if "codename" in kb.bannerFp:
182-
infoStr += " (%s)" % __formatOSfpString(kb.bannerFp["codename"])
185+
if "technology" in info:
186+
infoStr += "\nweb application technology: %s" % __formatFingerprintString(info["technology"], "and")
183187

184188
return infoStr
185189

lib/core/option.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ def __setKnowledgeBaseAttributes():
454454
kb.dbmsDetected = False
455455
kb.dbmsVersion = None
456456
kb.bannerFp = {}
457+
kb.headersCount = 0
457458
kb.headersFp = {}
458459
kb.htmlFp = []
459460
kb.injParameter = None

lib/parse/banner.py

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -33,60 +33,7 @@
3333
from lib.core.common import sanitizeStr
3434
from lib.core.data import kb
3535
from lib.core.data import paths
36-
37-
38-
class BannerHandler(ContentHandler):
39-
"""
40-
This class defines methods to parse and extract information from
41-
the given DBMS banner based upon the data in XML file
42-
"""
43-
44-
def __init__(self, banner):
45-
self.__banner = sanitizeStr(banner)
46-
47-
self.__regexp = None
48-
self.__match = None
49-
self.__version = None
50-
51-
52-
def __feedInfo(self, key, value):
53-
value = sanitizeStr(value)
54-
55-
if value in ( None, "None" ):
56-
return
57-
58-
if key == "version":
59-
kb.bannerFp[key] = value
60-
else:
61-
if key not in kb.bannerFp.keys():
62-
kb.bannerFp[key] = set()
63-
64-
kb.bannerFp[key].add(value)
65-
66-
67-
def startElement(self, name, attrs):
68-
if name == "regexp":
69-
self.__regexp = sanitizeStr(attrs.get("value"))
70-
self.__match = re.search(self.__regexp, self.__banner, re.I | re.M)
71-
72-
if name == "info" and self.__match:
73-
self.__feedInfo("type", attrs.get("type"))
74-
self.__feedInfo("distrib", attrs.get("distrib"))
75-
self.__feedInfo("release", attrs.get("release"))
76-
self.__feedInfo("codename", attrs.get("codename"))
77-
78-
self.__version = sanitizeStr(attrs.get("version"))
79-
self.__sp = sanitizeStr(attrs.get("sp"))
80-
81-
if self.__version.isdigit():
82-
self.__feedInfo("version", self.__match.group(int(self.__version)))
83-
84-
if self.__sp.isdigit():
85-
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
86-
87-
self.__regexp = None
88-
self.__match = None
89-
self.__version = None
36+
from lib.parse.handler import FingerprintHandler
9037

9138

9239
class MSSQLBannerHandler(ContentHandler):
@@ -172,9 +119,10 @@ def bannerParser(banner):
172119
if kb.dbms == "Microsoft SQL Server":
173120
handler = MSSQLBannerHandler(banner)
174121
parse(xmlfile, handler)
175-
handler = BannerHandler(banner)
122+
123+
handler = FingerprintHandler(banner, kb.bannerFp)
176124
parse(paths.GENERIC_XML, handler)
177125
else:
178-
handler = BannerHandler(banner)
126+
handler = FingerprintHandler(banner, kb.bannerFp)
179127
parse(xmlfile, handler)
180128
parse(paths.GENERIC_XML, handler)

lib/parse/handler.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
$Id$
5+
6+
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
7+
8+
Copyright (c) 2006-2008 Bernardo Damele A. G. <[email protected]>
9+
and Daniele Bellucci <[email protected]>
10+
11+
sqlmap is free software; you can redistribute it and/or modify it under
12+
the terms of the GNU General Public License as published by the Free
13+
Software Foundation version 2 of the License.
14+
15+
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
16+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18+
details.
19+
20+
You should have received a copy of the GNU General Public License along
21+
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
22+
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23+
"""
24+
25+
26+
27+
import re
28+
29+
from xml.sax.handler import ContentHandler
30+
31+
from lib.core.common import sanitizeStr
32+
from lib.core.data import kb
33+
34+
35+
class FingerprintHandler(ContentHandler):
36+
"""
37+
This class defines methods to parse and extract information from
38+
the given DBMS banner based upon the data in XML file
39+
"""
40+
41+
def __init__(self, banner, info):
42+
self.__banner = sanitizeStr(banner)
43+
44+
self.__regexp = None
45+
self.__match = None
46+
self.__dbmsVersion = None
47+
self.__techVersion = None
48+
self.__info = info
49+
50+
51+
def __feedInfo(self, key, value):
52+
value = sanitizeStr(value)
53+
54+
if value in ( None, "None" ):
55+
return
56+
57+
if key in ( "dbmsVersion" ):
58+
self.__info[key] = value
59+
else:
60+
if key not in self.__info.keys():
61+
self.__info[key] = set()
62+
63+
self.__info[key].add(value)
64+
65+
66+
def startElement(self, name, attrs):
67+
if name == "regexp":
68+
self.__regexp = sanitizeStr(attrs.get("value"))
69+
self.__match = re.search(self.__regexp, self.__banner, re.I | re.M)
70+
71+
if name == "info" and self.__match:
72+
self.__feedInfo("type", attrs.get("type"))
73+
self.__feedInfo("distrib", attrs.get("distrib"))
74+
self.__feedInfo("release", attrs.get("release"))
75+
self.__feedInfo("codename", attrs.get("codename"))
76+
77+
self.__dbmsVersion = sanitizeStr(attrs.get("dbms_version"))
78+
self.__techVersion = sanitizeStr(attrs.get("tech_version"))
79+
self.__sp = sanitizeStr(attrs.get("sp"))
80+
81+
if self.__dbmsVersion.isdigit():
82+
self.__feedInfo("dbmsVersion", self.__match.group(int(self.__dbmsVersion)))
83+
84+
if self.__techVersion.isdigit():
85+
self.__feedInfo("technology", "%s %s" % (attrs.get("technology"), self.__match.group(int(self.__techVersion))))
86+
else:
87+
self.__feedInfo("technology", attrs.get("technology"))
88+
89+
if self.__sp.isdigit():
90+
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
91+
92+
self.__regexp = None
93+
self.__match = None
94+
self.__dbmsVersion = None
95+
self.__techVersion = None

lib/parse/headers.py

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -27,67 +27,11 @@
2727
import re
2828

2929
from xml.sax import parse
30-
from xml.sax.handler import ContentHandler
3130

3231
from lib.core.common import checkFile
33-
from lib.core.common import sanitizeStr
3432
from lib.core.data import kb
3533
from lib.core.data import paths
36-
37-
38-
class HeadersHandler(ContentHandler):
39-
"""
40-
This class defines methods to parse and extract information from
41-
the given HTTP header based upon the data in XML file
42-
"""
43-
44-
def __init__(self, header):
45-
self.__header = sanitizeStr(header)
46-
47-
self.__regexp = None
48-
self.__match = None
49-
self.__techVersion = None
50-
51-
52-
def __feedInfo(self, key, value):
53-
value = sanitizeStr(value)
54-
55-
if value in ( None, "None" ):
56-
return
57-
58-
if key == "techVersion":
59-
kb.headersFp[key] = value
60-
else:
61-
if key not in kb.headersFp.keys():
62-
kb.headersFp[key] = set()
63-
64-
kb.headersFp[key].add(value)
65-
66-
67-
def startElement(self, name, attrs):
68-
if name == "regexp":
69-
self.__regexp = sanitizeStr(attrs.get("value"))
70-
self.__match = re.search(self.__regexp, self.__header, re.I | re.M)
71-
72-
if name == "info" and self.__match:
73-
self.__feedInfo("type", attrs.get("type"))
74-
self.__feedInfo("distrib", attrs.get("distrib"))
75-
self.__feedInfo("release", attrs.get("release"))
76-
self.__feedInfo("codename", attrs.get("codename"))
77-
self.__feedInfo("technology", attrs.get("codename"))
78-
79-
self.__techVersion = sanitizeStr(attrs.get("tech_version"))
80-
self.__sp = sanitizeStr(attrs.get("sp"))
81-
82-
if self.__techVersion.isdigit():
83-
self.__feedInfo("techVersion", self.__match.group(int(self.__techVersion)))
84-
85-
if self.__sp.isdigit():
86-
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
87-
88-
self.__regexp = None
89-
self.__match = None
90-
self.__techVersion = None
34+
from lib.parse.handler import FingerprintHandler
9135

9236

9337
def headersParser(headers):
@@ -97,11 +41,16 @@ def headersParser(headers):
9741
and the web application technology
9842
"""
9943

44+
if kb.headersCount > 3:
45+
return
46+
47+
kb.headersCount += 1
48+
10049
# TODO: ahead here
10150
topHeaders = {
10251
#"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
10352
#"microsoftsharepointteamservices": "%s/microsoftsharepointteamservices.xml" % paths.SQLMAP_XML_BANNER_PATH,
104-
#"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
53+
"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
10554
#"servlet-engine": "%s/servlet-engine.xml" % paths.SQLMAP_XML_BANNER_PATH,
10655
#"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
10756
#"www-authenticate": "%s/www-authenticate.xml" % paths.SQLMAP_XML_BANNER_PATH,
@@ -114,6 +63,6 @@ def headersParser(headers):
11463
value = headers[header]
11564
xmlfile = topHeaders[header]
11665
checkFile(xmlfile)
117-
handler = HeadersHandler(value)
66+
handler = FingerprintHandler(value, kb.headersFp)
11867
parse(xmlfile, handler)
11968
parse(paths.GENERIC_XML, handler)

0 commit comments

Comments
 (0)