diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 0c06b515307..56664d50fd7 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -167,6 +167,38 @@ def _formatInjection(inj): return data +def _formatDictInjection(inj): + paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else inj.place + data = { + "parameter": inj.parameter, + "paramtype": paramType, + "injection": [] + } + + for stype, sdata in inj.data.items(): + title = sdata.title + vector = sdata.vector + comment = sdata.comment + payload = agent.adjustLateValues(sdata.payload) + if inj.place == PLACE.CUSTOM_HEADER: + payload = payload.split(',', 1)[1] + if stype == PAYLOAD.TECHNIQUE.UNION: + count = re.sub(r"(?i)(\(.+\))|(\blimit[^a-z]+)", "", sdata.payload).count(',') + 1 + title = re.sub(r"\d+ to \d+", str(count), title) + vector = agent.forgeUnionQuery("[QUERY]", vector[0], vector[1], vector[2], None, None, vector[5], vector[6]) + if count == 1: + title = title.replace("columns", "column") + elif comment: + vector = "%s%s" % (vector, comment) + injection = { + "type": PAYLOAD.SQLINJECTION[stype], + "payload": urldecode(payload, unsafe="&", spaceplus=(inj.place != PLACE.GET and kb.postSpaceToPlus)), + "vector": vector + } + data["injection"].append(injection) + + return data + def _showInjections(): if conf.wizard and kb.wizardMode: kb.wizardMode = False @@ -194,6 +226,18 @@ def _showInjections(): warnMsg += "included in shown payload content(s)" logger.warning(warnMsg) +def _saveInjections(): + data = [_formatDictInjection(inj) for inj in kb.injections] + + if conf.jsonFile: + data = { + "url": conf.url, + "query": conf.parameters.get(PLACE.GET), + "data": conf.parameters.get(PLACE.POST), + "injections": data, + } + conf.dumper.json(conf.jsonFile, data) + def _randomFillBlankFields(value): retVal = value @@ -649,6 +693,7 @@ def start(): if place == PLACE.COOKIE: kb.mergeCookies = popValue() + _saveInjections() if len(kb.injections) == 0 or (len(kb.injections) == 1 and kb.injections[0].place is None): if kb.vainRun and not conf.multipleTargets: errMsg = "no parameter(s) found for testing in the provided data " diff --git a/lib/core/common.py b/lib/core/common.py index 3d6360bb84c..5a8c8b3f2c8 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1071,6 +1071,10 @@ def dataToDumpFile(dumpFile, data): errMsg = "error occurred when writing dump data to file ('%s')" % getUnicode(ex) logger.error(errMsg) +def dataToJsonFile(jsonFile, data): + with open(jsonFile, 'w') as f: + f.write(json.dumps(data)) + def dataToOutFile(filename, data): """ Saves data to filename diff --git a/lib/core/dump.py b/lib/core/dump.py index 2e3cdfde635..c8a058fa55e 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -15,6 +15,7 @@ from lib.core.common import Backend from lib.core.common import checkFile from lib.core.common import dataToDumpFile +from lib.core.common import dataToJsonFile from lib.core.common import dataToStdout from lib.core.common import filterNone from lib.core.common import getSafeExString @@ -143,6 +144,9 @@ def string(self, header, data, content_type=None, sort=True): else: self._write("%s: %s" % (header, ("'%s'" % _) if isinstance(data, six.string_types) else _)) + def json(self, jsonFile, data): + dataToJsonFile(jsonFile, data) + def lister(self, header, elements, content_type=None, sort=True): if elements and sort: try: diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index b4dd0af7584..a4e48c095d5 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -219,6 +219,7 @@ "crawlExclude": "string", "csvDel": "string", "dumpFile": "string", + "jsonFile": "string", "dumpFormat": "string", "encoding": "string", "eta": "boolean", diff --git a/lib/core/settings.py b/lib/core/settings.py index 5fec2e40754..82447cff3a3 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -20,7 +20,7 @@ from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.7.11.2" +VERSION = "1.7.11.3" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index b62a790378d..6bf82e68ccc 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -673,6 +673,9 @@ def cmdLineParser(argv=None): general.add_argument("--dump-file", dest="dumpFile", help="Store dumped data to a custom file") + general.add_argument("--json-file", dest="jsonFile", + help="Store json data to a custom file") + general.add_argument("--dump-format", dest="dumpFormat", help="Format of dumped data (CSV (default), HTML or SQLITE)") diff --git a/sqlmap.conf b/sqlmap.conf index 114324e8d52..e0fbfc3c7df 100644 --- a/sqlmap.conf +++ b/sqlmap.conf @@ -753,6 +753,9 @@ csvDel = , # Store dumped data to a custom file. dumpFile = +# Store json data to a custom file. +jsonFile = + # Format of dumped data # Valid: CSV, HTML or SQLITE dumpFormat = CSV