Added --code switch to match in boolean-based tests against the HTTP response code

This commit is contained in:
Bernardo Damele 2011-08-12 16:48:11 +00:00
parent e34787db99
commit 702ed73a65
9 changed files with 39 additions and 23 deletions

View File

@ -898,7 +898,7 @@ def checkNullConnection():
logger.info(infoMsg) logger.info(infoMsg)
try: try:
page, headers = Request.getPage(method=HTTPMETHOD.HEAD) page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
if not page and HTTPHEADER.CONTENT_LENGTH in headers: if not page and HTTPHEADER.CONTENT_LENGTH in headers:
kb.nullConnection = NULLCONNECTION.HEAD kb.nullConnection = NULLCONNECTION.HEAD
@ -906,7 +906,7 @@ def checkNullConnection():
infoMsg = "NULL connection is supported with HEAD header" infoMsg = "NULL connection is supported with HEAD header"
logger.info(infoMsg) logger.info(infoMsg)
else: else:
page, headers = Request.getPage(auxHeaders={HTTPHEADER.RANGE: "bytes=-1"}) page, headers, _ = Request.getPage(auxHeaders={HTTPHEADER.RANGE: "bytes=-1"})
if page and len(page) == 1 and HTTPHEADER.CONTENT_RANGE in headers: if page and len(page) == 1 and HTTPHEADER.CONTENT_RANGE in headers:
kb.nullConnection = NULLCONNECTION.RANGE kb.nullConnection = NULLCONNECTION.RANGE

View File

@ -1330,6 +1330,9 @@ def __cleanupOptions():
else: else:
kb.adjustTimeDelay = False kb.adjustTimeDelay = False
if conf.code:
conf.code = int(conf.code)
def __setConfAttributes(): def __setConfAttributes():
""" """
This function set some needed attributes into the configuration This function set some needed attributes into the configuration

View File

@ -68,6 +68,7 @@ optDict = {
"risk": "integer", "risk": "integer",
"string": "string", "string": "string",
"regexp": "string", "regexp": "string",
"code": "string",
"textOnly": "boolean", "textOnly": "boolean",
"titles": "boolean" "titles": "boolean"
}, },

View File

@ -200,13 +200,16 @@ def cmdLineParser():
"default %d)" % defaults.level) "default %d)" % defaults.level)
detection.add_option("--string", dest="string", detection.add_option("--string", dest="string",
help="String to match in page when the " help="String to match in the response when "
"query is valid") "query is valid")
detection.add_option("--regexp", dest="regexp", detection.add_option("--regexp", dest="regexp",
help="Regexp to match in page when the " help="Regexp to match in the response when "
"query is valid") "query is valid")
detection.add_option("--code", dest="code", type="int",
help="HTTP response code to match when the query is valid")
detection.add_option("--text-only", dest="textOnly", detection.add_option("--text-only", dest="textOnly",
action="store_true", action="store_true",
help="Compare pages based only on the textual content") help="Compare pages based only on the textual content")

View File

@ -28,7 +28,7 @@ from lib.core.settings import LOWER_RATIO_BOUND
from lib.core.settings import UPPER_RATIO_BOUND from lib.core.settings import UPPER_RATIO_BOUND
from lib.core.threads import getCurrentThreadData from lib.core.threads import getCurrentThreadData
def comparison(page, headers, getRatioValue=False, pageLength=None): def comparison(page, headers, code=None, getRatioValue=False, pageLength=None):
if page is None and pageLength is None: if page is None and pageLength is None:
return None return None
@ -50,6 +50,9 @@ def comparison(page, headers, getRatioValue=False, pageLength=None):
condition = re.search(conf.regexp, rawResponse, re.I | re.M) is not None condition = re.search(conf.regexp, rawResponse, re.I | re.M) is not None
return condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO) return condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO)
if isinstance(code, int) and conf.code:
return code == conf.code
if page: if page:
# In case of an DBMS error page return None # In case of an DBMS error page return None
if kb.errorIsNone and (wasLastRequestDBMSError() or wasLastRequestHTTPError()): if kb.errorIsNone and (wasLastRequestDBMSError() or wasLastRequestHTTPError()):

View File

