def _analysis_post(self): post_data = unquote(self._body) if re.search( '([^=]+)=([^%s]+%s?)' % (DEFAULT_GET_POST_DELIMITER, DEFAULT_GET_POST_DELIMITER), post_data): self._post_hint = POST_HINT.NORMAL self._post_data = paramToDict(post_data, place=PLACE.POST, hint=self._post_hint) elif re.search(JSON_RECOGNITION_REGEX, post_data): self._post_hint = POST_HINT.JSON elif re.search(XML_RECOGNITION_REGEX, post_data): self._post_hint = POST_HINT.XML elif re.search(JSON_LIKE_RECOGNITION_REGEX, post_data): self._post_hint = POST_HINT.JSON_LIKE elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, post_data): self._post_hint = POST_HINT.ARRAY_LIKE self._post_data = paramToDict(post_data, place=PLACE.POST, hint=self.post_hint) elif re.search(MULTIPART_RECOGNITION_REGEX, post_data): self._post_hint = POST_HINT.MULTIPART
def _build(self): p = self._urlparse port = 80 if p.scheme == "https": port = 443 self._https = True hostname = p.netloc if ":" in p.netloc: try: hostname, port = p.netloc.split(":") port = int(port) except: hostname = p.netloc port = 80 self._hostname = hostname self._port = port if self._method == HTTPMETHOD.POST: # 分析post数据类型 self._analysis_post() self._uri = p.path if p.query: self._uri = p.path + "?" + p.query self._params = paramToDict(p.query, place=PLACE.GET) self._netloc = "{}://{}{}".format(p.scheme, p.netloc, p.path) if "cookie" in self._headers or "Cookie" in self._headers: _cookies = self._headers.get("cookie", self._headers.get("Cookie", {})) if _cookies: self._cookies = paramToDict(_cookies, place=PLACE.COOKIE)
def _check_key(self): keys = [ 'kPH+bIxk5D2deZiIxcaaaA==', '4AvVhmFLUs0KTA3Kprsdag==', 'WkhBTkdYSUFPSEVJX0NBVA==', 'RVZBTk5JR0hUTFlfV0FPVQ==', 'U3ByaW5nQmxhZGUAAAAAAA==', 'cGljYXMAAAAAAAAAAAAAAA==', 'd2ViUmVtZW1iZXJNZUtleQ==', 'fsHspZw/92PrS3XrPW+vxw==', 'sHdIjUN6tzhl8xZMG3ULCQ==', 'WuB+y2gcHRnY2Lg9+Aqmqg==', 'ertVhmFLUs0KTA3Kprsdag==', '2itfW92XazYRi5ltW0M2yA==', '6ZmI6I2j3Y+R1aSn5BOlAA==', 'f/SY5TIve5WWzT4aQlABJA==', 'Jt3C93kMR9D5e8QzwfsiMw==', 'aU1pcmFjbGVpTWlyYWNsZQ==', ] for key in keys: payload = self.generator_payload(key) reqHeader = self.requests.headers if "Cookie" not in reqHeader: reqHeader["Cookie"] = "" _cookie = paramToDict(reqHeader["Cookie"], place=PLACE.COOKIE) _cookie["rememberMe"] = payload reqHeader["Cookie"] = url_dict2str(_cookie, PLACE.COOKIE) req = None if self.requests.method == HTTPMETHOD.GET: req = requests.get(self.requests.url, headers=reqHeader) elif self.requests.method == HTTPMETHOD.POST: req = requests.post(self.requests.url, data=self.requests.post_data, headers=reqHeader) if req and "deleteMe" not in req.headers.get('Set-Cookie', ''): result = ResultObject(self) result.init_info(self.requests.url, "Shiro Key发现", VulType.CMD_INNJECTION) result.add_detail("payload探测", req.reqinfo, generateResponse(req), "Cookie中rememberMe可以被反序列化", "rememberMe", payload, PLACE.COOKIE) self.success(result) return True return False
def audit(self): respHeader = self.response.headers isShiro = False if "deleteMe" in respHeader.get('Set-Cookie', ''): isShiro = True result = ResultObject(self) result.init_info(self.requests.url, "Shiro框架发现", VulType.BASELINE) result.add_detail("payload探测", self.requests.raw, self.response.raw, "在返回的cookie中发现了deleteMe标记", "", "", PLACE.GET) self.success(result) if WEB_PLATFORM.JAVA not in self.response.programing and conf.level < 2 and not isShiro: return if not isShiro: # 如果不是shiro框架,检测一下 reqHeader = self.requests.headers if "Cookie" not in reqHeader: reqHeader["Cookie"] = "" _cookie = paramToDict(reqHeader["Cookie"], place=PLACE.COOKIE) _cookie["rememberMe"] = "2" reqHeader["Cookie"] = url_dict2str(_cookie, PLACE.COOKIE) req = None if self.requests.method == HTTPMETHOD.GET: req = requests.get(self.requests.url, headers=reqHeader) elif self.requests.method == HTTPMETHOD.POST: req = requests.post(self.requests.url, data=self.requests.post_data, headers=reqHeader) if req and "deleteMe" in req.headers.get('Set-Cookie', ''): isShiro = True result = ResultObject(self) result.init_info(self.requests.url, "Shiro框架发现", VulType.BASELINE) result.add_detail( "payload探测", req.reqinfo, generateResponse(req), "在cookie中加入rememberMe=1,在返回cookie发现了deleteMe标记,可尝试爆破shiro的key", "", "", PLACE.GET) self.success(result) # 爆破 if isShiro: self._check_key()
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: if hasattr(conf.data, UNENCODED_ORIGINAL_VALUE): original = getattr(conf.data, UNENCODED_ORIGINAL_VALUE) setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original) place = PLACE.SOAP if re.match(SOAP_REGEX, conf.data, re.I | re.M) else PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True conf.method = HTTPMETHOD.POST if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(map(lambda place: place in conf.parameters, [PLACE.GET, PLACE.POST])): warnMsg = "you've provided target url without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target url itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True elif test[0] in ("q", "Q"): raise sqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data)): if CUSTOM_INJECTION_MARK_CHAR in (value or ""): if kb.processUserMarks is None: message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data'}[place] test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise sqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if not kb.processUserMarks: continue conf.parameters[place] = value conf.paramDict[place] = {} parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place]["#%d%s" % (i + 1, CUSTOM_INJECTION_MARK_CHAR)] = "".join("%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: conf.url = conf.url.replace(CUSTOM_INJECTION_MARK_CHAR, "") conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, "") if conf.data else conf.data # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value httpHeader = httpHeader.title() 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.USER_AGENT] = {PLACE.USER_AGENT: headerValue} testableParameters = True elif httpHeader == HTTPHEADER.REFERER: conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES))) if condition: conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue} testableParameters = True elif httpHeader == HTTPHEADER.HOST: conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise sqlmapGenericException, errMsg elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg
def start(): """ This function calls a function that performs checks on both URL stability and all GET, POST, Cookie and User-Agent parameters to check if they are dynamic and SQL injection affected """ if not conf.start: return False if conf.direct: initTargetEnv() setupTargetEnv() action() return True if conf.url and not conf.forms: kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie )) if conf.configFile and not kb.targetUrls: errMsg = "you did not edit the configuration file properly, set " errMsg += "the target url, list of targets or google dork" logger.error(errMsg) return False if kb.targetUrls and len(kb.targetUrls) > 1: infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls) logger.info(infoMsg) hostCount = 0 cookieStr = "" setCookieAsInjectable = True for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls: try: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie injData = [] initTargetEnv() parseTargetUrl() testSqlInj = False if PLACE.GET in conf.parameters: for parameter in re.findall(r"([^=]+)=[^&]+&?", conf.parameters[PLACE.GET]): paramKey = (conf.hostname, conf.path, PLACE.GET, parameter) if paramKey not in kb.testedParams: testSqlInj = True break else: paramKey = (conf.hostname, conf.path, None, None) if paramKey not in kb.testedParams: testSqlInj = True if not testSqlInj: infoMsg = "skipping '%s'" % targetUrl logger.info(infoMsg) continue if conf.multipleTargets: hostCount += 1 if conf.forms: name = kb.formNames[(targetUrl, targetMethod, targetData, targetCookie)] message = "[#%d] %s:\n%s %s" % (hostCount, "form%s" % (" '%s'" % name if name else ""), conf.method or HTTPMETHOD.GET, targetUrl) else: message = "%s %d:\n%s %s" % ("url", hostCount, conf.method or HTTPMETHOD.GET, targetUrl) if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data: message += "\nPOST data: %s" % repr(conf.data) if conf.data else "" if conf.forms: if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1: continue message += "\ndo you want to test this form? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): if conf.method == HTTPMETHOD.POST: message = "Edit POST data [default: %s]: " % (conf.data if conf.data else "") conf.data = readInput(message, default=conf.data) elif conf.method == HTTPMETHOD.GET: if conf.url.find("?") > -1: firstPart = conf.url[:conf.url.find("?")] secondPart = conf.url[conf.url.find("?")+1:] message = "Edit GET data [default: %s]: " % secondPart test = readInput(message, default=secondPart) conf.url = "%s?%s" % (firstPart, test) elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break else: message += "\ndo you want to test this url? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break logMsg = "testing url %s" % targetUrl logger.info(logMsg) setupTargetEnv() if not checkConnection(conf.forms) or not checkString() or not checkRegexp(): continue if conf.nullConnection: checkNullConnection() if not conf.dropSetCookie and conf.cj: for _, cookie in enumerate(conf.cj): cookie = getUnicode(cookie) index = cookie.index(" for ") cookieStr += "%s;" % cookie[8:index] if cookieStr: cookieStr = cookieStr[:-1] if PLACE.COOKIE in conf.parameters: message = "you provided an HTTP Cookie header value. " message += "The target url provided its own Cookie within " message += "the HTTP Set-Cookie header. Do you want to " message += "continue using the HTTP Cookie values that " message += "you provided? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): setCookieAsInjectable = False if setCookieAsInjectable: conf.httpHeaders.append(("Cookie", cookieStr)) conf.parameters[PLACE.COOKIE] = cookieStr __paramDict = paramToDict(PLACE.COOKIE, cookieStr) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict # TODO: consider the following line in __setRequestParams() __testableParameters = True if not kb.injPlace or not kb.injParameter or not kb.injType: if not conf.string and not conf.regexp and not conf.eRegexp: # NOTE: this is not needed anymore, leaving only to display # a warning message to the user in case the page is not stable checkStability() # Do a little prioritization reorder of a testable parameter list parameters = conf.parameters.keys() for place in (PLACE.URI, PLACE.POST, PLACE.GET): if place in parameters: parameters.remove(place) parameters.insert(0, place) for place in parameters: if not conf.paramDict.has_key(place): continue paramDict = conf.paramDict[place] for parameter, value in paramDict.items(): testSqlInj = True paramKey = (conf.hostname, conf.path, place, parameter) if paramKey in kb.testedParams: testSqlInj = False infoMsg = "skipping previously processed %s parameter '%s'" % (place, parameter) logger.info(infoMsg) # Avoid dinamicity test if the user provided the # parameter manually elif parameter in conf.testParameter: pass elif not checkDynParam(place, parameter, value): warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter) logger.warn(warnMsg) testSqlInj = False else: logMsg = "%s parameter '%s' is dynamic" % (place, parameter) logger.info(logMsg) kb.testedParams.add(paramKey) if testSqlInj: heuristicCheckSqlInjection(place, parameter, value) for parenthesis in range(0, 4): logMsg = "testing sql injection on %s " % place logMsg += "parameter '%s' with " % parameter logMsg += "%d parenthesis" % parenthesis logger.info(logMsg) injType = checkSqlInjection(place, parameter, value, parenthesis) if injType: injData.append((place, parameter, injType)) break else: infoMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg += "injectable with %d parenthesis" % parenthesis logger.info(infoMsg) if not injData: warnMsg = "%s parameter '%s' is not " % (place, parameter) warnMsg += "injectable" logger.warn(warnMsg) if not kb.injPlace or not kb.injParameter or not kb.injType: if len(injData) == 1: injDataSelected = injData[0] elif len(injData) > 1: injDataSelected = __selectInjection(injData) else: raise sqlmapNotVulnerableException, "all parameters are not injectable" if injDataSelected == "Quit": return else: kb.injPlace, kb.injParameter, kb.injType = injDataSelected setInjection() if kb.injPlace and kb.injParameter and kb.injType: if conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " exploit = readInput(message, default="Y") condition = not exploit or exploit[0] in ("y", "Y") else: condition = True if condition: if kb.paramMatchRatio: conf.matchRatio = kb.paramMatchRatio[(kb.injPlace, kb.injParameter)] setMatchRatio() checkForParenthesis() action() except KeyboardInterrupt: if conf.multipleTargets: warnMsg = "Ctrl+C detected in multiple target mode" logger.warn(warnMsg) message = "do you want to skip to the next target in list? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): return False elif test[0] in ("q", "Q"): raise sqlmapUserQuitException else: raise except sqlmapUserQuitException: raise except sqlmapSilentQuitException: raise except exceptionsTuple, e: e = getUnicode(e) if conf.multipleTargets: e += ", skipping to the next %s" % ("form" if conf.forms else "url") logger.error(e) else: logger.critical(e) return False
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return __testableParameters = False # Perform checks on GET parameters if conf.parameters.has_key(PLACE.GET) and conf.parameters[PLACE.GET]: parameters = conf.parameters[PLACE.GET] __paramDict = paramToDict(PLACE.GET, parameters) if __paramDict: conf.paramDict[PLACE.GET] = __paramDict __testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: if hasattr(conf.data, UNENCODED_ORIGINAL_VALUE): original = getattr(conf.data, UNENCODED_ORIGINAL_VALUE) conf.data = type(conf.data)(conf.data.replace("\n", " ")) setattr(conf.data, UNENCODED_ORIGINAL_VALUE, original) else: conf.data = conf.data.replace("\n", " ") # Check if POST data is in xml syntax if re.match(SOAP_REGEX, conf.data, re.I | re.M): place = PLACE.SOAP else: place = PLACE.POST conf.parameters[place] = conf.data __paramDict = paramToDict(place, conf.data) if __paramDict: conf.paramDict[place] = __paramDict __testableParameters = True conf.method = HTTPMETHOD.POST if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(map(lambda place: place in conf.parameters, [PLACE.GET, PLACE.POST])): warnMsg = "you've provided target url without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target url itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): conf.url = "%s%s" % (conf.url, URI_INJECTION_MARK_CHAR) elif test[0] in ("n", "N"): pass elif test[0] in ("q", "Q"): raise sqlmapUserQuitException if URI_INJECTION_MARK_CHAR in conf.url: conf.parameters[PLACE.URI] = conf.url conf.paramDict[PLACE.URI] = {} parts = conf.url.split(URI_INJECTION_MARK_CHAR) for i in xrange(len(parts)-1): result = str() for j in xrange(len(parts)): result += parts[j] if i == j: result += URI_INJECTION_MARK_CHAR conf.paramDict[PLACE.URI]["#%d%s" % (i+1, URI_INJECTION_MARK_CHAR)] = result conf.url = conf.url.replace(URI_INJECTION_MARK_CHAR, str()) __testableParameters = True # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie __paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict __testableParameters = True # Perform checks on User-Agent header value if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: if httpHeader == PLACE.UA: # No need for url encoding/decoding the user agent conf.parameters[PLACE.UA] = urldecode(headerValue) condition = any([not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES)]) if condition: conf.paramDict[PLACE.UA] = { PLACE.UA: headerValue } __testableParameters = True elif httpHeader == PLACE.REFERER: # No need for url encoding/decoding the referer conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any([not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES)]) if condition: conf.paramDict[PLACE.REFERER] = { PLACE.REFERER: headerValue } __testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent or Referer header" raise sqlmapGenericException, errMsg elif not __testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg
def start(): """ This function calls a function that performs checks on both URL stability and all GET, POST, Cookie and User-Agent parameters to check if they are dynamic and SQL injection affected """ if not conf.start: return False if conf.direct: initTargetEnv() setupTargetEnv() action() return True if conf.url and not conf.forms: kb.targetUrls.add((conf.url, conf.method, conf.data, conf.cookie)) if conf.configFile and not kb.targetUrls: errMsg = "you did not edit the configuration file properly, set " errMsg += "the target url, list of targets or google dork" logger.error(errMsg) return False if kb.targetUrls and len(kb.targetUrls) > 1: infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls) logger.info(infoMsg) hostCount = 0 cookieStr = "" setCookieAsInjectable = True for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls: try: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie initTargetEnv() parseTargetUrl() testSqlInj = False if PLACE.GET in conf.parameters: for parameter in re.findall(r"([^=]+)=[^&]+&?", conf.parameters[PLACE.GET]): paramKey = (conf.hostname, conf.path, PLACE.GET, parameter) if paramKey not in kb.testedParams: testSqlInj = True break else: paramKey = (conf.hostname, conf.path, None, None) if paramKey not in kb.testedParams: testSqlInj = True testSqlInj &= (conf.hostname, conf.path, None, None) not in kb.testedParams if not testSqlInj: infoMsg = "skipping '%s'" % targetUrl logger.info(infoMsg) continue if conf.multipleTargets: hostCount += 1 if conf.forms: message = "[#%d] form:\n%s %s" % ( hostCount, conf.method or HTTPMETHOD.GET, targetUrl) else: message = "url %d:\n%s %s%s" % ( hostCount, conf.method or HTTPMETHOD.GET, targetUrl, " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "") if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data: message += "\nPOST data: %s" % urlencode( conf.data) if conf.data else "" if conf.forms: if conf.method == HTTPMETHOD.GET and targetUrl.find( "?") == -1: continue message += "\ndo you want to test this form? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): if conf.method == HTTPMETHOD.POST: message = "Edit POST data [default: %s]%s: " % ( urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult( EMPTY_FORM_FIELDS_REGEX, conf.data) else "") conf.data = readInput(message, default=conf.data) if extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data): message = "do you want to fill blank fields with random values? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): while extractRegexResult( EMPTY_FORM_FIELDS_REGEX, conf.data): item = extractRegexResult( EMPTY_FORM_FIELDS_REGEX, conf.data) if item[-1] == '&': conf.data = conf.data.replace( item, "%s%s&" % (item[:-1], randomStr())) else: conf.data = conf.data.replace( item, "%s%s" % (item, randomStr())) conf.data = urldecode(conf.data) elif conf.method == HTTPMETHOD.GET: if conf.url.find("?") > -1: firstPart = conf.url[:conf.url.find("?")] secondPart = conf.url[conf.url.find("?") + 1:] message = "Edit GET data [default: %s]: " % secondPart test = readInput(message, default=secondPart) conf.url = "%s?%s" % (firstPart, test) elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break elif conf.realTest: logger.info(message) else: message += "\ndo you want to test this url? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break logMsg = "testing url %s" % targetUrl logger.info(logMsg) setupTargetEnv() if not checkConnection(suppressOutput=conf.forms ) or not checkString() or not checkRegexp(): continue if conf.nullConnection: checkNullConnection() if not conf.dropSetCookie and conf.cj: for _, cookie in enumerate(conf.cj): cookie = getUnicode(cookie) index = cookie.index(" for ") cookieStr += "%s;" % cookie[8:index] if cookieStr: cookieStr = cookieStr[:-1] if PLACE.COOKIE in conf.parameters: message = "you provided an HTTP Cookie header value. " message += "The target url provided its own Cookie within " message += "the HTTP Set-Cookie header. Do you want to " message += "continue using the HTTP Cookie values that " message += "you provided? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): setCookieAsInjectable = False if setCookieAsInjectable: conf.httpHeaders.append(("Cookie", cookieStr)) conf.parameters[PLACE.COOKIE] = cookieStr __paramDict = paramToDict(PLACE.COOKIE, cookieStr) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict # TODO: consider the following line in __setRequestParams() # __testableParameters = True 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: # NOTE: this is not needed anymore, leaving only to display # a warning message to the user in case the page is not stable checkStability() # Do a little prioritization reorder of a testable parameter list parameters = conf.parameters.keys() # Order of testing list (last to first) orderList = (PLACE.URI, PLACE.GET, PLACE.POST) for place in orderList: if place in parameters: parameters.remove(place) parameters.insert(0, place) proceed = True 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.REFERER and conf.level < 3) # Test Cookie header only if --level >= 2 skip |= (place == PLACE.COOKIE and conf.level < 2) skip &= not (place == PLACE.UA and intersect( USER_AGENT_ALIASES, conf.testParameter)) skip &= not (place == PLACE.REFERER and intersect( REFERER_ALIASES, conf.testParameter)) if skip: continue if not conf.paramDict.has_key(place): continue paramDict = conf.paramDict[place] for parameter, value in paramDict.items(): if not proceed: break testSqlInj = True paramKey = (conf.hostname, conf.path, place, parameter) if paramKey in kb.testedParams: testSqlInj = False infoMsg = "skipping previously processed %s parameter '%s'" % ( place, parameter) logger.info(infoMsg) # Avoid dinamicity test if the user provided the # parameter manually elif parameter in conf.testParameter or conf.realTest: pass elif not checkDynParam(place, parameter, value): warnMsg = "%s parameter '%s' is not dynamic" % ( place, parameter) logger.warn(warnMsg) else: logMsg = "%s parameter '%s' is dynamic" % ( place, parameter) logger.info(logMsg) kb.testedParams.add(paramKey) if testSqlInj: check = heuristicCheckSqlInjection( place, parameter) if not check and conf.realTest and\ not simpletonCheckSqlInjection(place, parameter, value): continue logMsg = "testing sql injection on %s " % place logMsg += "parameter '%s'" % parameter logger.info(logMsg) injection = checkSqlInjection( place, parameter, value) proceed = not kb.endDetection if injection is not None and injection.place is not None: kb.injections.append(injection) # In case when user wants to end detection phase (Ctrl+C) if not proceed: break msg = "%s parameter '%s' " % ( injection.place, injection.parameter) msg += "is vulnerable. Do you want to keep testing the others? [y/N] " test = readInput(msg, default="N") if test[0] in ("n", "N"): proceed = False paramKey = (conf.hostname, conf.path, None, None) kb.testedParams.add(paramKey) else: warnMsg = "%s parameter '%s' is not " % ( place, parameter) warnMsg += "injectable" logger.warn(warnMsg) if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None): if not conf.realTest: errMsg = "all parameters are not injectable, try to " errMsg += "increase --level/--risk values to perform " errMsg += "more tests." if isinstance(conf.tech, list) and len(conf.tech) > 0: errMsg += " Rerun without providing the --technique switch." if not conf.textOnly and kb.originalPage: percent = ( 100.0 * len(getFilteredPageContent(kb.originalPage)) / len(kb.originalPage)) errMsg += " Give it a go with the --text-only switch " errMsg += "if the target page has a low percentage of " errMsg += "textual content (~%.2f%% of " % percent errMsg += "page content is text)" raise sqlmapNotVulnerableException, errMsg else: errMsg = "it seems that all parameters are not injectable" raise sqlmapNotVulnerableException, errMsg else: # Flush the flag kb.testMode = False __saveToSessionFile() __showInjections() __selectInjection() if kb.injection.place is not None and kb.injection.parameter is not None: if kb.testQueryCount == 0 and conf.realTest: condition = False elif conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " exploit = readInput(message, default="Y") condition = not exploit or exploit[0] in ("y", "Y") else: condition = True if condition: action() except KeyboardInterrupt: if conf.multipleTargets: warnMsg = "user aborted in multiple target mode" logger.warn(warnMsg) message = "do you want to skip to the next target in list? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): return False elif test[0] in ("q", "Q"): raise sqlmapUserQuitException else: raise except sqlmapUserQuitException: raise except sqlmapSilentQuitException: raise except exceptionsTuple, e: e = getUnicode(e) if conf.multipleTargets: e += ", skipping to the next %s" % ("form" if conf.forms else "url") logger.error(e) else: logger.critical(e) return False finally:
def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise SqlmapSyntaxException, errMsg if conf.data is not None: conf.method = HTTPMETHOD.POST if CUSTOM_INJECTION_MARK_CHAR in conf.data: # later processed pass elif re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = re.sub(r'("[^"]+"\s*:\s*"[^"]+)"', r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR, conf.data) conf.data = re.sub( r'("[^"]+"\s*:\s*)(-?\d[\d\.]*\b)', r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR, conf.data ) kb.postHint = POST_HINT.JSON elif re.search(SOAP_RECOGNITION_REGEX, conf.data): message = "SOAP/XML like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = re.sub( r"(<([^>]+)( [^<]*)?>)([^<]+)(</\2)", r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR, conf.data ) kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = re.sub( r"(?si)(Content-Disposition.+?)((\r)?\n--)", r"\g<1>%s\g<2>" % CUSTOM_INJECTION_MARK_CHAR, conf.data ) kb.postHint = POST_HINT.MULTIPART else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True kb.processUserMarks = True if kb.postHint else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any( map(lambda place: place in conf.parameters, [PLACE.GET, PLACE.POST]) ): warnMsg = "you've provided target url without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target url itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True elif test[0] in ("q", "Q"): raise SqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data)): if CUSTOM_INJECTION_MARK_CHAR in (value or ""): if kb.processUserMarks is None: _ = {PLACE.URI: "-u", PLACE.CUSTOM_POST: "--data"} message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % _[place] test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value)[3] if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split("?")[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True continue conf.parameters[place] = value conf.paramDict[place] = OrderedDict() parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place][ "%s#%d%s" % (("%s " % kb.postHint) if kb.postHint else "", i + 1, CUSTOM_INJECTION_MARK_CHAR) ] = "".join( "%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts)) ) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: conf.url = conf.url.replace(CUSTOM_INJECTION_MARK_CHAR, "") conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, "") if conf.data else conf.data # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value httpHeader = httpHeader.title() 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.USER_AGENT] = {PLACE.USER_AGENT: headerValue} testableParameters = True elif httpHeader == HTTPHEADER.REFERER: conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES))) if condition: conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue} testableParameters = True elif httpHeader == HTTPHEADER.HOST: conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException, errMsg elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise SqlmapGenericException, errMsg
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return __testableParameters = False # Perform checks on GET parameters if conf.parameters.has_key(PLACE.GET) and conf.parameters[PLACE.GET]: parameters = conf.parameters[PLACE.GET] __paramDict = paramToDict(PLACE.GET, parameters) if __paramDict: conf.paramDict[PLACE.GET] = __paramDict __testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: conf.data = conf.data.replace("\n", " ") conf.parameters[PLACE.POST] = conf.data # Check if POST data is in xml syntax if re.match("[\n]*<(\?xml |soap\:|ns).*>", conf.data): conf.paramDict["POSTxml"] = True __paramDict = paramToDict("POSTxml", conf.data) else: __paramDict = paramToDict(PLACE.POST, conf.data) if __paramDict: conf.paramDict[PLACE.POST] = __paramDict __testableParameters = True conf.method = HTTPMETHOD.POST if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not conf.parameters.has_key(PLACE.GET): conf.url = "%s%s" % (conf.url, URI_INJECTION_MARK_CHAR) if URI_INJECTION_MARK_CHAR in conf.url: conf.parameters[PLACE.URI] = conf.url conf.paramDict[PLACE.URI] = {} parts = conf.url.split(URI_INJECTION_MARK_CHAR) for i in range(len(parts) - 1): result = str() for j in range(len(parts)): result += parts[j] if i == j: result += URI_INJECTION_MARK_CHAR conf.paramDict[PLACE.URI]["#%d%s" % (i + 1, URI_INJECTION_MARK_CHAR)] = result conf.url = conf.url.replace(URI_INJECTION_MARK_CHAR, str()) __testableParameters = True # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie __paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict __testableParameters = True # Perform checks on User-Agent header value if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: if httpHeader == PLACE.UA: # No need for url encoding/decoding the user agent conf.parameters[PLACE.UA] = urldecode(headerValue) condition = any([ not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES) ]) if condition: conf.paramDict[PLACE.UA] = {PLACE.UA: headerValue} __testableParameters = True elif httpHeader == PLACE.REFERER: # No need for url encoding/decoding the referer conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any([ not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES) ]) if condition: conf.paramDict[PLACE.REFERER] = { PLACE.REFERER: headerValue } __testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent or Referer header" raise sqlmapGenericException, errMsg elif not __testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg
def start(): """ This function calls a function that performs checks on both URL stability and all GET, POST, Cookie and User-Agent parameters to check if they are dynamic and SQL injection affected """ if not conf.start: return False if conf.direct: initTargetEnv() setupTargetEnv() action() return True if conf.url and not conf.forms: kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie )) if conf.configFile and not kb.targetUrls: errMsg = "you did not edit the configuration file properly, set " errMsg += "the target url, list of targets or google dork" logger.error(errMsg) return False if kb.targetUrls and len(kb.targetUrls) > 1: infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls) logger.info(infoMsg) hostCount = 0 cookieStr = "" setCookieAsInjectable = True for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls: try: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie initTargetEnv() parseTargetUrl() testSqlInj = False if PLACE.GET in conf.parameters: for parameter in re.findall(r"([^=]+)=[^&]+&?", conf.parameters[PLACE.GET]): paramKey = (conf.hostname, conf.path, PLACE.GET, parameter) if paramKey not in kb.testedParams: testSqlInj = True break else: paramKey = (conf.hostname, conf.path, None, None) if paramKey not in kb.testedParams: testSqlInj = True testSqlInj &= (conf.hostname, conf.path, None, None) not in kb.testedParams if not testSqlInj: infoMsg = "skipping '%s'" % targetUrl logger.info(infoMsg) continue if conf.multipleTargets: hostCount += 1 if conf.forms: message = "[#%d] form:\n%s %s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl) else: message = "url %d:\n%s %s%s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl, " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "") if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data: message += "\nPOST data: %s" % urlencode(conf.data) if conf.data else "" if conf.forms: if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1: continue message += "\ndo you want to test this form? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): if conf.method == HTTPMETHOD.POST: message = "Edit POST data [default: %s]%s: " % (urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "") conf.data = readInput(message, default=conf.data) if extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data): message = "do you want to fill blank fields with random values? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): while extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data): item = extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) if item[-1] == '&': conf.data = conf.data.replace(item, "%s%s&" % (item[:-1], randomStr())) else: conf.data = conf.data.replace(item, "%s%s" % (item, randomStr())) conf.data = urldecode(conf.data) elif conf.method == HTTPMETHOD.GET: if conf.url.find("?") > -1: firstPart = conf.url[:conf.url.find("?")] secondPart = conf.url[conf.url.find("?")+1:] message = "Edit GET data [default: %s]: " % secondPart test = readInput(message, default=secondPart) conf.url = "%s?%s" % (firstPart, test) elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break elif conf.realTest: logger.info(message) else: message += "\ndo you want to test this url? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break logMsg = "testing url %s" % targetUrl logger.info(logMsg) setupTargetEnv() if not checkConnection(suppressOutput=conf.forms) or not checkString() or not checkRegexp(): continue if conf.nullConnection: checkNullConnection() if not conf.dropSetCookie and conf.cj: for _, cookie in enumerate(conf.cj): cookie = getUnicode(cookie) index = cookie.index(" for ") cookieStr += "%s;" % cookie[8:index] if cookieStr: cookieStr = cookieStr[:-1] if PLACE.COOKIE in conf.parameters: message = "you provided an HTTP Cookie header value. " message += "The target url provided its own Cookie within " message += "the HTTP Set-Cookie header. Do you want to " message += "continue using the HTTP Cookie values that " message += "you provided? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): setCookieAsInjectable = False if setCookieAsInjectable: conf.httpHeaders.append(("Cookie", cookieStr)) conf.parameters[PLACE.COOKIE] = cookieStr __paramDict = paramToDict(PLACE.COOKIE, cookieStr) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict # TODO: consider the following line in __setRequestParams() # __testableParameters = True 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: # NOTE: this is not needed anymore, leaving only to display # a warning message to the user in case the page is not stable checkStability() # Do a little prioritization reorder of a testable parameter list parameters = conf.parameters.keys() # Order of testing list (last to first) orderList = (PLACE.URI, PLACE.GET, PLACE.POST) for place in orderList: if place in parameters: parameters.remove(place) parameters.insert(0, place) proceed = True 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.REFERER and conf.level < 3) # Test Cookie header only if --level >= 2 skip |= (place == PLACE.COOKIE and conf.level < 2) skip &= not (place == PLACE.UA and intersect(USER_AGENT_ALIASES, conf.testParameter)) skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter)) if skip: continue if not conf.paramDict.has_key(place): continue paramDict = conf.paramDict[place] for parameter, value in paramDict.items(): if not proceed: break testSqlInj = True paramKey = (conf.hostname, conf.path, place, parameter) if paramKey in kb.testedParams: testSqlInj = False infoMsg = "skipping previously processed %s parameter '%s'" % (place, parameter) logger.info(infoMsg) # Avoid dinamicity test if the user provided the # parameter manually elif parameter in conf.testParameter or conf.realTest: pass elif not checkDynParam(place, parameter, value): warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter) logger.warn(warnMsg) else: logMsg = "%s parameter '%s' is dynamic" % (place, parameter) logger.info(logMsg) kb.testedParams.add(paramKey) if testSqlInj: check = heuristicCheckSqlInjection(place, parameter) if not check and conf.realTest and\ not simpletonCheckSqlInjection(place, parameter, value): continue logMsg = "testing sql injection on %s " % place logMsg += "parameter '%s'" % parameter logger.info(logMsg) injection = checkSqlInjection(place, parameter, value) proceed = not kb.endDetection if injection is not None and injection.place is not None: kb.injections.append(injection) # In case when user wants to end detection phase (Ctrl+C) if not proceed: break msg = "%s parameter '%s' " % (injection.place, injection.parameter) msg += "is vulnerable. Do you want to keep testing the others? [y/N] " test = readInput(msg, default="N") if test[0] in ("n", "N"): proceed = False paramKey = (conf.hostname, conf.path, None, None) kb.testedParams.add(paramKey) else: warnMsg = "%s parameter '%s' is not " % (place, parameter) warnMsg += "injectable" logger.warn(warnMsg) if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None): if not conf.realTest: errMsg = "all parameters are not injectable, try to " errMsg += "increase --level/--risk values to perform " errMsg += "more tests." if isinstance(conf.tech, list) and len(conf.tech) > 0: errMsg += " Rerun without providing the --technique switch." if not conf.textOnly and kb.originalPage: percent = (100.0 * len(getFilteredPageContent(kb.originalPage)) / len(kb.originalPage)) errMsg += " Give it a go with the --text-only switch " errMsg += "if the target page has a low percentage of " errMsg += "textual content (~%.2f%% of " % percent errMsg += "page content is text)" raise sqlmapNotVulnerableException, errMsg else: errMsg = "it seems that all parameters are not injectable" raise sqlmapNotVulnerableException, errMsg else: # Flush the flag kb.testMode = False __saveToSessionFile() __showInjections() __selectInjection() if kb.injection.place is not None and kb.injection.parameter is not None: if kb.testQueryCount == 0 and conf.realTest: condition = False elif conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " exploit = readInput(message, default="Y") condition = not exploit or exploit[0] in ("y", "Y") else: condition = True if condition: action() except KeyboardInterrupt: if conf.multipleTargets: warnMsg = "user aborted in multiple target mode" logger.warn(warnMsg) message = "do you want to skip to the next target in list? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): return False elif test[0] in ("q", "Q"): raise sqlmapUserQuitException else: raise except sqlmapUserQuitException: raise except sqlmapSilentQuitException: raise except exceptionsTuple, e: e = getUnicode(e) if conf.multipleTargets: e += ", skipping to the next %s" % ("form" if conf.forms else "url") logger.error(e) else: logger.critical(e) return False finally:
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return __testableParameters = False # Perform checks on GET parameters if conf.parameters.has_key(PLACE.GET) and conf.parameters[PLACE.GET]: parameters = conf.parameters[PLACE.GET] __paramDict = paramToDict(PLACE.GET, parameters) if __paramDict: conf.paramDict[PLACE.GET] = __paramDict __testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: conf.data = conf.data.replace("\n", " ") conf.parameters[PLACE.POST] = conf.data # Check if POST data is in xml syntax if re.match("[\n]*<(\?xml |soap\:|ns).*>", conf.data): conf.paramDict["POSTxml"] = True __paramDict = paramToDict("POSTxml", conf.data) else: __paramDict = paramToDict(PLACE.POST, conf.data) if __paramDict: conf.paramDict[PLACE.POST] = __paramDict __testableParameters = True conf.method = HTTPMETHOD.POST if "*" in conf.url: conf.parameters[PLACE.URI] = conf.url conf.paramDict[PLACE.URI] = {} parts = conf.url.split("*") for i in range(len(parts)-1): result = str() for j in range(len(parts)): result += parts[j] if i == j: result += "*" conf.paramDict[PLACE.URI]["#%d*" % (i+1)] = result conf.url = conf.url.replace("*", str()) __testableParameters = True # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie __paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict __testableParameters = True # Perform checks on User-Agent header value if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: if httpHeader == PLACE.UA: # No need for url encoding/decoding the user agent conf.parameters[PLACE.UA] = headerValue condition = not conf.testParameter condition |= PLACE.UA in conf.testParameter condition |= "user-agent" in conf.testParameter condition |= "useragent" in conf.testParameter condition |= "ua" in conf.testParameter if condition: conf.paramDict[PLACE.UA] = { PLACE.UA: headerValue } __testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent header" raise sqlmapGenericException, errMsg elif not __testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg
def start(): """ This function calls a function that performs checks on both URL stability and all GET, POST, Cookie and User-Agent parameters to check if they are dynamic and SQL injection affected """ if conf.url: kb.targetUrls.add((conf.url, conf.method, conf.data, conf.cookie)) if conf.configFile and not kb.targetUrls: errMsg = "you did not edit the configuration file properly, set " errMsg += "the target url, list of targets or google dork" logger.error(errMsg) if kb.targetUrls and len(kb.targetUrls) > 1: infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls) logger.info(infoMsg) hostCount = 0 receivedCookies = [] cookieStr = "" setCookieAsInjectable = True for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie injData = [] if conf.multipleTargets: hostCount += 1 message = "url %d:\n%s %s" % (hostCount, conf.method or "GET", targetUrl) if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data: message += "\nPOST data: %s" % conf.data message += "\ndo you want to test this url? [Y/n/q] " test = readInput(message, default="Y") if not test: pass elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break logMsg = "testing url %s" % targetUrl logger.info(logMsg) initTargetEnv() if not checkConnection() or not checkString() or not checkRegexp(): continue for _, cookie in enumerate(conf.cj): cookie = str(cookie) index = cookie.index(" for ") cookieStr += "%s;" % cookie[8:index] if cookieStr: cookieStr = cookieStr[:-1] if "Cookie" in conf.parameters: message = "you provided an HTTP Cookie header value. " message += "The target url provided its own Cookie within " message += "the HTTP Set-Cookie header. Do you want to " message += "continue using the HTTP Cookie values that " message += "you provided? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): setCookieAsInjectable = False if setCookieAsInjectable: conf.httpHeaders.append(("Cookie", cookieStr)) conf.parameters["Cookie"] = cookieStr.replace("%", "%%") __paramDict = paramToDict("Cookie", cookieStr) if __paramDict: conf.paramDict["Cookie"] = __paramDict __testableParameters = True if not kb.injPlace or not kb.injParameter or not kb.injType: if not conf.string and not conf.regexp and not conf.eRegexp: if checkStability(): logMsg = "url is stable" logger.info(logMsg) else: errMsg = "url is not stable, try with --string or " errMsg += "--regexp options, refer to the user's manual " errMsg += "paragraph 'Page comparison' for details" if conf.multipleTargets: errMsg += ", skipping to next url" logger.warn(errMsg) continue else: raise sqlmapConnectionException, errMsg for place in conf.parameters.keys(): if not conf.paramDict.has_key(place): continue paramDict = conf.paramDict[place] for parameter, value in paramDict.items(): if not checkDynParam(place, parameter, value): warnMsg = "%s parameter '%s' is not dynamic" % ( place, parameter) logger.warn(warnMsg) else: logMsg = "%s parameter '%s' is dynamic" % (place, parameter) logger.info(logMsg) for parenthesis in range(0, 4): logMsg = "testing sql injection on %s " % place logMsg += "parameter '%s' with " % parameter logMsg += "%d parenthesis" % parenthesis logger.info(logMsg) injType = checkSqlInjection( place, parameter, value, parenthesis) if injType: injData.append((place, parameter, injType)) break else: infoMsg = "%s parameter '%s' is not " % ( place, parameter) infoMsg += "injectable with %d parenthesis" % parenthesis logger.info(infoMsg) if not injData: warnMsg = "%s parameter '%s' is not " % (place, parameter) warnMsg += "injectable" logger.warn(warnMsg) if not kb.injPlace or not kb.injParameter or not kb.injType: if len(injData) == 1: injDataSelected = injData[0] elif len(injData) > 1: injDataSelected = __selectInjection(injData) elif conf.multipleTargets: continue else: return if injDataSelected == "Quit": return else: kb.injPlace, kb.injParameter, kb.injType = injDataSelected setInjection() if not conf.multipleTargets and (not kb.injPlace or not kb.injParameter or not kb.injType): raise sqlmapNotVulnerableException, "all parameters are not injectable" elif kb.injPlace and kb.injParameter and kb.injType: condition = False if conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " exploit = readInput(message, default="Y") if not exploit or exploit[0] in ("y", "Y"): condition = True else: condition = True if condition: checkForParenthesis() createTargetDirs() action() if conf.loggedToOut: logger.info("Fetched data logged to text files under '%s'" % conf.outputPath)
def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise SqlmapSyntaxException(errMsg) if conf.data is not None: conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method def process(match, repl): retVal = match.group(0) if not (conf.testParameter and match.group("name") not in conf.testParameter): retVal = repl while True: _ = re.search(r"\\g<([^>]+)>", retVal) if _: retVal = retVal.replace( _.group(0), match.group( int(_.group(1)) if _.group(1).isdigit() else _. group(1))) else: break return retVal if kb.processUserMarks is None and CUSTOM_INJECTION_MARK_CHAR in conf.data: message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'--data'. Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if not (kb.processUserMarks and CUSTOM_INJECTION_MARK_CHAR in conf.data): if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub( r'("(?P<name>[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data) conf.data = re.sub( r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.JSON elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): message = "JSON-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub( r"('(?P<name>[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % CUSTOM_INJECTION_MARK_CHAR), conf.data) conf.data = re.sub( r"('(?P<name>[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.JSON_LIKE elif re.search(SOAP_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub( r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower( ) else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub( r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"'](?P<name>[^\n]+?)[\"']).+?)(((\r)?\n)+--)", functools.partial(process, repl=r"\g<1>%s\g<4>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.MULTIPART if not kb.postHint: if CUSTOM_INJECTION_MARK_CHAR in conf.data: # later processed pass else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True else: if CUSTOM_INJECTION_MARK_CHAR not in conf.data: # in case that no usable parameter values has been found conf.parameters[PLACE.POST] = conf.data kb.processUserMarks = True if (kb.postHint and CUSTOM_INJECTION_MARK_CHAR in conf.data) else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any( place in conf.parameters for place in (PLACE.GET, PLACE.POST) ) and not kb.postHint and not CUSTOM_INJECTION_MARK_CHAR in (conf.data or ""): warnMsg = "you've provided target URL without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target URL itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True elif test[0] in ("q", "Q"): raise SqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))): _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or "" if CUSTOM_INJECTION_MARK_CHAR in _: if kb.processUserMarks is None: lut = { PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie' } message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % lut[ place] test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value).query if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split('?')[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True elif place == PLACE.CUSTOM_POST: conf.parameters[PLACE.POST] = conf.data paramDict = paramToDict(PLACE.POST, conf.data) if paramDict: conf.paramDict[PLACE.POST] = paramDict testableParameters = True else: conf.parameters[place] = value conf.paramDict[place] = OrderedDict() if place == PLACE.CUSTOM_HEADER: for index in xrange(len(conf.httpHeaders)): header, value = conf.httpHeaders[index] if CUSTOM_INJECTION_MARK_CHAR in re.sub( PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value): parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place][ "%s #%d%s" % (header, i + 1, CUSTOM_INJECTION_MARK_CHAR )] = "%s,%s" % (header, "".join( "%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts)))) conf.httpHeaders[index] = ( header, value.replace(CUSTOM_INJECTION_MARK_CHAR, "")) else: parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s#%d%s" % ( ("%s " % kb.postHint) if kb.postHint else "", i + 1, CUSTOM_INJECTION_MARK_CHAR)] = "".join( "%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: for item in ("url", "data", "agent", "referer", "cookie"): if conf.get(item): conf[item] = conf[item].replace(CUSTOM_INJECTION_MARK_CHAR, "") # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value httpHeader = httpHeader.title() if httpHeader == HTTP_HEADER.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.USER_AGENT] = { PLACE.USER_AGENT: headerValue } testableParameters = True elif httpHeader == HTTP_HEADER.REFERER: conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES))) if condition: conf.paramDict[PLACE.REFERER] = { PLACE.REFERER: headerValue } testableParameters = True elif httpHeader == HTTP_HEADER.HOST: conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException(errMsg) elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the given request data" raise SqlmapGenericException(errMsg)
def start(): """ This function calls a function that performs checks on both URL stability and all GET, POST, Cookie and User-Agent parameters to check if they are dynamic and SQL injection affected """ if conf.url: kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie )) if conf.configFile and not kb.targetUrls: errMsg = "you did not edit the configuration file properly, set " errMsg += "the target url, list of targets or google dork" logger.error(errMsg) if kb.targetUrls and len(kb.targetUrls) > 1: infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls) logger.info(infoMsg) hostCount = 0 receivedCookies = [] cookieStr = "" setCookieAsInjectable = True for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie injData = [] if conf.multipleTargets: hostCount += 1 message = "url %d:\n%s %s" % (hostCount, conf.method or "GET", targetUrl) if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data: message += "\nPOST data: %s" % conf.data message += "\ndo you want to test this url? [Y/n/q] " test = readInput(message, default="Y") if not test: pass elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break logMsg = "testing url %s" % targetUrl logger.info(logMsg) initTargetEnv() if not checkConnection() or not checkString() or not checkRegexp(): continue for _, cookie in enumerate(conf.cj): cookie = str(cookie) index = cookie.index(" for ") cookieStr += "%s;" % cookie[8:index] if cookieStr: cookieStr = cookieStr[:-1] if "Cookie" in conf.parameters: message = "you provided an HTTP Cookie header value. " message += "The target url provided its own Cookie within " message += "the HTTP Set-Cookie header. Do you want to " message += "continue using the HTTP Cookie values that " message += "you provided? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): setCookieAsInjectable = False if setCookieAsInjectable: conf.httpHeaders.append(("Cookie", cookieStr)) conf.parameters["Cookie"] = cookieStr.replace("%", "%%") __paramDict = paramToDict("Cookie", cookieStr) if __paramDict: conf.paramDict["Cookie"] = __paramDict __testableParameters = True if not kb.injPlace or not kb.injParameter or not kb.injType: if not conf.string and not conf.regexp and not conf.eRegexp: if checkStability(): logMsg = "url is stable" logger.info(logMsg) else: errMsg = "url is not stable, try with --string or " errMsg += "--regexp options, refer to the user's manual " errMsg += "paragraph 'Page comparison' for details" if conf.multipleTargets: errMsg += ", skipping to next url" logger.warn(errMsg) continue else: raise sqlmapConnectionException, errMsg for place in conf.parameters.keys(): if not conf.paramDict.has_key(place): continue paramDict = conf.paramDict[place] for parameter, value in paramDict.items(): if not checkDynParam(place, parameter, value): warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter) logger.warn(warnMsg) else: logMsg = "%s parameter '%s' is dynamic" % (place, parameter) logger.info(logMsg) for parenthesis in range(0, 4): logMsg = "testing sql injection on %s " % place logMsg += "parameter '%s' with " % parameter logMsg += "%d parenthesis" % parenthesis logger.info(logMsg) injType = checkSqlInjection(place, parameter, value, parenthesis) if injType: injData.append((place, parameter, injType)) break else: infoMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg += "injectable with %d parenthesis" % parenthesis logger.info(infoMsg) if not injData: warnMsg = "%s parameter '%s' is not " % (place, parameter) warnMsg += "injectable" logger.warn(warnMsg) if not kb.injPlace or not kb.injParameter or not kb.injType: if len(injData) == 1: injDataSelected = injData[0] elif len(injData) > 1: injDataSelected = __selectInjection(injData) elif conf.multipleTargets: continue else: return if injDataSelected == "Quit": return else: kb.injPlace, kb.injParameter, kb.injType = injDataSelected setInjection() if not conf.multipleTargets and ( not kb.injPlace or not kb.injParameter or not kb.injType ): raise sqlmapNotVulnerableException, "all parameters are not injectable" elif kb.injPlace and kb.injParameter and kb.injType: condition = False if conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " exploit = readInput(message, default="Y") if not exploit or exploit[0] in ("y", "Y"): condition = True else: condition = True if condition: checkForParenthesis() createTargetDirs() action() if conf.loggedToOut: logger.info("Fetched data logged to text files under '%s'" % conf.outputPath)
def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise SqlmapSyntaxException(errMsg) if conf.data is not None: conf.method = HTTPMETHOD.POST if CUSTOM_INJECTION_MARK_CHAR in conf.data: # later processed pass elif re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = re.sub(r'("[^"]+"\s*:\s*"[^"]+)"', r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR, conf.data) conf.data = re.sub(r'("[^"]+"\s*:\s*)(-?\d[\d\.]*\b)', r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR, conf.data) kb.postHint = POST_HINT.JSON elif re.search(SOAP_RECOGNITION_REGEX, conf.data): message = "SOAP/XML like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = re.sub(r"(<([^>]+)( [^<]*)?>)([^<]+)(</\2)", r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR, conf.data) kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = re.sub(r"(?si)(Content-Disposition.+?)((\r)?\n--)", r"\g<1>%s\g<2>" % CUSTOM_INJECTION_MARK_CHAR, conf.data) kb.postHint = POST_HINT.MULTIPART else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True kb.processUserMarks = True if kb.postHint else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)): warnMsg = "you've provided target url without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target url itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True elif test[0] in ("q", "Q"): raise SqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, re.sub(r"\bq=[^;']+", "", str(conf.httpHeaders)))): if CUSTOM_INJECTION_MARK_CHAR in (value or ""): if kb.processUserMarks is None: _ = {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer'} message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % _[place] test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value).query if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split('?')[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True else: conf.parameters[place] = value conf.paramDict[place] = OrderedDict() if place == PLACE.CUSTOM_HEADER: for index in xrange(len(conf.httpHeaders)): header, value = conf.httpHeaders[index] if CUSTOM_INJECTION_MARK_CHAR in re.sub(r"\bq=[^;']+", "", value): conf.paramDict[place][header] = "%s,%s" % (header, value) conf.httpHeaders[index] = (header, value.replace(CUSTOM_INJECTION_MARK_CHAR, "")) else: parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s#%d%s" % (("%s " % kb.postHint) if kb.postHint else "", i + 1, CUSTOM_INJECTION_MARK_CHAR)] = "".join("%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: conf.url = conf.url.replace(CUSTOM_INJECTION_MARK_CHAR, "") conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, "") if conf.data else conf.data # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value httpHeader = httpHeader.title() 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.USER_AGENT] = {PLACE.USER_AGENT: headerValue} testableParameters = True elif httpHeader == HTTPHEADER.REFERER: conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES))) if condition: conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue} testableParameters = True elif httpHeader == HTTPHEADER.HOST: conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException(errMsg) elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise SqlmapGenericException(errMsg)
def start(): """ This function calls a function that performs checks on both URL stability and all GET, POST, Cookie and User-Agent parameters to check if they are dynamic and SQL injection affected """ if not conf.start: return False if conf.direct: initTargetEnv() setupTargetEnv() action() return True if conf.url and not any([conf.forms, conf.crawlDepth]): kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie )) if conf.configFile and not kb.targetUrls: errMsg = "you did not edit the configuration file properly, set " errMsg += "the target url, list of targets or google dork" logger.error(errMsg) return False if kb.targetUrls and len(kb.targetUrls) > 1: infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls) logger.info(infoMsg) hostCount = 0 cookieStr = "" setCookieAsInjectable = True for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls: try: conf.url = targetUrl conf.method = targetMethod conf.data = targetData conf.cookie = targetCookie initTargetEnv() parseTargetUrl() testSqlInj = False if PLACE.GET in conf.parameters and not any([conf.data, conf.testParameter]): for parameter in re.findall(r"([^=]+)=([^%s]+%s?|\Z)" % (conf.pDel or ";", conf.pDel or ";"), conf.parameters[PLACE.GET]): paramKey = (conf.hostname, conf.path, PLACE.GET, parameter[0]) if paramKey not in kb.testedParams: testSqlInj = True break else: paramKey = (conf.hostname, conf.path, None, None) if paramKey not in kb.testedParams: testSqlInj = True testSqlInj &= (conf.hostname, conf.path, None, None) not in kb.testedParams if not testSqlInj: infoMsg = "skipping '%s'" % targetUrl logger.info(infoMsg) continue if conf.multipleTargets: hostCount += 1 if conf.forms: message = "[#%d] form:\n%s %s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl) else: message = "url %d:\n%s %s%s" % (hostCount, conf.method or HTTPMETHOD.GET, targetUrl, " (PageRank: %s)" % get_pagerank(targetUrl) if conf.googleDork and conf.pageRank else "") if conf.cookie: message += "\nCookie: %s" % conf.cookie if conf.data: message += "\nPOST data: %s" % urlencode(conf.data) if conf.data else "" if conf.forms: if conf.method == HTTPMETHOD.GET and targetUrl.find("?") == -1: continue message += "\ndo you want to test this form? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): if conf.method == HTTPMETHOD.POST: message = "Edit POST data [default: %s]%s: " % (urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "") conf.data = readInput(message, default=conf.data) conf.data = __randomFillBlankFields(conf.data) conf.data = urldecode(conf.data) elif conf.method == HTTPMETHOD.GET: if targetUrl.find("?") > -1: firstPart = targetUrl[:targetUrl.find("?")] secondPart = targetUrl[targetUrl.find("?")+1:] message = "Edit GET data [default: %s]: " % secondPart test = readInput(message, default=secondPart) test = __randomFillBlankFields(test) conf.url = "%s?%s" % (firstPart, test) parseTargetUrl() elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break elif conf.realTest: logger.info(message) else: message += "\ndo you want to test this url? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): continue elif test[0] in ("q", "Q"): break infoMsg = "testing url %s" % targetUrl logger.info(infoMsg) setupTargetEnv() if not checkConnection(suppressOutput=conf.forms) or not checkString() or not checkRegexp(): continue if conf.checkWaf: checkWaf() if conf.nullConnection: checkNullConnection() if not conf.dropSetCookie and conf.cj: cookieStr = ";".join("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value)) for _, cookie in enumerate(conf.cj)) if cookieStr: if PLACE.COOKIE in conf.parameters: message = "you provided an HTTP Cookie header value. " message += "The target url provided its own Cookie within " message += "the HTTP Set-Cookie header. Do you want to " message += "continue using the HTTP Cookie values that " message += "you provided? [Y/n] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): setCookieAsInjectable = False if setCookieAsInjectable: conf.httpHeaders.append(("Cookie", cookieStr)) conf.parameters[PLACE.COOKIE] = cookieStr __paramDict = paramToDict(PLACE.COOKIE, cookieStr) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict # TODO: consider the following line in __setRequestParams() # __testableParameters = True 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: # NOTE: this is not needed anymore, leaving only to display # a warning message to the user in case the page is not stable checkStability() # Do a little prioritization reorder of a testable parameter list parameters = conf.parameters.keys() # Order of testing list (last to first) orderList = (PLACE.URI, PLACE.GET, PLACE.POST) for place in orderList: if place in parameters: parameters.remove(place) parameters.insert(0, place) proceed = True 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.REFERER and conf.level < 3) # 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.REFERER and intersect(REFERER_ALIASES, conf.skip, True) not in ([], None)) skip |= (place == PLACE.COOKIE and intersect('cookie', conf.skip, True) not in ([], None)) skip &= not (place == PLACE.UA and intersect(USER_AGENT_ALIASES, conf.testParameter, True)) skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter, True)) if skip: continue if not conf.paramDict.has_key(place): continue paramDict = conf.paramDict[place] for parameter, value in paramDict.items(): if not proceed: break kb.vainRun = False testSqlInj = True paramKey = (conf.hostname, conf.path, place, parameter) if paramKey in kb.testedParams: testSqlInj = False infoMsg = "skipping previously processed %s parameter '%s'" % (place, parameter) logger.info(infoMsg) elif parameter in conf.testParameter: pass elif parameter == conf.rParam: testSqlInj = False infoMsg = "skipping randomizing %s parameter '%s'" % (place, parameter) logger.info(infoMsg) elif parameter in conf.skip: testSqlInj = False infoMsg = "skipping %s parameter '%s'" % (place, parameter) logger.info(infoMsg) # Ignore session-like parameters for --level < 4 elif conf.level < 4 and parameter.upper() in IGNORE_PARAMETERS: testSqlInj = False infoMsg = "ignoring %s parameter '%s'" % (place, parameter) logger.info(infoMsg) elif conf.realTest: pass elif PAYLOAD.TECHNIQUE.BOOLEAN in conf.tech: if not checkDynParam(place, parameter, value): warnMsg = "%s parameter '%s' appears to be not dynamic" % (place, parameter) logger.warn(warnMsg) else: infoMsg = "%s parameter '%s' is dynamic" % (place, parameter) logger.info(infoMsg) kb.testedParams.add(paramKey) if testSqlInj: check = heuristicCheckSqlInjection(place, parameter) if not check: if conf.smart or conf.realTest and not simpletonCheckSqlInjection(place, parameter, value): infoMsg = "skipping %s parameter '%s'" % (place, parameter) logger.info(infoMsg) continue infoMsg = "testing sql injection on %s " % place infoMsg += "parameter '%s'" % parameter logger.info(infoMsg) injection = checkSqlInjection(place, parameter, value) proceed = not kb.endDetection if injection is not None and injection.place is not None: kb.injections.append(injection) # In case when user wants to end detection phase (Ctrl+C) if not proceed: break msg = "%s parameter '%s' " % (injection.place, injection.parameter) msg += "is vulnerable. Do you want to keep testing the others? [y/N] " test = readInput(msg, default="N") if test[0] in ("n", "N"): proceed = False paramKey = (conf.hostname, conf.path, None, None) kb.testedParams.add(paramKey) else: warnMsg = "%s parameter '%s' is not " % (place, parameter) warnMsg += "injectable" logger.warn(warnMsg) if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None): if kb.vainRun and not conf.multipleTargets: errMsg = "no testable parameter(s) found in the provided data " errMsg += "(e.g. GET parameter 'id' in 'www.site.com/index.php?id=1')" raise sqlmapNoneDataException, errMsg elif not conf.realTest: errMsg = "all parameters appear to be not injectable." if conf.level < 5 or conf.risk < 3: errMsg += " Try to increase --level/--risk values " errMsg += "to perform more tests." if isinstance(conf.tech, list) and len(conf.tech) < 5: errMsg += " Rerun without providing the --technique switch." if not conf.textOnly and kb.originalPage: percent = (100.0 * len(getFilteredPageContent(kb.originalPage)) / len(kb.originalPage)) if kb.dynamicParameters: errMsg += " You can give it a go with the --text-only " errMsg += "switch if the target page has a low percentage " errMsg += "of textual content (~%.2f%% of " % percent errMsg += "page content is text)." elif percent < LOW_TEXT_PERCENT and not kb.errorIsNone: errMsg += " Please retry with the --text-only switch " errMsg += "(along with --technique=BU) as this case " errMsg += "looks like a perfect candidate " errMsg += "(low textual content along with inability " errMsg += "of comparison engine to detect at least " errMsg += "one dynamic parameter)." if kb.heuristicTest: errMsg += " As heuristic test turned out positive you are " errMsg += "strongly advised to continue on with the tests. " errMsg += "Please, consider usage of tampering scripts as " errMsg += "your target might filter the queries." if not conf.string and not conf.regexp: errMsg += " Also, you can try to rerun by providing " errMsg += "either a valid --string " errMsg += "or a valid --regexp, refer to the user's " errMsg += "manual for details" elif conf.string: errMsg += " Also, you can try to rerun by providing a " errMsg += "valid --string as perhaps the string you " errMsg += "have choosen does not match " errMsg += "exclusively True responses" elif conf.regexp: errMsg += " Also, you can try to rerun by providing a " errMsg += "valid --regexp as perhaps the regular " errMsg += "expression that you have choosen " errMsg += "does not match exclusively True responses" raise sqlmapNotVulnerableException, errMsg else: errMsg = "it seems that all parameters are not injectable" raise sqlmapNotVulnerableException, errMsg else: # Flush the flag kb.testMode = False __saveToSessionFile() __saveToResultsFile() __showInjections() __selectInjection() if kb.injection.place is not None and kb.injection.parameter is not None: if kb.testQueryCount == 0 and conf.realTest: condition = False elif conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " exploit = readInput(message, default="Y") condition = not exploit or exploit[0] in ("y", "Y") else: condition = True if condition: action() except KeyboardInterrupt: if conf.multipleTargets: warnMsg = "user aborted in multiple target mode" logger.warn(warnMsg) message = "do you want to skip to the next target in list? [Y/n/q]" test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): pass elif test[0] in ("n", "N"): return False elif test[0] in ("q", "Q"): raise sqlmapUserQuitException else: raise except sqlmapUserQuitException: raise except sqlmapSilentQuitException: raise except exceptionsTuple, e: e = getUnicode(e) if conf.multipleTargets: e += ", skipping to the next %s" % ("form" if conf.forms else "url") logger.error(e) else: logger.critical(e) return False finally:
def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise SqlmapSyntaxException(errMsg) if conf.data is not None: conf.method = HTTPMETHOD.POST def process(match, repl): retVal = match.group(0) if not (conf.testParameter and match.group("name") not in conf.testParameter): retVal = repl while True: _ = re.search(r"\\g<([^>]+)>", retVal) if _: retVal = retVal.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) else: break return retVal if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.JSON elif re.search(SOAP_RECOGNITION_REGEX, conf.data): message = "SOAP/XML like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart like data found in POST data. " message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(?si)(Content-Disposition.+?)((\r)?\n--)", r"\g<1>%s\g<2>" % CUSTOM_INJECTION_MARK_CHAR, conf.data) kb.postHint = POST_HINT.MULTIPART if not kb.postHint: if CUSTOM_INJECTION_MARK_CHAR in conf.data: # later processed pass else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True else: if CUSTOM_INJECTION_MARK_CHAR not in conf.data: # in case that no usable parameter values has been found conf.parameters[PLACE.POST] = conf.data kb.processUserMarks = True if (kb.postHint and CUSTOM_INJECTION_MARK_CHAR in conf.data) else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint: warnMsg = "you've provided target url without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target url itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True elif test[0] in ("q", "Q"): raise SqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))): _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or "" if CUSTOM_INJECTION_MARK_CHAR in _: if kb.processUserMarks is None: lut = {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie'} message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % lut[place] test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value).query if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split('?')[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True elif place == PLACE.CUSTOM_POST: conf.parameters[PLACE.POST] = conf.data paramDict = paramToDict(PLACE.POST, conf.data) if paramDict: conf.paramDict[PLACE.POST] = paramDict testableParameters = True else: conf.parameters[place] = value conf.paramDict[place] = OrderedDict() if place == PLACE.CUSTOM_HEADER: for index in xrange(len(conf.httpHeaders)): header, value = conf.httpHeaders[index] if CUSTOM_INJECTION_MARK_CHAR in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value): parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s #%d%s" % (header, i + 1, CUSTOM_INJECTION_MARK_CHAR)] = "%s,%s" % (header, "".join("%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts)))) conf.httpHeaders[index] = (header, value.replace(CUSTOM_INJECTION_MARK_CHAR, "")) else: parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s#%d%s" % (("%s " % kb.postHint) if kb.postHint else "", i + 1, CUSTOM_INJECTION_MARK_CHAR)] = "".join("%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: for item in ("url", "data", "agent", "referer", "cookie"): if conf.get(item): conf[item] = conf[item].replace(CUSTOM_INJECTION_MARK_CHAR, "") # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value httpHeader = httpHeader.title() if httpHeader == HTTP_HEADER.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.USER_AGENT] = {PLACE.USER_AGENT: headerValue} testableParameters = True elif httpHeader == HTTP_HEADER.REFERER: conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES))) if condition: conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue} testableParameters = True elif httpHeader == HTTP_HEADER.HOST: conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException(errMsg) elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the given request data" raise SqlmapGenericException(errMsg)
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return __testableParameters = False # Perform checks on GET parameters if conf.parameters.has_key(PLACE.GET) and conf.parameters[PLACE.GET]: parameters = conf.parameters[PLACE.GET] __paramDict = paramToDict(PLACE.GET, parameters) if __paramDict: conf.paramDict[PLACE.GET] = __paramDict __testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: conf.data = conf.data.replace("\n", " ") conf.parameters[PLACE.POST] = conf.data # Check if POST data is in xml syntax if re.match("[\n]*<(\?xml |soap\:|ns).*>", conf.data): conf.paramDict["POSTxml"] = True __paramDict = paramToDict("POSTxml", conf.data) else: __paramDict = paramToDict(PLACE.POST, conf.data) if __paramDict: conf.paramDict[PLACE.POST] = __paramDict __testableParameters = True conf.method = HTTPMETHOD.POST if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not conf.parameters.has_key(PLACE.GET): conf.url = "%s%s" % (conf.url, URI_INJECTION_MARK_CHAR) if URI_INJECTION_MARK_CHAR in conf.url: conf.parameters[PLACE.URI] = conf.url conf.paramDict[PLACE.URI] = {} parts = conf.url.split(URI_INJECTION_MARK_CHAR) for i in range(len(parts)-1): result = str() for j in range(len(parts)): result += parts[j] if i == j: result += URI_INJECTION_MARK_CHAR conf.paramDict[PLACE.URI]["#%d%s" % (i+1, URI_INJECTION_MARK_CHAR)] = result conf.url = conf.url.replace(URI_INJECTION_MARK_CHAR, str()) __testableParameters = True # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie __paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if __paramDict: conf.paramDict[PLACE.COOKIE] = __paramDict __testableParameters = True # Perform checks on User-Agent header value if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: if httpHeader == PLACE.UA: # No need for url encoding/decoding the user agent conf.parameters[PLACE.UA] = urldecode(headerValue) condition = any([not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES)]) if condition: conf.paramDict[PLACE.UA] = { PLACE.UA: headerValue } __testableParameters = True elif httpHeader == PLACE.REFERER: # No need for url encoding/decoding the referer conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any([not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES)]) if condition: conf.paramDict[PLACE.REFERER] = { PLACE.REFERER: headerValue } __testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent or Referer header" raise sqlmapGenericException, errMsg elif not __testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg
def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise SqlmapSyntaxException(errMsg) if conf.data is not None: conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method hintNames = [] def process(match, repl): retVal = match.group(0) if not (conf.testParameter and match.group("name") not in conf.testParameter): retVal = repl while True: _ = re.search(r"\\g<([^>]+)>", retVal) if _: retVal = retVal.replace(_.group(0), match.group(int(_.group(1)) if _.group(1).isdigit() else _.group(1))) else: break if CUSTOM_INJECTION_MARK_CHAR in retVal: hintNames.append((retVal.split(CUSTOM_INJECTION_MARK_CHAR)[0], match.group("name"))) return retVal if kb.processUserMarks is None and CUSTOM_INJECTION_MARK_CHAR in conf.data: message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'--data'. Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if kb.processUserMarks: kb.testOnlyCustom = True if not (kb.processUserMarks and CUSTOM_INJECTION_MARK_CHAR in conf.data): if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data) conf.data = re.sub(r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*\b)', functools.partial(process, repl=r'\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR), conf.data) match = re.search(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data) if match and not (conf.testParameter and match.group("name") not in conf.testParameter): _ = match.group(2) _ = re.sub(r'("[^"]+)"', '\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR, _) _ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', '\g<0>%s' % CUSTOM_INJECTION_MARK_CHAR, _) conf.data = conf.data.replace(match.group(0), match.group(0).replace(match.group(2), _)) kb.postHint = POST_HINT.JSON elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): message = "JSON-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"('(?P<name>[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % CUSTOM_INJECTION_MARK_CHAR), conf.data) conf.data = re.sub(r"('(?P<name>[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.JSON_LIKE elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data): message = "Array-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER, r"\g<1>%s" % CUSTOM_INJECTION_MARK_CHAR, conf.data) kb.postHint = POST_HINT.ARRAY_LIKE elif re.search(XML_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException elif test[0] not in ("n", "N"): conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"'](?P<name>[^\n]+?)[\"']).+?)(((\r)?\n)+--)", functools.partial(process, repl=r"\g<1>%s\g<4>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) kb.postHint = POST_HINT.MULTIPART if not kb.postHint: if CUSTOM_INJECTION_MARK_CHAR in conf.data: # later processed pass else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True else: if CUSTOM_INJECTION_MARK_CHAR not in conf.data: # in case that no usable parameter values has been found conf.parameters[PLACE.POST] = conf.data kb.processUserMarks = True if (kb.postHint and CUSTOM_INJECTION_MARK_CHAR in conf.data) else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and not CUSTOM_INJECTION_MARK_CHAR in (conf.data or "") and conf.url.startswith("http"): warnMsg = "you've provided target URL without any GET " warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " warnMsg += "and without providing any POST parameters " warnMsg += "through --data option" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target URL itself? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True elif test[0] in ("q", "Q"): raise SqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))): _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or "" if CUSTOM_INJECTION_MARK_CHAR in _: if kb.processUserMarks is None: lut = {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie'} message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % lut[place] test = readInput(message, default="Y") if test and test[0] in ("q", "Q"): raise SqlmapUserQuitException else: kb.processUserMarks = not test or test[0] not in ("n", "N") if kb.processUserMarks: kb.testOnlyCustom = True if "=%s" % CUSTOM_INJECTION_MARK_CHAR in _: warnMsg = "it seems that you've provided empty parameter value(s) " warnMsg += "for testing. Please, always use only valid parameter values " warnMsg += "so sqlmap could be able to run properly" logger.warn(warnMsg) if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value).query if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split('?')[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True elif place == PLACE.CUSTOM_POST: conf.parameters[PLACE.POST] = conf.data paramDict = paramToDict(PLACE.POST, conf.data) if paramDict: conf.paramDict[PLACE.POST] = paramDict testableParameters = True else: conf.parameters[place] = value conf.paramDict[place] = OrderedDict() if place == PLACE.CUSTOM_HEADER: for index in xrange(len(conf.httpHeaders)): header, value = conf.httpHeaders[index] if CUSTOM_INJECTION_MARK_CHAR in re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value): parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s #%d%s" % (header, i + 1, CUSTOM_INJECTION_MARK_CHAR)] = "%s,%s" % (header, "".join("%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts)))) conf.httpHeaders[index] = (header, value.replace(CUSTOM_INJECTION_MARK_CHAR, "")) else: parts = value.split(CUSTOM_INJECTION_MARK_CHAR) for i in xrange(len(parts) - 1): name = None if kb.postHint: for ending, _ in hintNames: if parts[i].endswith(ending): name = "%s %s" % (kb.postHint, _) break if name is None: name = "%s#%s%s" % (("%s " % kb.postHint) if kb.postHint else "", i + 1, CUSTOM_INJECTION_MARK_CHAR) conf.paramDict[place][name] = "".join("%s%s" % (parts[j], CUSTOM_INJECTION_MARK_CHAR if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: for item in ("url", "data", "agent", "referer", "cookie"): if conf.get(item): conf[item] = conf[item].replace(CUSTOM_INJECTION_MARK_CHAR, "") # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: # Url encoding of the header values should be avoided # Reference: http://stackoverflow.com/questions/5085904/is-ok-to-urlencode-the-value-in-headerlocation-value httpHeader = httpHeader.title() if httpHeader == HTTP_HEADER.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.USER_AGENT] = {PLACE.USER_AGENT: headerValue} testableParameters = True elif httpHeader == HTTP_HEADER.REFERER: conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES))) if condition: conf.paramDict[PLACE.REFERER] = {PLACE.REFERER: headerValue} testableParameters = True elif httpHeader == HTTP_HEADER.HOST: conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException(errMsg) elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the given request data" raise SqlmapGenericException(errMsg) if conf.csrfToken: if not any(conf.csrfToken in _ for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not conf.csrfToken in set(_[0].lower() for _ in conf.httpHeaders) and not conf.csrfToken in conf.paramDict.get(PLACE.COOKIE, {}): errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken errMsg += "found in provided GET, POST, Cookie or header values" raise SqlmapGenericException(errMsg) else: for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE): for parameter in conf.paramDict.get(place, {}): if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): message = "%s parameter '%s' appears to hold anti-CSRF token. " % (place, parameter) message += "Do you want sqlmap to automatically update it in further requests? [y/N] " test = readInput(message, default="N") if test and test[0] in ("y", "Y"): conf.csrfToken = parameter break
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ __testableParameters = False # Perform checks on GET parameters if conf.parameters.has_key("GET") and conf.parameters["GET"]: parameters = conf.parameters["GET"] __paramDict = paramToDict("GET", parameters) if __paramDict: conf.paramDict["GET"] = __paramDict __testableParameters = True # Perform checks on POST parameters if conf.method == "POST" and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: urlDecodedData = urldecode(conf.data).replace("%", "%%") conf.parameters["POST"] = urlDecodedData __paramDict = paramToDict("POST", urlDecodedData) if __paramDict: conf.paramDict["POST"] = __paramDict __testableParameters = True # Perform checks on Cookie parameters if conf.cookie: # TODO: sure about decoding the cookie? #urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%") urlDecodedCookie = conf.cookie.replace("%", "%%") conf.parameters["Cookie"] = urlDecodedCookie __paramDict = paramToDict("Cookie", urlDecodedCookie) if __paramDict: conf.paramDict["Cookie"] = __paramDict __testableParameters = True # Perform checks on User-Agent header value if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: if httpHeader == "User-Agent": conf.parameters["User-Agent"] = urldecode(headerValue).replace( "%", "%%") condition = not conf.testParameter condition |= "User-Agent" in conf.testParameter condition |= "user-agent" in conf.testParameter condition |= "useragent" in conf.testParameter condition |= "ua" in conf.testParameter if condition: conf.paramDict["User-Agent"] = {"User-Agent": headerValue} __testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent header" raise sqlmapGenericException, errMsg elif not __testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg
def _setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ if conf.direct: conf.parameters[None] = "direct connection" return hintNames = [] testableParameters = False # Perform checks on GET parameters if conf.parameters.get(PLACE.GET): parameters = conf.parameters[PLACE.GET] paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.paramDict[PLACE.GET] = paramDict testableParameters = True # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: logger.warn("detected empty POST body") conf.data = "" if conf.data is not None: conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method def process(match, repl): retVal = match.group(0) if not (conf.testParameter and match.group("name") not in conf.testParameter): retVal = repl while True: _ = re.search(r"\\g<([^>]+)>", retVal) if _: retVal = retVal.replace( _.group(0), match.group( int(_.group(1)) if _.group(1).isdigit() else _. group(1))) else: break if kb.customInjectionMark in retVal: hintNames.append((retVal.split(kb.customInjectionMark)[0], match.group("name"))) return retVal if kb.processUserMarks is None and kb.customInjectionMark in conf.data: message = "custom injection marker ('%s') found in option " % kb.customInjectionMark message += "'--data'. Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException else: kb.processUserMarks = choice == 'Y' if kb.processUserMarks: kb.testOnlyCustom = True if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub( r'("(?P<name>[^"]+)"\s*:\s*".+?)"(?<!\\")', functools.partial(process, repl=r'\g<1>%s"' % kb.customInjectionMark), conf.data) conf.data = re.sub( r'("(?P<name>[^"]+)"\s*:\s*)(-?\d[\d\.]*)\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) conf.data = re.sub( r'("(?P<name>[^"]+)"\s*:\s*)((true|false|null))\b', functools.partial(process, repl=r'\g<1>\g<3>%s' % kb.customInjectionMark), conf.data) match = re.search(r'(?P<name>[^"]+)"\s*:\s*\[([^\]]+)\]', conf.data) if match and not (conf.testParameter and match.group("name") not in conf.testParameter): _ = match.group(2) _ = re.sub(r'("[^"]+)"', r'\g<1>%s"' % kb.customInjectionMark, _) _ = re.sub(r'(\A|,|\s+)(-?\d[\d\.]*\b)', r'\g<0>%s' % kb.customInjectionMark, _) conf.data = conf.data.replace( match.group(0), match.group(0).replace(match.group(2), _)) kb.postHint = POST_HINT.JSON elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): message = "JSON-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub( r"('(?P<name>[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % kb.customInjectionMark), conf.data) conf.data = re.sub( r"('(?P<name>[^']+)'\s*:\s*)(-?\d[\d\.]*\b)", functools.partial(process, repl=r"\g<0>%s" % kb.customInjectionMark), conf.data) kb.postHint = POST_HINT.JSON_LIKE elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data): message = "Array-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub( r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER, r"\g<1>%s" % kb.customInjectionMark, conf.data) kb.postHint = POST_HINT.ARRAY_LIKE elif re.search(XML_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub( r"(<(?P<name>[^>]+)( [^<]*)?>)([^<]+)(</\2)", functools.partial(process, repl=r"\g<1>\g<4>%s\g<5>" % kb.customInjectionMark), conf.data) kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower( ) else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': if not (kb.processUserMarks and kb.customInjectionMark in conf.data): conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(kb.customInjectionMark, ASTERISK_MARKER) conf.data = re.sub( r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"']?(?P<name>[^\"'\r\n]+)[\"']?).+?)(((\r)?\n)+--)", functools.partial(process, repl=r"\g<1>%s\g<4>" % kb.customInjectionMark), conf.data) kb.postHint = POST_HINT.MULTIPART if not kb.postHint: if kb.customInjectionMark in conf.data: # later processed pass else: place = PLACE.POST conf.parameters[place] = conf.data paramDict = paramToDict(place, conf.data) if paramDict: conf.paramDict[place] = paramDict testableParameters = True else: if kb.customInjectionMark not in conf.data: # in case that no usable parameter values has been found conf.parameters[PLACE.POST] = conf.data kb.processUserMarks = True if (kb.postHint and kb.customInjectionMark in ( conf.data or "")) else kb.processUserMarks if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any( place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and kb.customInjectionMark not in ( conf.data or "") and conf.url.startswith("http"): warnMsg = "you've provided target URL without any GET " warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') " warnMsg += "and without providing any POST parameters " warnMsg += "through option '--data'" logger.warn(warnMsg) message = "do you want to try URI injections " message += "in the target URL itself? [Y/n/q] " choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException elif choice == 'Y': conf.url = "%s%s" % (conf.url, kb.customInjectionMark) kb.processUserMarks = True for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))): _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or "" if kb.customInjectionMark in _: if kb.processUserMarks is None: lut = { PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie' } message = "custom injection marker ('%s') found in option " % kb.customInjectionMark message += "'%s'. Do you want to process it? [Y/n/q] " % lut[ place] choice = readInput(message, default='Y').upper() if choice == 'Q': raise SqlmapUserQuitException else: kb.processUserMarks = choice == 'Y' if kb.processUserMarks: kb.testOnlyCustom = True if "=%s" % kb.customInjectionMark in _: warnMsg = "it seems that you've provided empty parameter value(s) " warnMsg += "for testing. Please, always use only valid parameter values " warnMsg += "so sqlmap could be able to run properly" logger.warn(warnMsg) if not kb.processUserMarks: if place == PLACE.URI: query = urlparse.urlsplit(value).query if query: parameters = conf.parameters[PLACE.GET] = query paramDict = paramToDict(PLACE.GET, parameters) if paramDict: conf.url = conf.url.split('?')[0] conf.paramDict[PLACE.GET] = paramDict testableParameters = True elif place == PLACE.CUSTOM_POST: conf.parameters[PLACE.POST] = conf.data paramDict = paramToDict(PLACE.POST, conf.data) if paramDict: conf.paramDict[PLACE.POST] = paramDict testableParameters = True else: conf.parameters[place] = value conf.paramDict[place] = OrderedDict() if place == PLACE.CUSTOM_HEADER: for index in xrange(len(conf.httpHeaders)): header, value = conf.httpHeaders[index] if kb.customInjectionMark in re.sub( PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value): parts = value.split(kb.customInjectionMark) for i in xrange(len(parts) - 1): conf.paramDict[place]["%s #%d%s" % ( header, i + 1, kb.customInjectionMark )] = "%s,%s" % (header, "".join( "%s%s" % (parts[j], kb.customInjectionMark if i == j else "") for j in xrange(len(parts)))) conf.httpHeaders[index] = ( header, value.replace(kb.customInjectionMark, "")) else: parts = value.split(kb.customInjectionMark) for i in xrange(len(parts) - 1): name = None if kb.postHint: for ending, _ in hintNames: if parts[i].endswith(ending): name = "%s %s" % (kb.postHint, _) break if name is None: name = "%s#%s%s" % ( ("%s " % kb.postHint) if kb.postHint else "", i + 1, kb.customInjectionMark) conf.paramDict[place][name] = "".join( "%s%s" % (parts[j], kb.customInjectionMark if i == j else "") for j in xrange(len(parts))) if place == PLACE.URI and PLACE.GET in conf.paramDict: del conf.paramDict[PLACE.GET] elif place == PLACE.CUSTOM_POST and PLACE.POST in conf.paramDict: del conf.paramDict[PLACE.POST] testableParameters = True if kb.processUserMarks: for item in ("url", "data", "agent", "referer", "cookie"): if conf.get(item): conf[item] = conf[item].replace(kb.customInjectionMark, "") # Perform checks on Cookie parameters if conf.cookie: conf.parameters[PLACE.COOKIE] = conf.cookie paramDict = paramToDict(PLACE.COOKIE, conf.cookie) if paramDict: conf.paramDict[PLACE.COOKIE] = paramDict testableParameters = True # Perform checks on header values if conf.httpHeaders: for httpHeader, headerValue in list(conf.httpHeaders): # 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.upper() == HTTP_HEADER.USER_AGENT.upper(): conf.parameters[PLACE.USER_AGENT] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, USER_AGENT_ALIASES, True))) if condition: conf.paramDict[PLACE.USER_AGENT] = { PLACE.USER_AGENT: headerValue } testableParameters = True elif httpHeader.upper() == HTTP_HEADER.REFERER.upper(): conf.parameters[PLACE.REFERER] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, REFERER_ALIASES, True))) if condition: conf.paramDict[PLACE.REFERER] = { PLACE.REFERER: headerValue } testableParameters = True elif httpHeader.upper() == HTTP_HEADER.HOST.upper(): conf.parameters[PLACE.HOST] = urldecode(headerValue) condition = any((not conf.testParameter, intersect(conf.testParameter, HOST_ALIASES, True))) if condition: conf.paramDict[PLACE.HOST] = {PLACE.HOST: headerValue} testableParameters = True else: condition = intersect(conf.testParameter, [httpHeader], True) if condition: conf.parameters[PLACE.CUSTOM_HEADER] = str( conf.httpHeaders) conf.paramDict[PLACE.CUSTOM_HEADER] = { httpHeader: "%s,%s%s" % (httpHeader, headerValue, kb.customInjectionMark) } conf.httpHeaders = [ (_[0], _[1].replace(kb.customInjectionMark, "")) for _ in conf.httpHeaders ] testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent, Referer or Host header value" raise SqlmapGenericException(errMsg) elif not testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the given request data" raise SqlmapGenericException(errMsg) if conf.csrfToken: if not any( re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search( r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set( _[0].lower() for _ in conf.httpHeaders ) and conf.csrfToken not in conf.paramDict.get( PLACE.COOKIE, {}): errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken._original errMsg += "found in provided GET, POST, Cookie or header values" raise SqlmapGenericException(errMsg) else: for place in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if conf.csrfToken: break for parameter in conf.paramDict.get(place, {}): if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): message = "%s parameter '%s' appears to hold anti-CSRF token. " % ( place, parameter) message += "Do you want sqlmap to automatically update it in further requests? [y/N] " if readInput(message, default='N', boolean=True): class _(unicode): pass conf.csrfToken = _(re.escape(getUnicode(parameter))) conf.csrfToken._original = getUnicode(parameter) break
def __setRequestParams(): """ Check and set the parameters and perform checks on 'data' option for HTTP method POST. """ __testableParameters = False # Perform checks on GET parameters if conf.parameters.has_key("GET") and conf.parameters["GET"]: parameters = conf.parameters["GET"] __paramDict = paramToDict("GET", parameters) if __paramDict: conf.paramDict["GET"] = __paramDict __testableParameters = True # Perform checks on POST parameters if conf.method == "POST" and not conf.data: errMsg = "HTTP POST method depends on HTTP data value to be posted" raise sqlmapSyntaxException, errMsg if conf.data: conf.parameters["POST"] = conf.data __paramDict = paramToDict("POST", conf.data) if __paramDict: conf.paramDict["POST"] = __paramDict __testableParameters = True conf.method = "POST" # Perform checks on Cookie parameters if conf.cookie: conf.parameters["Cookie"] = conf.cookie __paramDict = paramToDict("Cookie", conf.cookie) if __paramDict: conf.paramDict["Cookie"] = __paramDict __testableParameters = True # Perform checks on User-Agent header value if conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders: if httpHeader == "User-Agent": # No need for url encoding/decoding the user agent conf.parameters["User-Agent"] = headerValue condition = not conf.testParameter condition |= "User-Agent" in conf.testParameter condition |= "user-agent" in conf.testParameter condition |= "useragent" in conf.testParameter condition |= "ua" in conf.testParameter if condition: conf.paramDict["User-Agent"] = { "User-Agent": headerValue } __testableParameters = True if not conf.parameters: errMsg = "you did not provide any GET, POST and Cookie " errMsg += "parameter, neither an User-Agent header" raise sqlmapGenericException, errMsg elif not __testableParameters: errMsg = "all testable parameters you provided are not present " errMsg += "within the GET, POST and Cookie parameters" raise sqlmapGenericException, errMsg