Merge branch 'master' of github.com:sqlmapproject/sqlmap

This commit is contained in:
Bernardo Damele 2012-07-26 23:11:11 +01:00
commit 92c2b3bd4c
13 changed files with 65 additions and 26 deletions

View File

@ -359,7 +359,7 @@ def checkSqlInjection(place, parameter, value):
injectable = True
if not injectable and not conf.string and kb.pageStable:
if not injectable and not any((conf.string, conf.notString, conf.regexp)) and kb.pageStable:
trueSet = set(extractTextTagContent(truePage))
falseSet = set(extractTextTagContent(falsePage))
candidates = filter(None, (_.strip() if _.strip() in (kb.pageTemplate or "") and _.strip() not in falsePage else None for _ in (trueSet - falseSet)))
@ -460,7 +460,7 @@ def checkSqlInjection(place, parameter, value):
# Feed with the boundaries details only the first time a
# test has been successful
if injection.place is None or injection.parameter is None:
if place in (PLACE.UA, PLACE.REFERER, PLACE.HOST):
if place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST):
injection.parameter = place
else:
injection.parameter = parameter
@ -499,6 +499,7 @@ def checkSqlInjection(place, parameter, value):
injection.conf.textOnly = conf.textOnly
injection.conf.titles = conf.titles
injection.conf.string = conf.string
injection.conf.notString = conf.notString
injection.conf.regexp = conf.regexp
injection.conf.optimize = conf.optimize

View File

@ -357,7 +357,7 @@ def start():
if (len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None)) \
and (kb.injection.place is None or kb.injection.parameter is None):
if not conf.string and not conf.regexp and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech:
if not any((conf.string, conf.notString, conf.regexp)) and PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech:
# NOTE: this is not needed anymore, leaving only to display
# a warning message to the user in case the page is not stable
checkStability()
@ -378,7 +378,7 @@ def start():
for place in parameters:
# Test User-Agent and Referer headers only if
# --level >= 3
skip = (place == PLACE.UA and conf.level < 3)
skip = (place == PLACE.USER_AGENT and conf.level < 3)
skip |= (place == PLACE.REFERER and conf.level < 3)
# Test Host header only if
@ -388,11 +388,11 @@ def start():
# Test Cookie header only if --level >= 2
skip |= (place == PLACE.COOKIE and conf.level < 2)
skip |= (place == PLACE.UA and intersect(USER_AGENT_ALIASES, conf.skip, True) not in ([], None))
skip |= (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.skip, True) not in ([], None))
skip |= (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.skip, True) not in ([], None))
skip |= (place == PLACE.COOKIE and intersect(PLACE.COOKIE, conf.skip, True) not in ([], None))
skip &= not (place == PLACE.UA and intersect(USER_AGENT_ALIASES, conf.testParameter, True))
skip &= not (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.testParameter, True))
skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter, True))
skip &= not (place == PLACE.HOST and intersect(HOST_ALIASES, conf.testParameter, True))
@ -527,7 +527,7 @@ def start():
errMsg += "Please, consider usage of tampering scripts as "
errMsg += "your target might filter the queries."
if not conf.string and not conf.regexp:
if not conf.string and not conf.notString and not conf.regexp:
errMsg += " Also, you can try to rerun by providing "
errMsg += "either a valid value for option '--string' "
errMsg += "(or '--regexp')"

View File

