From bb98894dc13b1d75197c06b46d722aac3fdf664b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Apr 2015 16:28:54 +0200 Subject: [PATCH] Adding option --safe-req --- lib/core/option.py | 69 +++++++++++++++++++++++++++++++++++------- lib/core/optiondict.py | 1 + lib/parse/cmdline.py | 3 ++ lib/request/connect.py | 7 +++-- sqlmap.conf | 3 ++ 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index c6334b500..a2778d60b 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1136,21 +1136,63 @@ def _setHTTPProxy(): proxyHandler.__init__(proxyHandler.proxies) -def _setSafeUrl(): +def _setSafeVisit(): """ - Check and set the safe URL options. + Check and set the safe visit options. """ - if not conf.safeUrl: + if not any ((conf.safeUrl, conf.safeReqFile)): return - if not re.search("^http[s]*://", conf.safeUrl): - if ":443/" in conf.safeUrl: - conf.safeUrl = "https://" + conf.safeUrl + if conf.safeReqFile: + checkFile(conf.safeReqFile) + + raw = readCachedFileContent(conf.safeReqFile) + match = re.search(r"\A([A-Z]+) ([^ ]+) HTTP/[0-9.]+\Z", raw[:raw.find('\n')]) + + if match: + kb.safeReq.method = match.group(1) + kb.safeReq.url = match.group(2) + kb.safeReq.headers = {} + + for line in raw[raw.find('\n') + 1:].split('\n'): + line = line.strip() + if line and ':' in line: + key, value = line.split(':', 1) + value = value.strip() + kb.safeReq.headers[key] = value + if key == HTTP_HEADER.HOST: + if not value.startswith("http"): + scheme = "http" + if value.endswith(":443"): + scheme = "https" + value = "%s://%s" % (scheme, value) + kb.safeReq.url = urlparse.urljoin(value, kb.safeReq.url) + else: + break + + post = None + + if '\r\n\r\n' in raw: + post = raw[raw.find('\r\n\r\n') + 4:] + elif '\n\n' in raw: + post = raw[raw.find('\n\n') + 2:] + + if post and post.strip(): + kb.safeReq.post = post + else: + kb.safeReq.post = None else: - conf.safeUrl = "http://" + conf.safeUrl + errMsg = "invalid format of a safe request file" + raise SqlmapSyntaxException, errMsg + else: + if not re.search("^http[s]*://", conf.safeUrl): + if ":443/" in conf.safeUrl: + conf.safeUrl = "https://" + conf.safeUrl + else: + conf.safeUrl = "http://" + conf.safeUrl if conf.safeFreq <= 0: - errMsg = "please provide a valid value (>0) for safe frequency (--safe-freq) while using safe URL feature" + errMsg = "please provide a valid value (>0) for safe frequency (--safe-freq) while using safe visit features" raise SqlmapSyntaxException(errMsg) def _setPrefixSuffix(): @@ -1791,6 +1833,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.responseTimes = [] kb.resumeValues = True kb.safeCharEncode = False + kb.safeReq = AttribDict() kb.singleLogFlags = set() kb.reduceTests = None kb.stickyDBMS = False @@ -2265,8 +2308,12 @@ def _basicOptionValidation(): errMsg = "option '--safe-post' requires usage of option '--safe-url'" raise SqlmapSyntaxException(errMsg) - if conf.safeFreq and not conf.safeUrl: - errMsg = "option '--safe-freq' requires usage of option '--safe-url'" + if conf.safeFreq and not any((conf.safeUrl, conf.safeReqFile)): + errMsg = "option '--safe-freq' requires usage of option '--safe-url' or '--safe-req'" + raise SqlmapSyntaxException(errMsg) + + if conf.safeReqFile and any((conf.safeUrl, conf.safePost)): + errMsg = "option '--safe-req' is incompatible with option '--safe-url' and option '--safe-post'" raise SqlmapSyntaxException(errMsg) if conf.csrfUrl and not conf.csrfToken: @@ -2416,7 +2463,7 @@ def init(): _setHTTPAuthentication() _setHTTPProxy() _setDNSCache() - _setSafeUrl() + _setSafeVisit() _setGoogleDorking() _setBulkMultipleTargets() _setSitemapTargets() diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index da71e84c1..3fbc3de47 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -52,6 +52,7 @@ optDict = { "rParam": "string", "safeUrl": "string", "safePost": "string", + "safeReqFile": "string", "safeFreq": "integer", "skipUrlEncode": "boolean", "csrfToken": "string", diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 9a9787adb..d252fe4fa 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -191,6 +191,9 @@ def cmdLineParser(): request.add_option("--safe-post", dest="safePost", help="POST data to send to a safe URL") + request.add_option("--safe-req", dest="safeReqFile", + help="Load safe HTTP request from a file") + request.add_option("--safe-freq", dest="safeFreq", type="int", help="Test requests between two visits to a given safe URL") diff --git a/lib/request/connect.py b/lib/request/connect.py index 3321b9d85..71f50e16a 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -971,10 +971,13 @@ class Connect(object): warnMsg += "10 or more)" logger.critical(warnMsg) - if conf.safeUrl and conf.safeFreq > 0: + if conf.safeFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.safeFreq == 0: - Connect.getPage(url=conf.safeUrl, post=conf.safePost, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) + if conf.safeUrl: + Connect.getPage(url=conf.safeUrl, post=conf.safePost, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) + elif kb.safeReq: + Connect.getPage(url=kb.safeReq.url, post=kb.safeReq.post, method=kb.safeReq.method, auxHeaders=kb.safeReq.headers) start = time.time() diff --git a/sqlmap.conf b/sqlmap.conf index 498c3d3e8..7f9e3d5f4 100644 --- a/sqlmap.conf +++ b/sqlmap.conf @@ -156,6 +156,9 @@ safeUrl = # Example: username=admin&password=passw0rd! safePost = +# Load safe HTTP request from a file. +safeReqFile = + # Test requests between two visits to a given safe URL (default 0). # Valid: integer # Default: 0