@ -306,7 +306,7 @@ class Connect:
# Return response object # Return response object
if response: if response:
return conn, None return conn, None, None
# Get HTTP response # Get HTTP response
page = conn.read() page = conn.read()
@ -369,7 +369,7 @@ class Connect:
warnMsg = "connection timed out while trying " warnMsg = "connection timed out while trying "
warnMsg += "to get error page information (%d)" % e.code warnMsg += "to get error page information (%d)" % e.code
logger.warn(warnMsg) logger.warn(warnMsg)
return None, None return None, None, None
except: except:
pass pass
@ -409,7 +409,7 @@ class Connect:
processResponse(page, responseHeaders) processResponse(page, responseHeaders)
elif e.code == 504: elif e.code == 504:
if ignoreTimeout: if ignoreTimeout:
return None, None return None, None, None
else: else:
warnMsg = "unable to connect to the target url (%d - %s)" % (e.code, httplib.responses[e.code]) warnMsg = "unable to connect to the target url (%d - %s)" % (e.code, httplib.responses[e.code])
if threadData.retriesCount < conf.retries and not kb.threadException and not conf.realTest: if threadData.retriesCount < conf.retries and not kb.threadException and not conf.realTest:
@ -418,14 +418,14 @@ class Connect:
return Connect.__retryProxy(**kwargs) return Connect.__retryProxy(**kwargs)
elif kb.testMode: elif kb.testMode:
logger.critical(warnMsg) logger.critical(warnMsg)
return None, None return None, None, None
else: else:
raise sqlmapConnectionException, warnMsg raise sqlmapConnectionException, warnMsg
else: else:
debugMsg = "got HTTP error code: %d (%s)" % (code, status) debugMsg = "got HTTP error code: %d (%s)" % (code, status)
logger.debug(debugMsg) logger.debug(debugMsg)
processResponse(page, responseHeaders) processResponse(page, responseHeaders)
return page, responseHeaders return page, responseHeaders, code
except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine, httplib.IncompleteRead), e: except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine, httplib.IncompleteRead), e:
tbMsg = traceback.format_exc() tbMsg = traceback.format_exc()
@ -454,16 +454,16 @@ class Connect:
if "forcibly closed" in tbMsg: if "forcibly closed" in tbMsg:
logger.critical(warnMsg) logger.critical(warnMsg)
return None, None return None, None, None
elif silent or (ignoreTimeout and any(map(lambda x: x in tbMsg, ["timed out", "IncompleteRead"]))): elif silent or (ignoreTimeout and any(map(lambda x: x in tbMsg, ["timed out", "IncompleteRead"]))):
return None, None return None, None, None
elif threadData.retriesCount < conf.retries and not kb.threadException and not conf.realTest: elif threadData.retriesCount < conf.retries and not kb.threadException and not conf.realTest:
warnMsg += ", sqlmap is going to retry the request" warnMsg += ", sqlmap is going to retry the request"
logger.critical(warnMsg) logger.critical(warnMsg)
return Connect.__retryProxy(**kwargs) return Connect.__retryProxy(**kwargs)
elif kb.testMode: elif kb.testMode:
logger.critical(warnMsg) logger.critical(warnMsg)
return None, None return None, None, None
else: else:
raise sqlmapConnectionException, warnMsg raise sqlmapConnectionException, warnMsg
@ -485,7 +485,7 @@ class Connect:
logger.log(7, responseMsg) logger.log(7, responseMsg)
return page, responseHeaders return page, responseHeaders, code
@staticmethod @staticmethod
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None): def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None):
@ -613,7 +613,7 @@ class Connect:
auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" auxHeaders[HTTPHEADER.RANGE] = "bytes=-1"
_, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) _, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404)
if headers: if headers:
if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers:
@ -622,7 +622,7 @@ class Connect:
pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:])
if not pageLength: if not pageLength:
page, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) page, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare)
threadData.lastQueryDuration = calculateDeltaSeconds(start) threadData.lastQueryDuration = calculateDeltaSeconds(start)
@ -643,8 +643,8 @@ class Connect:
page = removeReflectiveValues(page, payload) page = removeReflectiveValues(page, payload)
if getRatioValue: if getRatioValue:
return comparison(page, headers, getRatioValue=False, pageLength=pageLength), comparison(page, headers, getRatioValue=True, pageLength=pageLength) return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength)
elif pageLength or page: elif pageLength or page:
return comparison(page, headers, getRatioValue, pageLength) return comparison(page, headers, code, getRatioValue, pageLength)
else: else:
return False return False

View File

@ -62,7 +62,7 @@ class Web:
cmd = conf.osCmd cmd = conf.osCmd
cmdUrl = "%s?cmd=%s" % (self.webBackdoorUrl, cmd) cmdUrl = "%s?cmd=%s" % (self.webBackdoorUrl, cmd)
page, _ = Request.getPage(url=cmdUrl, direct=True, silent=True) page, _, _ = Request.getPage(url=cmdUrl, direct=True, silent=True)
if page is not None: if page is not None:
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S) output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
@ -237,7 +237,7 @@ class Web:
self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, uriPath) self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, uriPath)
self.webStagerUrl = "%s/%s" % (self.webBaseUrl, stagerName) self.webStagerUrl = "%s/%s" % (self.webBaseUrl, stagerName)
uplPage, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False) uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False)
if "sqlmap file uploader" not in uplPage: if "sqlmap file uploader" not in uplPage:
if localPath not in warned: if localPath not in warned:

View File

@ -109,7 +109,7 @@ def __findUnionCharCount(comment, place, parameter, value, prefix, suffix, where
query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, kb.uChar) query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, kb.uChar)
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False) page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
ratio = comparison(page, headers, True) or MIN_RATIO ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
ratios.append(ratio) ratios.append(ratio)
min_, max_ = min(min_, ratio), max(max_, ratio) min_, max_ = min(min_, ratio), max(max_, ratio)
items.append((count, ratio)) items.append((count, ratio))

View File

@ -204,12 +204,12 @@ level = 1
# Default: 1 # Default: 1
risk = 1 risk = 1
# String to match within the page content when the query is valid, only # String to match within the raw response when the query is valid, only
# needed if the page content dynamically changes at each refresh. # needed if the page content dynamically changes at each refresh.
# Refer to the user's manual for further details. # Refer to the user's manual for further details.
string = string =
# Regular expression to match within the page content when the query is # Regular expression to match within the raw response when the query is
# valid, only needed if the needed if the page content dynamically changes # valid, only needed if the needed if the page content dynamically changes
# at each refresh. # at each refresh.
# Refer to the user's manual for further details. # Refer to the user's manual for further details.
@ -217,6 +217,12 @@ string =
# (http://www.python.org/doc/2.5.2/lib/re-syntax.html) # (http://www.python.org/doc/2.5.2/lib/re-syntax.html)
regexp = regexp =
# HTTP response code to match when the query is valid
# Valid: True or False
# Example: 200 (assuming any False statement returns a different response
# code)
code =
# Compare pages based only on the textual content # Compare pages based only on the textual content
# Valid: True or False # Valid: True or False
textOnly = False textOnly = False