def queryOutputLength(expression, payload): """ Returns the query output length. """ lengthQuery = queries[kb.dbms].length.query select = re.search("\ASELECT\s+", expression, re.I) selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I) selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I) selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I) miscExpr = re.search("\A(.+)", expression, re.I) if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr: if selectTopExpr: regExpr = selectTopExpr.groups()[0] elif selectDistinctExpr: regExpr = selectDistinctExpr.groups()[0] elif selectFromExpr: regExpr = selectFromExpr.groups()[0] elif selectExpr: regExpr = selectExpr.groups()[0] elif miscExpr: regExpr = miscExpr.groups()[0] if (select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I)) or len(regExpr) <= 1: return None, None, None if selectDistinctExpr: lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr, expression) if kb.dbms in (DBMS.MYSQL, DBMS.POSTGRESQL): lengthExpr += " AS %s" % randomStr(lowercase=True) elif select: lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1) else: lengthExpr = lengthQuery % expression infoMsg = "retrieving the length of query output" logger.info(infoMsg) output = resume(lengthExpr, payload) if output: return 0, output, regExpr dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr)) start = time.time() lengthExprUnescaped = unescaper.unescape(lengthExpr) count, length = bisection(payload, lengthExprUnescaped, charsetType=2) debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) if length == " ": length = 0 return count, length, regExpr
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None): start = time.time() value = None count = 0 value = _goDns(payload, expression) if value: return value timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if not (timeBasedCompare and kb.dnsTest): if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search("(COUNT|LTRIM)\(", expression, re.I) and not timeBasedCompare: if field and conf.hexConvert: nulledCastedField = agent.nullAndCastField(field) injExpression = expression.replace(field, nulledCastedField, 1) else: injExpression = expression length = queryOutputLength(injExpression, payload) else: length = None kb.inferenceMode = True count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) kb.inferenceMode = False if not kb.bruteMode: debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False): start = time.time() value = None count = 0 value = __goDns(payload, expression) if value is None: timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if not (timeBasedCompare and kb.dnsTest): if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not timeBasedCompare: _, length, _ = queryOutputLength(expression, payload) else: length = None kb.inferenceMode = True count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) kb.inferenceMode = False if not kb.bruteMode: debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False): start = time.time() timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if (conf.eta or conf.threads > 1 ) and Backend.getIdentifiedDbms() and not timeBasedCompare: _, length, _ = queryOutputLength(expression, payload) else: length = None dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression)) count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) if not kb.bruteMode: debugMsg = "performed %d queries in %d seconds" % ( count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None): start = time.time() value = None count = 0 value = _goDns(payload, expression) if payload is None: return None if value is not None: return value timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if not (timeBasedCompare and kb.dnsTest): if (conf.eta or conf.threads > 1 ) and Backend.getIdentifiedDbms() and not re.search( r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not conf.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): expression = "SELECT %s FROM (%s)" % (field, expression) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): expression += " AS %s" % randomStr(lowercase=True, seed=hash(expression)) if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields.split( ','): nulledCastedField = agent.nullAndCastField(field) injExpression = expression.replace(field, nulledCastedField, 1) else: injExpression = expression length = queryOutputLength(injExpression, payload) else: length = None kb.inferenceMode = True count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) kb.inferenceMode = False if not kb.bruteMode: debugMsg = "performed %d queries in %.2f seconds" % ( count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def queryOutputLength(expression, payload): """ Returns the query output length. """ lengthQuery = queries[kb.dbms].length select = re.search("\ASELECT\s+", expression, re.I) selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I) selectExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I) miscExpr = re.search("\A(.+)", expression, re.I) if selectTopExpr or selectDistinctExpr or selectExpr: if selectTopExpr: regExpr = selectTopExpr.groups()[0] elif selectDistinctExpr: regExpr = selectDistinctExpr.groups()[0] elif selectExpr: regExpr = selectExpr.groups()[0] elif miscExpr: regExpr = miscExpr.groups()[0] if (select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I)) or len(regExpr) <= 1: return None, None, None if select: lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1) else: lengthExpr = lengthQuery % expression infoMsg = "retrieving the length of query output" logger.info(infoMsg) output = resume(lengthExpr, payload) if output: return 0, output, regExpr dataToSessionFile( "[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr)) lengthExprUnescaped = unescaper.unescape(lengthExpr) count, length = bisection(payload, lengthExprUnescaped) if length == " ": length = 0 return count, length, regExpr
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None): start = time.time() value = None count = 0 value = _goDns(payload, expression) if payload is None: return None if value is not None: return value timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if timeBasedCompare and conf.threads > 1 and kb.forceThreads is None: msg = "multi-threading is considered unsafe in " msg += "time-based data retrieval. Are you sure " msg += "of your choice (breaking warranty) [y/N] " kb.forceThreads = readInput(msg, default='N', boolean=True) if not (timeBasedCompare and kb.dnsTest): if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CUBRID): alias = randomStr(lowercase=True, seed=hash(expression)) expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example expression += " AS %s" % alias else: expression = "SELECT %s FROM (%s)" % (field, expression) if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields: nulledCastedField = agent.nullAndCastField(field) injExpression = expression.replace(field, nulledCastedField, 1) else: injExpression = expression length = queryOutputLength(injExpression, payload) else: length = None kb.inferenceMode = True count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) kb.inferenceMode = False if not kb.bruteMode: debugMsg = "performed %d queries in %.2f seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def queryOutputLength(expression, payload): """ Returns the query output length. """ lengthQuery = queries[kb.dbms].length select = re.search("\ASELECT\s+", expression, re.I) selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I) selectExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I) miscExpr = re.search("\A(.+)", expression, re.I) if selectTopExpr or selectDistinctExpr or selectExpr: if selectTopExpr: regExpr = selectTopExpr.groups()[0] elif selectDistinctExpr: regExpr = selectDistinctExpr.groups()[0] elif selectExpr: regExpr = selectExpr.groups()[0] elif miscExpr: regExpr = miscExpr.groups()[0] if ( select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I) ) or len(regExpr) <= 1: return None, None, None if select: lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1) else: lengthExpr = lengthQuery % expression infoMsg = "retrieving the length of query output" logger.info(infoMsg) output = resume(lengthExpr, payload) if output: return 0, output, regExpr dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], lengthExpr)) lengthExprUnescaped = unescaper.unescape(lengthExpr) count, length = bisection(payload, lengthExprUnescaped) if length == " ": length = 0 return count, length, regExpr
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None): start = time.time() if ( conf.eta or conf.threads > 1 ) and kb.dbms: _, length, _ = queryOutputLength(expression, payload) else: length = None dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression)) count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar) debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False, field=None): start = time.time() value = None count = 0 value = _goDns(payload, expression) if value: return value timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) if not (timeBasedCompare and kb.dnsTest): if ( (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search("(COUNT|LTRIM)\(", expression, re.I) and not timeBasedCompare ): if field and re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): expression = "SELECT %s FROM (%s)" % (field, expression) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): expression += " AS %s" % randomStr(lowercase=True) if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields.split(","): nulledCastedField = agent.nullAndCastField(field) injExpression = expression.replace(field, nulledCastedField, 1) else: injExpression = expression length = queryOutputLength(injExpression, payload) else: length = None kb.inferenceMode = True count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) kb.inferenceMode = False if not kb.bruteMode: debugMsg = "performed %d queries in %.2f seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None, dump=False): start = time.time() timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not timeBasedCompare: _, length, _ = queryOutputLength(expression, payload) else: length = None dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression)) count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar, dump) if not kb.bruteMode: debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) return value
def __goInference(payload, expression): start = time.time() if ( conf.eta or conf.threads > 1 ) and kb.dbms: _, length, _ = queryOutputLength(expression, payload) else: length = None dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression)) count, value = bisection(payload, expression, length=length) duration = int(time.time() - start) if conf.eta and length: infoMsg = "retrieved: %s" % value logger.info(infoMsg) infoMsg = "performed %d queries in %d seconds" % (count, duration) logger.info(infoMsg) return value
def __goInference(payload, expression): start = time.time() if (conf.eta or conf.threads > 1) and kb.dbms: _, length, _ = queryOutputLength(expression, payload) else: length = None dataToSessionFile( "[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression)) count, value = bisection(payload, expression, length=length) duration = int(time.time() - start) if conf.eta and length: infoMsg = "retrieved: %s" % value logger.info(infoMsg) infoMsg = "performed %d queries in %d seconds" % (count, duration) logger.info(infoMsg) return value
def resume(expression, payload): """ This function can be called to resume part or entire output of a SQL injection query output. """ try: if "sqlmapfile" in expression or "sqlmapoutput" in expression: return None condition = ( kb.resumedQueries and conf.url in kb.resumedQueries.keys() and expression in kb.resumedQueries[conf.url].keys() ) if not condition: return None resumedValue = kb.resumedQueries[conf.url][expression] if not resumedValue: return None resumedValue = restoreDumpMarkedChars(resumedValue, True) if resumedValue[-1] == "]": resumedValue = resumedValue[:-1] infoMsg = "read from file '%s': " % conf.sessionFile logValue = re.findall("%s(.*?)%s" % (DUMP_START_MARKER, DUMP_STOP_MARKER), resumedValue, re.S) if logValue: logValue = ", ".join([value.replace(DUMP_DEL_MARKER, ", ") for value in logValue]) else: logValue = resumedValue if "\n" in logValue: infoMsg += "%s..." % logValue.split("\n")[0] else: infoMsg += logValue logger.info(infoMsg) return resumedValue # If we called this function without providing a payload it means that # we have called it from lib/request/inject __goInband() function # in UNION query (inband) SQL injection so we return to the calling # function so that the query output will be retrieved taking advantage # of the inband SQL injection vulnerability. if not payload: return None if not kb.dbms: return None substringQuery = queries[kb.dbms].substring.query select = re.search("\ASELECT ", expression, re.I) _, length, regExpr = queryOutputLength(expression, payload) if not length: return None if len(resumedValue) == int(length): infoMsg = "read from file '%s': " % conf.sessionFile infoMsg += "%s" % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile( "[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, replaceNewlineTabs(resumedValue)) ) return resumedValue elif len(resumedValue) < int(length): infoMsg = "resumed from file '%s': " % conf.sessionFile infoMsg += "%s..." % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile( "[%s][%s][%s][%s][%s" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, replaceNewlineTabs(resumedValue)) ) if select: newExpr = expression.replace( regExpr, safeStringFormat(substringQuery, (regExpr, len(resumedValue) + 1, int(length))), 1 ) else: newExpr = safeStringFormat(substringQuery, (expression, len(resumedValue) + 1, int(length))) missingCharsLength = int(length) - len(resumedValue) infoMsg = "retrieving pending %d query " % missingCharsLength infoMsg += "output characters" logger.info(infoMsg) start = time.time() count, finalValue = bisection(payload, newExpr, length=missingCharsLength) debugMsg = "performed %d queries in %d seconds" % (count, calculateDeltaSeconds(start)) logger.debug(debugMsg) if len(finalValue) != (int(length) - len(resumedValue)): warnMsg = "the total length of the query is not " warnMsg += "right, sqlmap is going to retrieve the " warnMsg += "query value from the beginning now" logger.warn(warnMsg) return None return "%s%s" % (resumedValue, finalValue) return None except ValueError: errMsg = "invalid resume value for expression: '%s'" % expression logger.error(errMsg) return None
def resume(expression, payload): """ This function can be called to resume part or entire output of a SQL injection query output. """ condition = (kb.resumedQueries and conf.url in kb.resumedQueries.keys() and expression in kb.resumedQueries[conf.url].keys()) if not condition: return None resumedValue = kb.resumedQueries[conf.url][expression] if not resumedValue: return None if resumedValue[-1] == "]": resumedValue = resumedValue[:-1] infoMsg = "read from file '%s': " % conf.sessionFile logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S) if logValue: logValue = ", ".join( [value.replace("__DEL__", ", ") for value in logValue]) else: logValue = resumedValue if "\n" in logValue: infoMsg += "%s..." % logValue.split("\n")[0] else: infoMsg += logValue logger.info(infoMsg) return resumedValue # If we called this function without providing a payload it means that # we have called it from lib/request/inject __goInband() function # in UNION query (inband) SQL injection so we return to the calling # function so that the query output will be retrieved taking advantage # of the inband SQL injection vulnerability. if not payload: return None expressionUnescaped = unescaper.unescape(expression) substringQuery = queries[kb.dbms].substring select = re.search("\ASELECT ", expression, re.I) _, length, regExpr = queryOutputLength(expression, payload) if not length: return None if len(resumedValue) == int(length): infoMsg = "read from file '%s': " % conf.sessionFile infoMsg += "%s" % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, resumedValue)) return resumedValue elif len(resumedValue) < int(length): infoMsg = "resumed from file '%s': " % conf.sessionFile infoMsg += "%s..." % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, resumedValue)) if select: newExpr = expressionUnescaped.replace( regExpr, substringQuery % (regExpr, len(resumedValue) + 1, int(length)), 1) else: newExpr = substringQuery % (expressionUnescaped, len(resumedValue) + 1, int(length)) missingCharsLength = int(length) - len(resumedValue) infoMsg = "retrieving pending %d query " % missingCharsLength infoMsg += "output characters" logger.info(infoMsg) _, finalValue = bisection(payload, newExpr, length=missingCharsLength) if len(finalValue) != (int(length) - len(resumedValue)): warnMsg = "the total length of the query is not " warnMsg += "right, sqlmap is going to retrieve the " warnMsg += "query value from the beginning now" logger.warn(warnMsg) return None return "%s%s" % (resumedValue, finalValue) return None
def queryOutputLength(expression, payload): """ Returns the query output length. """ lengthQuery = queries[Backend.getIdentifiedDbms()].length.query select = re.search("\ASELECT\s+", expression, re.I) selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I) selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I) selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I) miscExpr = re.search("\A(.+)", expression, re.I) if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr: if selectTopExpr: regExpr = selectTopExpr.groups()[0] elif selectDistinctExpr: regExpr = selectDistinctExpr.groups()[0] elif selectFromExpr: regExpr = selectFromExpr.groups()[0] elif selectExpr: regExpr = selectExpr.groups()[0] elif miscExpr: regExpr = miscExpr.groups()[0] if (select and re.search("\A(COUNT|LTRIM)\(", regExpr, re.I)) or len(regExpr) <= 1: return None, None, None if selectDistinctExpr: lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr, expression) if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): lengthExpr += " AS %s" % randomStr(lowercase=True) elif select: lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1) else: lengthExpr = lengthQuery % expression infoMsg = "retrieving the length of query output" logger.info(infoMsg) output = resume(lengthExpr, payload) if output: return 0, output, regExpr dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], lengthExpr)) start = time.time() lengthExprUnescaped = unescaper.unescape(lengthExpr) count, length = bisection(payload, lengthExprUnescaped, charsetType=2) debugMsg = "performed %d queries in %d seconds" % ( count, calculateDeltaSeconds(start)) logger.debug(debugMsg) if length == " ": length = 0 return count, length, regExpr
def resume(expression, payload): """ This function can be called to resume part or entire output of a SQL injection query output. """ try: if "sqlmapfile" in expression or "sqlmapoutput" in expression or conf.freshQueries: return None condition = (kb.resumedQueries and conf.url in kb.resumedQueries.keys() and expression in kb.resumedQueries[conf.url].keys()) if not condition: return None resumedValue = kb.resumedQueries[conf.url][expression] if not resumedValue: return None resumedValue = restoreDumpMarkedChars(resumedValue, True) if resumedValue[-1] == "]": resumedValue = resumedValue[:-1] infoMsg = "read from file '%s': " % conf.sessionFile logValue = re.findall( "%s(.*?)%s" % (DUMP_START_MARKER, DUMP_STOP_MARKER), resumedValue, re.S) if logValue: if kb.technique == PAYLOAD.TECHNIQUE.UNION: logValue = ", ".join([ value.replace(DUMP_DEL_MARKER, ", ") for value in logValue ]) else: return None else: logValue = resumedValue if "\n" in logValue: infoMsg += "%s..." % logValue.split("\n")[0] else: infoMsg += logValue dataToStdout("[%s] [INFO] %s\n" % (time.strftime("%X"), infoMsg)) return resumedValue # If we called this function without providing a payload it means # that we have called it from lib/request/inject __goInband() or # from __goError() function so we return to the calling function # so that the query output will be retrieved taking advantage # of either error-based or inband SQL injection vulnerability. if not payload: return None if not Backend.getIdentifiedDbms(): return None substringQuery = queries[Backend.getIdentifiedDbms()].substring.query select = re.search("\ASELECT ", expression, re.I) _, length, regExpr = queryOutputLength(expression, payload) if not length: return None if len(resumedValue) == int(length): infoMsg = "read from file '%s': " % conf.sessionFile infoMsg += "%s" % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(resumedValue))) return resumedValue elif len(resumedValue) < int(length): infoMsg = "resumed from file '%s': " % conf.sessionFile infoMsg += "%s..." % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(resumedValue))) if select: newExpr = expression.replace( regExpr, safeStringFormat( substringQuery, (regExpr, len(resumedValue) + 1, int(length))), 1) else: newExpr = safeStringFormat( substringQuery, (expression, len(resumedValue) + 1, int(length))) missingCharsLength = int(length) - len(resumedValue) infoMsg = "retrieving pending %d query " % missingCharsLength infoMsg += "output characters" logger.info(infoMsg) start = time.time() count, finalValue = bisection(payload, newExpr, length=missingCharsLength) debugMsg = "performed %d queries in %d seconds" % ( count, calculateDeltaSeconds(start)) logger.debug(debugMsg) if len(finalValue) != (int(length) - len(resumedValue)): warnMsg = "the total length of the query is not " warnMsg += "right, sqlmap is going to retrieve the " warnMsg += "query value from the beginning now" logger.warn(warnMsg) return None return "%s%s" % (resumedValue, finalValue) return None except ValueError: errMsg = "invalid resume value for expression: '%s'" % expression logger.error(errMsg) return None
def resume(expression, payload): """ This function can be called to resume part or entire output of a SQL injection query output. """ condition = ( kb.resumedQueries and conf.url in kb.resumedQueries.keys() and expression in kb.resumedQueries[conf.url].keys() ) if not condition: return None resumedValue = kb.resumedQueries[conf.url][expression] if not resumedValue: return None if resumedValue[-1] == "]": resumedValue = resumedValue[:-1] infoMsg = "read from file '%s': " % conf.sessionFile logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S) if logValue: logValue = ", ".join([value.replace("__DEL__", ", ") for value in logValue]) else: logValue = resumedValue if "\n" in logValue: infoMsg += "%s..." % logValue.split("\n")[0] else: infoMsg += logValue logger.info(infoMsg) return resumedValue # If we called this function without providing a payload it means that # we have called it from lib/request/inject __goInband() function # in UNION query (inband) SQL injection so we return to the calling # function so that the query output will be retrieved taking advantage # of the inband SQL injection vulnerability. if not payload: return None expressionUnescaped = unescaper.unescape(expression) substringQuery = queries[kb.dbms].substring select = re.search("\ASELECT ", expression, re.I) _, length, regExpr = queryOutputLength(expression, payload) if not length: return None if len(resumedValue) == int(length): infoMsg = "read from file '%s': " % conf.sessionFile infoMsg += "%s" % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, resumedValue)) return resumedValue elif len(resumedValue) < int(length): infoMsg = "resumed from file '%s': " % conf.sessionFile infoMsg += "%s..." % resumedValue.split("\n")[0] logger.info(infoMsg) dataToSessionFile("[%s][%s][%s][%s][%s" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, resumedValue)) if select: newExpr = expressionUnescaped.replace(regExpr, substringQuery % (regExpr, len(resumedValue) + 1, int(length)), 1) else: newExpr = substringQuery % (expressionUnescaped, len(resumedValue) + 1, int(length)) missingCharsLength = int(length) - len(resumedValue) infoMsg = "retrieving pending %d query " % missingCharsLength infoMsg += "output characters" logger.info(infoMsg) _, finalValue = bisection(payload, newExpr, length=missingCharsLength) if len(finalValue) != ( int(length) - len(resumedValue) ): warnMsg = "the total length of the query is not " warnMsg += "right, sqlmap is going to retrieve the " warnMsg += "query value from the beginning now" logger.warn(warnMsg) return None return "%s%s" % (resumedValue, finalValue) return None