Skip to content

Commit 702ed73

Browse files
committed
Added --code switch to match in boolean-based tests against the HTTP response code
1 parent e34787d commit 702ed73

9 files changed

Lines changed: 39 additions & 23 deletions

File tree

lib/controller/checks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -898,15 +898,15 @@ def checkNullConnection():
898898
logger.info(infoMsg)
899899

900900
try:
901-
page, headers = Request.getPage(method=HTTPMETHOD.HEAD)
901+
page, headers, _ = Request.getPage(method=HTTPMETHOD.HEAD)
902902

903903
if not page and HTTPHEADER.CONTENT_LENGTH in headers:
904904
kb.nullConnection = NULLCONNECTION.HEAD
905905

906906
infoMsg = "NULL connection is supported with HEAD header"
907907
logger.info(infoMsg)
908908
else:
909-
page, headers = Request.getPage(auxHeaders={HTTPHEADER.RANGE: "bytes=-1"})
909+
page, headers, _ = Request.getPage(auxHeaders={HTTPHEADER.RANGE: "bytes=-1"})
910910

911911
if page and len(page) == 1 and HTTPHEADER.CONTENT_RANGE in headers:
912912
kb.nullConnection = NULLCONNECTION.RANGE

lib/core/option.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,9 @@ def __cleanupOptions():
13301330
else:
13311331
kb.adjustTimeDelay = False
13321332

