Implementation for an Issue #2

This commit is contained in:
Miroslav Stampar 2014-10-23 11:23:53 +02:00
parent 8dcad46805
commit fc1b05bec9
6 changed files with 51 additions and 1 deletions

View File

@ -457,6 +457,12 @@ def start():
infoMsg = "skipping %s parameter '%s'" % (place, parameter) infoMsg = "skipping %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
elif parameter == conf.csrfToken:
testSqlInj = False
infoMsg = "skipping CSRF protection token parameter '%s'" % parameter
logger.info(infoMsg)
# Ignore session-like parameters for --level < 4 # Ignore session-like parameters for --level < 4
elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)): elif conf.level < 4 and (parameter.upper() in IGNORE_PARAMETERS or parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX)):
testSqlInj = False testSqlInj = False

View File

@ -53,6 +53,9 @@ class SqlmapSyntaxException(SqlmapBaseException):
class SqlmapThreadException(SqlmapBaseException): class SqlmapThreadException(SqlmapBaseException):
pass pass
class SqlmapTokenException(SqlmapBaseException):
pass
class SqlmapUndefinedMethod(SqlmapBaseException): class SqlmapUndefinedMethod(SqlmapBaseException):
pass pass

View File

@ -344,6 +344,12 @@ def _setRequestParams():
errMsg += "within the given request data" errMsg += "within the given request data"
raise SqlmapGenericException(errMsg) raise SqlmapGenericException(errMsg)
if conf.csrfToken:
if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))):
errMsg = "CSRF protection token parameter '%s' not " % conf.csrfToken
errMsg += "found in provided GET and/or POST values"
raise SqlmapGenericException(errMsg)
def _setHashDB(): def _setHashDB():
""" """
Check and set the HashDB SQLite file for query resume functionality. Check and set the HashDB SQLite file for query resume functionality.

View File

@ -190,6 +190,12 @@ def cmdLineParser():
action="store_true", action="store_true",
help="Skip URL encoding of payload data") help="Skip URL encoding of payload data")
request.add_option("--csrf-token", dest="csrfToken",
help="Parameter used as a CSRF protection token")
request.add_option("--csrf-url", dest="csrfUrl",
help="URL address to visit to extract CSRF protection token")
request.add_option("--force-ssl", dest="forceSSL", request.add_option("--force-ssl", dest="forceSSL",
action="store_true", action="store_true",
help="Force usage of SSL/HTTPS") help="Force usage of SSL/HTTPS")

View File

@ -106,7 +106,7 @@ def forgeHeaders(items=None):
elif not kb.testMode: elif not kb.testMode:
headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, cookie.name, getUnicode(cookie.value)) headers[HTTP_HEADER.COOKIE] += "%s %s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, cookie.name, getUnicode(cookie.value))
if kb.testMode: if kb.testMode and not conf.csrfToken:
resetCookieJar(conf.cj) resetCookieJar(conf.cj)
return headers return headers

View File

@ -63,6 +63,7 @@ from lib.core.enums import WEB_API
from lib.core.exception import SqlmapCompressionException from lib.core.exception import SqlmapCompressionException
from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapConnectionException
from lib.core.exception import SqlmapSyntaxException from lib.core.exception import SqlmapSyntaxException
from lib.core.exception import SqlmapTokenException
from lib.core.exception import SqlmapValueException from lib.core.exception import SqlmapValueException
from lib.core.settings import ASTERISK_MARKER from lib.core.settings import ASTERISK_MARKER
from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR from lib.core.settings import CUSTOM_INJECTION_MARK_CHAR
@ -748,6 +749,34 @@ class Connect(object):
if value and place == PLACE.CUSTOM_HEADER: if value and place == PLACE.CUSTOM_HEADER:
auxHeaders[value.split(',')[0]] = value.split(',', 1)[1] auxHeaders[value.split(',')[0]] = value.split(',', 1)[1]
if conf.csrfToken:
def _adjustParameter(paramString, parameter, newValue):
retVal = paramString
match = re.search("%s=(?P<value>[^&]*)" % parameter, paramString)
if match:
origValue = match.group("value")
retVal = re.sub("%s=[^&]*" % parameter, "%s=%s" % (parameter, newValue), paramString)
return retVal
page, _, _ = Connect.getPage(url=conf.csrfUrl or conf.url, cookie=conf.parameters.get(PLACE.COOKIE), direct=True, silent=True, ua=conf.parameters.get(PLACE.USER_AGENT), referer=conf.parameters.get(PLACE.REFERER), host=conf.parameters.get(PLACE.HOST))
match = re.search(r"<input[^>]+name=[\"']?%s[\"']?\s[^>]*value=(\"([^\"]+)|'([^']+)|([^ >]+))" % conf.csrfToken, page)
token = (match.group(2) or match.group(3) or match.group(4)) if match else None
if not token:
errMsg = "CSRF token value '%s' can't be found at '%s'" % (conf.csrfToken, conf.csrfUrl or conf.url)
if not conf.csrfUrl:
errMsg += ". You can try to rerun by providing "
errMsg += "a valid value for option '--csrf-url'"
raise SqlmapTokenException, errMsg
if token:
for item in (PLACE.GET, PLACE.POST):
if item in conf.parameters:
if item == PLACE.GET and get:
get = _adjustParameter(get, conf.csrfToken, token)
elif item == PLACE.POST and post:
post = _adjustParameter(post, conf.csrfToken, token)
if conf.rParam: if conf.rParam:
def _randomizeParameter(paramString, randomParameter): def _randomizeParameter(paramString, randomParameter):
retVal = paramString retVal = paramString