def checkPayload(payload): """ This method checks if the generated payload is detectable by the PHPIDS filter rules """ if not payload: return global rules detected = False payload = urldecode(payload) if not rules: xmlrules = readXmlFile(paths.PHPIDS_RULES_XML) rules = [] for xmlrule in xmlrules.getElementsByTagName("filter"): rule = "(?i)%s" % xmlrule.getElementsByTagName('rule')[0].childNodes[0].nodeValue desc = __adjustGrammar(xmlrule.getElementsByTagName('description')[0].childNodes[0].nodeValue) rules.append((rule, desc)) if payload: for rule, desc in rules: if re.search(rule, payload): detected = True logger.warn("highly probable IDS/IPS detection: '%s: %s'" % (desc, payload)) if not detected: logger.warn("payload '%s' possibly gone undetected" % payload)
def parseTargetUrl(): """ Parse target url and set some attributes into the configuration singleton. """ if not conf.url: return if not re.search("^http[s]*://", conf.url): if ":443/" in conf.url: conf.url = "https://" + conf.url else: conf.url = "http://" + conf.url __urlSplit = urlparse.urlsplit(conf.url) __hostnamePort = __urlSplit[1].split(":") conf.scheme = __urlSplit[0] conf.path = __urlSplit[2] conf.hostname = __hostnamePort[0] if len(__hostnamePort) == 2: conf.port = int(__hostnamePort[1]) elif conf.scheme == "https": conf.port = 443 else: conf.port = 80 if __urlSplit[3]: conf.parameters["GET"] = urldecode(__urlSplit[3]).replace("%", "%%") conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
def getTargetUrls(self): """ This method returns the list of hosts with parameters out of your Google dork search results """ for _ in self._matches: _ = urldecode(_) if re.search(r"(.*?)\?(.+)", _): kb.targetUrls.add((_, None, None, None)) elif re.search(URI_INJECTABLE_REGEX, _, re.I): if kb.scanOnlyGoogleGETs is None: message = "do you want to scan only results containing GET parameters? [Y/n] " test = readInput(message, default="Y") kb.scanOnlyGoogleGETs = test.lower() != 'n' if not kb.scanOnlyGoogleGETs: kb.targetUrls.add((_, None, None, None))
def checkPayload(payload): """ This method checks if the generated payload is detectable by the PHPIDS filter rules """ global rules payload = urldecode(payload) if not rules: xmlrules = readXmlFile(paths.PHPIDS_RULES_XML) rules = [] for xmlrule in xmlrules.getElementsByTagName("filter"): rule = "(?i)%s" % xmlrule.getElementsByTagName('rule')[0].childNodes[0].nodeValue desc = __adjustGrammar(xmlrule.getElementsByTagName('description')[0].childNodes[0].nodeValue) rules.append((rule, desc)) if payload: for rule, desc in rules: regObj = getCompiledRegex(rule) if regObj.search(payload): logger.warn("highly probable IDS/IPS detection: '%s: %s'" % (desc, payload))
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 = "" 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) if conf.data and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in conf.data else 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 (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, PLACE.CUSTOM_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 Host header only if # --level >= 5 skip |= place == PLACE.HOST and conf.level < 5 # 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(PLACE.COOKIE, conf.skip, True) not in ([], None) skip &= not (place == PLACE.UA and intersect(USER_AGENT_ALIASES, conf.testParameter, True)) skip &= not (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.testParameter, True)) skip &= not (place == PLACE.HOST and intersect(HOST_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 for 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 (if any)? [y/N] " test = readInput(msg, default="N") if test[0] not in ("y", "Y"): 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 parameter(s) found for testing 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 option '--technique'." 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 __saveToResultsFile() __saveToHashDB() __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: 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", " ") 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 if httpHeader == PLACE.UA: 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: 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 == PLACE.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 __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 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 = "" 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) if conf.data and urlencode( DEFAULT_GET_POST_DELIMITER, None) not in conf.data else 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 (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, PLACE.CUSTOM_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 Host header only if # --level >= 5 skip |= (place == PLACE.HOST and conf.level < 5) # 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( PLACE.COOKIE, conf.skip, True) not in ([], None)) skip &= not (place == PLACE.UA and intersect( USER_AGENT_ALIASES, conf.testParameter, True)) skip &= not (place == PLACE.REFERER and intersect( REFERER_ALIASES, conf.testParameter, True)) skip &= not (place == PLACE.HOST and intersect( HOST_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 for 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 (if any)? [y/N] " test = readInput(msg, default="N") if test[0] not in ("y", "Y"): 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 parameter(s) found for testing 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 option '--technique'." 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 __saveToResultsFile() __saveToHashDB() __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. """ __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 __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 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: 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", " ") 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] 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 mark ('%s') found in " % 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 if httpHeader == PLACE.UA: 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: 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 == PLACE.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