@ -118,7 +118,7 @@ class Agent:
retVal = ET.tostring(root)
elif place in (PLACE.URI, PLACE.CUSTOM_POST):
retVal = paramString.replace("%s%s" % (origValue, CUSTOM_INJECTION_MARK_CHAR), self.addPayloadDelimiters(newValue))
elif place in (PLACE.UA, PLACE.REFERER, PLACE.HOST):
elif place in (PLACE.USER_AGENT, PLACE.REFERER, PLACE.HOST):
retVal = paramString.replace(origValue, self.addPayloadDelimiters(newValue))
else:
retVal = paramString.replace("%s=%s" % (parameter, origValue),

View File

@ -255,7 +255,7 @@ class Format:
if "technology" in info:
infoStr += "\nweb application technology: %s" % Format.humanize(info["technology"], ", ")
return infoStr
return infoStr.lstrip()
class Backend:
# Set methods
@ -2362,7 +2362,7 @@ def setOptimize():
#conf.predictOutput = True
conf.keepAlive = True
conf.threads = 3 if conf.threads < 3 else conf.threads
conf.nullConnection = not any([conf.data, conf.textOnly, conf.titles, conf.string, conf.regexp, conf.tor])
conf.nullConnection = not any([conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor])
if not conf.nullConnection:
debugMsg = "turning off --null-connection switch used indirectly by switch -o"

View File

@ -61,7 +61,7 @@ class PLACE:
SOAP = "SOAP"
URI = "URI"
COOKIE = "Cookie"
UA = "User-Agent"
USER_AGENT = "User-Agent"
REFERER = "Referer"
HOST = "Host"
CUSTOM_POST = "(custom) POST"

View File

@ -1867,6 +1867,14 @@ def __basicOptionValidation():
errMsg = "option '--string' is incompatible with switch '--null-connection'"
raise sqlmapSyntaxException, errMsg
if conf.notString and conf.nullConnection:
errMsg = "option '--not-string' is incompatible with switch '--null-connection'"
raise sqlmapSyntaxException, errMsg
if conf.string and conf.notString:
errMsg = "option '--string' is incompatible with switch '--not-string'"
raise sqlmapSyntaxException, errMsg
if conf.regexp and conf.nullConnection:
errMsg = "option '--regexp' is incompatible with switch '--null-connection'"
raise sqlmapSyntaxException, errMsg

View File

@ -76,6 +76,7 @@ optDict = {
"level": "integer",
"risk": "integer",
"string": "string",
"notString": "notString",
"regexp": "string",
"code": "integer",
"textOnly": "boolean",
@ -87,7 +88,8 @@ optDict = {
"timeSec": "integer",
"uCols": "string",
"uChar": "string",
"dnsName": "string"
"dnsName": "string",
"secondOrder": "string"
},
"Fingerprint": {

View File

@ -26,6 +26,7 @@ from lib.core.data import logger
from lib.core.data import paths
from lib.core.dump import dumper
from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HTTPHEADER
from lib.core.enums import HTTPMETHOD
from lib.core.enums import PLACE
from lib.core.exception import sqlmapFilePathException
@ -158,16 +159,18 @@ def __setRequestParams():
# Url encoding of the header values should be avoided
# Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value
if httpHeader == PLACE.UA:
conf.parameters[PLACE.UA] = urldecode(headerValue)
httpHeader = "-".join(_.capitalize() for _ in (httpHeader or "").split("-"))
if httpHeader == HTTPHEADER.USER_AGENT:
conf.parameters[PLACE.USER_AGENT] = urldecode(headerValue)
condition = any((not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES)))
if condition:
conf.paramDict[PLACE.UA] = {PLACE.UA: headerValue}
conf.paramDict[PLACE.USER_AGENT] = {PLACE.USER_AGENT: headerValue}
testableParameters = True
elif httpHeader == PLACE.REFERER:
elif httpHeader == HTTPHEADER.REFERER:
conf.parameters[PLACE.REFERER] = urldecode(headerValue)
condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES)))
@ -176,7 +179,7 @@ def __setRequestParams():
conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue}
testableParameters = True
elif httpHeader == PLACE.HOST:
elif httpHeader == HTTPHEADER.HOST:
conf.parameters[PLACE.HOST] = urldecode(headerValue)
condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES)))

View File