1333+
if conf.code:
1334+
conf.code = int(conf.code)
1335+
13331336
def __setConfAttributes():
13341337
"""
13351338
This function set some needed attributes into the configuration

lib/core/optiondict.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"risk": "integer",
6969
"string": "string",
7070
"regexp": "string",
71+
"code": "string",
7172
"textOnly": "boolean",
7273
"titles": "boolean"
7374
},

lib/parse/cmdline.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,16 @@ def cmdLineParser():
200200
"default %d)" % defaults.level)
201201

202202
detection.add_option("--string", dest="string",
203-
help="String to match in page when the "
203+
help="String to match in the response when "
204204
"query is valid")
205205

206206
detection.add_option("--regexp", dest="regexp",
207-
help="Regexp to match in page when the "
207+
help="Regexp to match in the response when "
208208
"query is valid")
209209

210+
detection.add_option("--code", dest="code", type="int",
211+
help="HTTP response code to match when the query is valid")
212+
210213
detection.add_option("--text-only", dest="textOnly",
211214
action="store_true",
212215
help="Compare pages based only on the textual content")

lib/request/comparison.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from lib.core.settings import UPPER_RATIO_BOUND
2929
from lib.core.threads import getCurrentThreadData
3030

31-
def comparison(page, headers, getRatioValue=False, pageLength=None):
31+
def comparison(page, headers, code=None, getRatioValue=False, pageLength=None):
3232
if page is None and pageLength is None:
3333
return None
3434

@@ -50,6 +50,9 @@ def comparison(page, headers, getRatioValue=False, pageLength=None):
5050
condition = re.search(conf.regexp, rawResponse, re.I | re.M) is not None
5151
return condition if not getRatioValue else (MAX_RATIO if condition else MIN_RATIO)
5252

53+
if isinstance(code, int) and conf.code:
54+
return code == conf.code
55+
5356
if page:
5457
# In case of an DBMS error page return None
5558
if kb.errorIsNone and (wasLastRequestDBMSError() or wasLastRequestHTTPError()):

lib/request/connect.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ def getPage(**kwargs):
306306

307307
# Return response object
308308
if response:
309-
return conn, None
309+
return conn, None, None
310310

311311
# Get HTTP response
312312
page = conn.read()
@@ -369,7 +369,7 @@ def getPage(**kwargs):
369369
warnMsg = "connection timed out while trying "
370370
warnMsg += "to get error page information (%d)" % e.code
371371
logger.warn(warnMsg)
372-
return None, None
372+
return None, None, None
373373
except:
374374
pass
375375

@@ -409,7 +409,7 @@ def getPage(**kwargs):
409409
processResponse(page, responseHeaders)
410410
elif e.code == 504:
411411
if ignoreTimeout:
412-
return None, None
412+
return None, None, None
413413
else:
414414
warnMsg = "unable to connect to the target url (%d - %s)" % (e.code, httplib.responses[e.code])
415415
if threadData.retriesCount < conf.retries and not kb.threadException and not conf.realTest:
@@ -418,14 +418,14 @@ def getPage(**kwargs):
418418
return Connect.__retryProxy(**kwargs)
419419
elif kb.testMode:
420420
logger.critical(warnMsg)
421-
return None, None
421+
return None, None, None
422422
else:
423423
raise sqlmapConnectionException, warnMsg
424424
else:
425425
debugMsg = "got HTTP error code: %d (%s)" % (code, status)
426426
logger.debug(debugMsg)
427427
processResponse(page, responseHeaders)
428-
return page, responseHeaders
428+
return page, responseHeaders, code
429429

430430
except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine, httplib.IncompleteRead), e:
431431
tbMsg = traceback.format_exc()
@@ -454,16 +454,16 @@ def getPage(**kwargs):
454454

455455
if "forcibly closed" in tbMsg:
456456
logger.critical(warnMsg)
457-
return None, None
457+
return None, None, None
458458
elif silent or (ignoreTimeout and any(map(lambda x: x in tbMsg, ["timed out", "IncompleteRead"]))):
459-
return None, None
459+
return None, None, None
460460
elif threadData.retriesCount < conf.retries and not kb.threadException and not conf.realTest:
461461
warnMsg += ", sqlmap is going to retry the request"
462462
logger.critical(warnMsg)
463463
return Connect.__retryProxy(**kwargs)
464464
elif kb.testMode:
465465
logger.critical(warnMsg)
466-
return None, None
466+
return None, None, None
467467
else:
468468
raise sqlmapConnectionException, warnMsg
469469

@@ -485,7 +485,7 @@ def getPage(**kwargs):
485485

486486
logger.log(7, responseMsg)
487487

488-
return page, responseHeaders
488+
return page, responseHeaders, code
489489

490490
@staticmethod
491491
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 @@ def queryPage(value=None, place=None, content=False, getRatioValue=False, silent
613613

614614
auxHeaders[HTTPHEADER.RANGE] = "bytes=-1"
615615

616-
_, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404)
616+
_, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404)
617617

618618
if headers:
619619
if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers:
@@ -622,7 +622,7 @@ def queryPage(value=None, place=None, content=False, getRatioValue=False, silent
622622
pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:])
623623

624624
if not pageLength:
625-
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)
625+
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)
626626

627627
threadData.lastQueryDuration = calculateDeltaSeconds(start)
628628

@@ -643,8 +643,8 @@ def queryPage(value=None, place=None, content=False, getRatioValue=False, silent
643643
page = removeReflectiveValues(page, payload)
644644

645645
if getRatioValue:
646-
return comparison(page, headers, getRatioValue=False, pageLength=pageLength), comparison(page, headers, getRatioValue=True, pageLength=pageLength)
646+
return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength)
647647
elif pageLength or page:
648-
return comparison(page, headers, getRatioValue, pageLength)
648+
return comparison(page, headers, code, getRatioValue, pageLength)
649649
else:
650650
return False

lib/takeover/web.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def webBackdoorRunCmd(self, cmd):
6262
cmd = conf.osCmd
6363

6464
cmdUrl = "%s?cmd=%s" % (self.webBackdoorUrl, cmd)
65-
page, _ = Request.getPage(url=cmdUrl, direct=True, silent=True)
65+
page, _, _ = Request.getPage(url=cmdUrl, direct=True, silent=True)
6666

6767
if page is not None:
6868
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
@@ -237,7 +237,7 @@ def webInit(self):
237237
self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, uriPath)
238238
self.webStagerUrl = "%s/%s" % (self.webBaseUrl, stagerName)
239239

240-
uplPage, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False)
240+
uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False)
241241

242242
if "sqlmap file uploader" not in uplPage:
243243
if localPath not in warned:

lib/techniques/union/test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def __orderByTest(cols):
109109
query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, kb.uChar)
110110
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
111111
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
112-
ratio = comparison(page, headers, True) or MIN_RATIO
112+
ratio = comparison(page, headers, getRatioValue=True) or MIN_RATIO
113113
ratios.append(ratio)
114114
min_, max_ = min(min_, ratio), max(max_, ratio)
115115
items.append((count, ratio))

sqlmap.conf

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,19 +204,25 @@ level = 1
204204
# Default: 1
205205
risk = 1
206206

207-
# String to match within the page content when the query is valid, only
207+
# String to match within the raw response when the query is valid, only
208208
# needed if the page content dynamically changes at each refresh.
209209
# Refer to the user's manual for further details.
210210
string =
211211

212-
# Regular expression to match within the page content when the query is
212+
# Regular expression to match within the raw response when the query is
213213
# valid, only needed if the needed if the page content dynamically changes
214214
# at each refresh.
215215
# Refer to the user's manual for further details.
216216
# Valid: regular expression with Python syntax
217217
# (http://www.python.org/doc/2.5.2/lib/re-syntax.html)
218218
regexp =
219219

220+
# HTTP response code to match when the query is valid
221+
# Valid: True or False
222+
# Example: 200 (assuming any False statement returns a different response
223+
# code)
224+
code =
225+
220226
# Compare pages based only on the textual content
221227
# Valid: True or False
222228
textOnly = False

0 commit comments

Comments
 (0)