diff --git a/lib/controller/controller.py b/lib/controller/controller.py index a30051df5..9e26b6504 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -7,6 +7,7 @@ Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ +import os import re from lib.controller.action import action @@ -22,6 +23,7 @@ from lib.controller.checks import simpletonCheckSqlInjection from lib.core.agent import agent from lib.core.common import extractRegexResult from lib.core.common import getFilteredPageContent +from lib.core.common import getPublicTypeMembers from lib.core.common import getUnicode from lib.core.common import intersect from lib.core.common import paramToDict @@ -154,6 +156,34 @@ def __saveToSessionFile(): setInjection(inj) +def __saveToResultsFile(): + if not conf.resultsFP: + return + + techniques = dict(map(lambda x: (x[1], x[0]), getPublicTypeMembers(PAYLOAD.TECHNIQUE))) + + found = False + + results = {} + for inj in kb.injections: + if inj.place is None or inj.parameter is None: + continue + + key = (inj.place, inj.parameter) + if key not in results: + results[key] = [] + + results[key].extend(inj.data.keys()) + + for key, value in results.items(): + place, parameter = key + line = "%s,%s,%s,%s%s" % (conf.url, place, parameter, "".join(map(lambda x: techniques[x][0].upper(), sorted(value))), os.linesep) + conf.resultsFP.writelines(line) + + if not results: + line = "%s,,,%s" % (conf.url, os.linesep) + conf.resultsFP.writelines(line) + def start(): """ This function calls a function that performs checks on both URL @@ -467,6 +497,7 @@ def start(): kb.testMode = False __saveToSessionFile() + __saveToResultsFile() __showInjections() __selectInjection() @@ -523,4 +554,9 @@ def start(): if kb.dataOutputFlag and not conf.multipleTargets: logger.info("Fetched data logged to text files under '%s'" % conf.outputPath) + if conf.multipleTargets: + infoMsg = "you can find results of scanning in multiple targets mode " + infoMsg += "inside the CSV file '%s'" % conf.resultsFilename + logger.info(infoMsg) + return True diff --git a/lib/core/option.py b/lib/core/option.py index 4a528b97d..d78dd75f4 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1297,6 +1297,8 @@ def __setConfAttributes(): conf.path = None conf.port = None conf.redirectHandled = False + conf.resultsFilename = None + conf.resultsFP = None conf.scheme = None conf.sessionFP = None conf.start = True diff --git a/lib/core/settings.py b/lib/core/settings.py index 24eba1c2e..209d3e20e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -327,3 +327,6 @@ IGNORE_PARAMETERS = ("__VIEWSTATE", "__EVENTARGUMENT", "__EVENTTARGET", "__EVENT # Turn off resume console info to avoid potential slowdowns TURN_OFF_RESUME_INFO_LIMIT = 20 + +# Strftime format for results file used in multiple target mode +RESULTS_FILE_FORMAT = 'results-%I%M%p_%m%d%Y.csv' diff --git a/lib/core/target.py b/lib/core/target.py index f19286395..a009f7ec6 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -34,6 +34,7 @@ from lib.core.option import __setDBMS from lib.core.option import __setKnowledgeBaseAttributes from lib.core.session import resumeConfKb from lib.core.settings import REFERER_ALIASES +from lib.core.settings import RESULTS_FILE_FORMAT from lib.core.settings import SOAP_REGEX from lib.core.settings import UNICODE_ENCODING from lib.core.settings import URI_INJECTABLE_REGEX @@ -234,6 +235,22 @@ def __setOutputResume(): errMsg = "unable to write on the session file specified" raise sqlmapFilePathException, errMsg +def __setResultsFile(): + """ + Create results file for storing results of running in a + multiple target mode. + """ + + if not conf.multipleTargets: + return + + if not conf.resultsFP: + conf.resultsFilename = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, time.strftime(RESULTS_FILE_FORMAT).lower()) + conf.resultsFP = codecs.open(conf.resultsFilename, "w+", UNICODE_ENCODING) + conf.resultsFP.writelines("Target url,Place,Parameter,Techniques%s" % os.linesep) + + logger.info("using '%s' as results file" % conf.resultsFilename) + def __createFilesDir(): """ Create the file directory. @@ -336,3 +353,4 @@ def setupTargetEnv(): __createTargetDirs() __setRequestParams() __setOutputResume() + __setResultsFile()