Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 585645e

Browse files
committed
Implements #4403
1 parent 673a5af commit 585645e

4 files changed

Lines changed: 39 additions & 23 deletions

File tree

lib/core/option.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
20582058
kb.identifiedWafs = set()
20592059
kb.injection = InjectionDict()
20602060
kb.injections = []
2061+
kb.jsonAggMode = False
20612062
kb.laggingChecked = False
20622063
kb.lastParserStatus = None
20632064

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from thirdparty.six import unichr as _unichr
1919

2020
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
21-
VERSION = "1.4.10.19"
21+
VERSION = "1.4.10.20"
2222
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2323
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2424
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

lib/techniques/union/use.py

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import binascii
9+
import json
910
import re
1011
import time
1112
import xml.etree.ElementTree
@@ -74,7 +75,7 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
7475
if retVal is None:
7576
vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector
7677

77-
if not kb.rowXmlMode:
78+
if not any((kb.rowXmlMode, kb.jsonAggMode)):
7879
injExpression = unescaper.escape(agent.concatQuery(expression, unpack))
7980
kb.unionDuplicates = vector[7]
8081
kb.forcePartialUnion = vector[8]
@@ -99,24 +100,8 @@ def _oneShotUnionUse(expression, unpack=True, limited=False):
99100

100101
incrementCounter(PAYLOAD.TECHNIQUE.UNION)
101102

102-
if not kb.rowXmlMode:
103-
# Parse the returned page to get the exact UNION-based
104-
# SQL injection output
105-
def _(regex):
106-
return firstNotNone(
107-
extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE),
108-
extractRegexResult(regex, removeReflectiveValues(listToStrValue((_ for _ in headers.headers if not _.startswith(HTTP_HEADER.URI)) if headers else None), payload, True), re.DOTALL | re.IGNORECASE)
109-
)
110-
111-
# Automatically patching last char trimming cases
112-
if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""):
113-
warnMsg = "automatically patching output having last char trimmed"
114-
singleTimeWarnMessage(warnMsg)
115-
page = page.replace(kb.chars.stop[:-1], kb.chars.stop)
116-
117-
retVal = _("(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop))
118-
else:
119-
output = extractRegexResult(r"(?P<result>(<row.+?/>)+)", page)
103+
if kb.rowXmlMode:
104+
output = extractRegexResult(r"(?P<result>(<row.+?/>)+)", page or "")
120105
if output:
121106
try:
122107
root = xml.etree.ElementTree.fromstring(safeStringFormat("<root>%s</root>", getBytes(output)))
@@ -149,6 +134,28 @@ def _(regex):
149134
pass
150135
else:
151136
retVal = getUnicode(retVal)
137+
elif kb.jsonAggMode:
138+
output = extractRegexResult(r"(?P<result>%s.*?%s)" % (kb.chars.start, kb.chars.stop), page or "")
139+
if output:
140+
retVal = ""
141+
for row in json.loads(output[len(kb.chars.start):-len(kb.chars.stop)]):
142+
retVal += "%s%s%s" % (kb.chars.start, row, kb.chars.stop)
143+
else:
144+
# Parse the returned page to get the exact UNION-based
145+
# SQL injection output
146+
def _(regex):
147+
return firstNotNone(
148+
extractRegexResult(regex, removeReflectiveValues(page, payload), re.DOTALL | re.IGNORECASE),
149+
extractRegexResult(regex, removeReflectiveValues(listToStrValue((_ for _ in headers.headers if not _.startswith(HTTP_HEADER.URI)) if headers else None), payload, True), re.DOTALL | re.IGNORECASE)
150+
)
151+
152+
# Automatically patching last char trimming cases
153+
if kb.chars.stop not in (page or "") and kb.chars.stop[:-1] in (page or ""):
154+
warnMsg = "automatically patching output having last char trimmed"
155+
singleTimeWarnMessage(warnMsg)
156+
page = page.replace(kb.chars.stop[:-1], kb.chars.stop)
157+
158+
retVal = _("(?P<result>%s.*%s)" % (kb.chars.start, kb.chars.stop))
152159

153160
if retVal is not None:
154161
retVal = getUnicode(retVal, kb.pageEncoding)
@@ -159,7 +166,7 @@ def _(regex):
159166

160167
hashDBWrite("%s%s" % (conf.hexConvert or False, expression), retVal)
161168

162-
elif not kb.rowXmlMode:
169+
elif not any((kb.rowXmlMode, kb.jsonAggMode)):
163170
trimmed = _("%s(?P<result>.*?)<" % (kb.chars.start))
164171

165172
if trimmed:
@@ -236,7 +243,15 @@ def unionUse(expression, unpack=True, dump=False):
236243
# Set kb.partRun in case the engine is called from the API
237244
kb.partRun = getPartRun(alias=False) if conf.api else None
238245

239-
if Backend.isDbms(DBMS.MSSQL) and kb.dumpColumns:
246+
if Backend.isDbms(DBMS.MYSQL) and expressionFields:
247+
match = re.search(r"SELECT\s*(.+?)\bFROM", expression, re.I)
248+
if match:
249+
kb.jsonAggMode = True
250+
_ = expression.replace(expressionFields, "CONCAT('%s',JSON_ARRAYAGG(CONCAT_WS('%s',%s)),'%s')" % (kb.chars.start, kb.chars.delimiter, expressionFields, kb.chars.stop), 1)
251+
output = _oneShotUnionUse(_, False)
252+
value = parseUnionPage(output)
253+
kb.jsonAggMode = False
254+
elif Backend.isDbms(DBMS.MSSQL) and kb.dumpColumns:
240255
kb.rowXmlMode = True
241256
_ = "(%s FOR XML RAW, BINARY BASE64)" % expression
242257
output = _oneShotUnionUse(_, False)

plugins/generic/entries.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def dumpTable(self, foundData=None):
159159
continue
160160

161161
kb.dumpColumns = [unsafeSQLIdentificatorNaming(_) for _ in colList]
162-
colNames = colString = ", ".join(column for column in colList)
162+
colNames = colString = ','.join(column for column in colList)
163163
rootQuery = queries[Backend.getIdentifiedDbms()].dump_table
164164

165165
infoMsg = "fetching entries"

0 commit comments

Comments
 (0)