@ -245,6 +245,10 @@ def cmdLineParser():
help="String to match when "
"query is evaluated to True")
detection.add_option("--not-string", dest="notString",
help="String to match when "
"query is evaluated to False")
detection.add_option("--regexp", dest="regexp",
help="Regexp to match when "
"query is evaluated to True")
@ -284,6 +288,10 @@ def cmdLineParser():
techniques.add_option("--dns-domain", dest="dnsName",
help="Domain name used for DNS exfiltration attack")
techniques.add_option("--second-order", dest="secondOrder",
help="Resulting page url searched for second-order "
"response")
# Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint")

View File

@ -31,7 +31,7 @@ def comparison(page, headers, code=None, getRatioValue=False, pageLength=None):
return _
def _adjust(condition, getRatioValue):
if not any([conf.string, conf.regexp, conf.code]):
if not any([conf.string, conf.notString, conf.regexp, conf.code]):
# Negative logic approach is used in raw page comparison scheme as that what is "different" than original
# PAYLOAD.WHERE.NEGATIVE response is considered as True; in switch based approach negative logic is not
# applied as that what is by user considered as True is that what is returned by the comparison mechanism
@ -54,14 +54,18 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
seqMatcher = threadData.seqMatcher
seqMatcher.set_seq1(kb.pageTemplate)
if any([conf.string, conf.regexp]):
if any([conf.string, conf.notString, conf.regexp]):
rawResponse = "%s%s" % (listToStrValue(headers.headers if headers else ""), page)
# String to match in page when the query is valid
# String to match in page when the query is True and/or valid
if conf.string:
return conf.string in rawResponse
# Regular expression to match in page when the query is valid
# String to match in page when the query is False and/or invalid
if conf.notString:
return conf.notString not in rawResponse
# Regular expression to match in page when the query is True and/or valid
if conf.regexp:
return re.search(conf.regexp, rawResponse, re.I | re.M) is not None

View File

@ -192,7 +192,7 @@ class Connect:
code = None
page = None
requestMsg = u"HTTP request [#%d]:\n%s " % (threadData.lastRequestUID, method or (HTTPMETHOD.POST if post else HTTPMETHOD.GET))
requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/"
requestMsg += ("%s" % urlparse.urlsplit(url)[2] or "/") if not any((refreshing, crawling)) else url
responseMsg = u"HTTP response "
requestHeaders = u""
responseHeaders = None
@ -236,7 +236,7 @@ class Connect:
return page
elif any ([refreshing, crawling]):
elif any ((refreshing, crawling)):
pass
elif target:
@ -595,8 +595,8 @@ class Connect:
if PLACE.COOKIE in conf.parameters:
cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value
if PLACE.UA in conf.parameters:
ua = conf.parameters[PLACE.UA] if place != PLACE.UA or not value else value
if PLACE.USER_AGENT in conf.parameters:
ua = conf.parameters[PLACE.USER_AGENT] if place != PLACE.USER_AGENT or not value else value
if PLACE.REFERER in conf.parameters:
referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value
@ -731,6 +731,9 @@ class Connect:
if not pageLength:
page, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare)
if conf.secondOrder:
page, headers, code = Connect.getPage(url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True)
threadData.lastQueryDuration = calculateDeltaSeconds(start)
kb.originalCode = kb.originalCode or code

View File

@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
"""
import hashlib
import os
import sqlite3
import threading
import time
@ -54,7 +55,7 @@ class HashDB(object):
def retrieve(self, key, unserialize=False):
retVal = None
if key:
if key and (self._write_cache or os.path.isfile(self.filepath)):
hash_ = HashDB.hashKey(key)
retVal = self._write_cache.get(hash_, None)
if not retVal:

View File

@ -247,6 +247,11 @@ risk = 1
# Refer to the user's manual for further details.
string =
# String to match within the raw response when the query is evaluated to
# False, only needed if the page content dynamically changes at each refresh.
# Refer to the user's manual for further details.
notString =
# Regular expression to match within the raw response when the query is
# evaluated to True, only needed if the needed if the page content
# dynamically changes at each refresh.
@ -305,6 +310,10 @@ uChar =
# Valid: string
dnsName =
# Resulting page url searched for second-order response
# Valid: string
secondOrder =
[Fingerprint]