From 3ca23364a3f6ab6daa9c78cdd83b5820d051b1fd Mon Sep 17 00:00:00 2001 From: bkbilly Date: Tue, 25 Jul 2023 13:09:04 +0300 Subject: [PATCH 1/4] Add support for json file output --- lib/controller/controller.py | 9 +++++++++ lib/core/common.py | 7 +++++++ lib/core/dump.py | 4 ++++ lib/core/optiondict.py | 1 + lib/parse/cmdline.py | 3 +++ sqlmap.conf | 3 +++ 6 files changed, 27 insertions(+) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 8441279a954..27398d3b300 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -177,6 +177,15 @@ def _showInjections(): else: header = "sqlmap resumed the following injection point(s) from stored session" + if conf.jsonFile: + data = { + "url": conf.url, + "query": conf.parameters.get(PLACE.GET), + "data": conf.parameters.get(PLACE.POST), + "injections": kb.injections, + } + conf.dumper.json(conf.jsonFile, data) + if conf.api: conf.dumper.string("", {"url": conf.url, "query": conf.parameters.get(PLACE.GET), "data": conf.parameters.get(PLACE.POST)}, content_type=CONTENT_TYPE.TARGET) conf.dumper.string("", kb.injections, content_type=CONTENT_TYPE.TECHNIQUES) diff --git a/lib/core/common.py b/lib/core/common.py index d235b838a86..75bba1b0bfe 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1071,6 +1071,13 @@ def dataToDumpFile(dumpFile, data): errMsg = "error occurred when writing dump data to file ('%s')" % getUnicode(ex) logger.error(errMsg) +def dataToJsonFile(jsonFile, data): + print("***************") + print(jsonFile, data) + print("***************") + 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 761ee99558b..71abe3e50a8 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -218,6 +218,7 @@ "crawlExclude": "string", "csvDel": "string", "dumpFile": "string", + "jsonFile": "string", "dumpFormat": "string", "encoding": "string", "eta": "boolean", diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index b1074166cf8..c121c8fd38f 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -670,6 +670,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 895b601155f..3e4cbd6e857 100644 --- a/sqlmap.conf +++ b/sqlmap.conf @@ -748,6 +748,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 From 6152c08cc9cc4b22aa0b2cab416e2249d2a3802d Mon Sep 17 00:00:00 2001 From: bkbilly Date: Tue, 25 Jul 2023 13:15:28 +0300 Subject: [PATCH 2/4] bump version --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 44b3104f081..15d29fe3172 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.7.2" +VERSION = "1.7.7.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) From 1da1e604bda6830f152c3b090c5fa01820e8ec57 Mon Sep 17 00:00:00 2001 From: bkbilly Date: Tue, 25 Jul 2023 13:30:12 +0300 Subject: [PATCH 3/4] Always save injections --- lib/controller/controller.py | 20 +++++++++++--------- lib/core/common.py | 3 --- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 27398d3b300..7d43290a865 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -177,15 +177,6 @@ def _showInjections(): else: header = "sqlmap resumed the following injection point(s) from stored session" - if conf.jsonFile: - data = { - "url": conf.url, - "query": conf.parameters.get(PLACE.GET), - "data": conf.parameters.get(PLACE.POST), - "injections": kb.injections, - } - conf.dumper.json(conf.jsonFile, data) - if conf.api: conf.dumper.string("", {"url": conf.url, "query": conf.parameters.get(PLACE.GET), "data": conf.parameters.get(PLACE.POST)}, content_type=CONTENT_TYPE.TARGET) conf.dumper.string("", kb.injections, content_type=CONTENT_TYPE.TECHNIQUES) @@ -203,6 +194,16 @@ def _showInjections(): warnMsg += "included in shown payload content(s)" logger.warning(warnMsg) +def _saveInjections(): + if conf.jsonFile: + data = { + "url": conf.url, + "query": conf.parameters.get(PLACE.GET), + "data": conf.parameters.get(PLACE.POST), + "injections": kb.injections, + } + conf.dumper.json(conf.jsonFile, data) + def _randomFillBlankFields(value): retVal = value @@ -658,6 +659,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 75bba1b0bfe..06fb4743800 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1072,9 +1072,6 @@ def dataToDumpFile(dumpFile, data): logger.error(errMsg) def dataToJsonFile(jsonFile, data): - print("***************") - print(jsonFile, data) - print("***************") with open(jsonFile, 'w') as f: f.write(json.dumps(data)) From f267c9c1f5cd8b1c0bab962728f113ec8cc184cd Mon Sep 17 00:00:00 2001 From: bkbilly Date: Tue, 25 Jul 2023 15:26:33 +0300 Subject: [PATCH 4/4] Formated json output --- lib/controller/controller.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 7d43290a865..e2578bb8518 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 @@ -195,12 +227,14 @@ def _showInjections(): 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": kb.injections, + "injections": data, } conf.dumper.json(conf.jsonFile, data)