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

Skip to content

Commit 3a8309c

Browse files
committed
Major bug fix to detect UNION query technique and various improvements to parsing and using of --union-char and --union-cols switches
1 parent 707edc7 commit 3a8309c

5 files changed

Lines changed: 301 additions & 49 deletions

File tree

lib/controller/checks.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,29 @@ def checkSqlInjection(place, parameter, value):
8585
stype = test.stype
8686
clause = test.clause
8787

88-
if stype == 3:
88+
if stype == PAYLOAD.TECHNIQUE.UNION:
8989
configUnion(test.request.char)
9090

91+
if "[CHAR]" in title:
92+
if conf.uChar is None:
93+
continue
94+
else:
95+
title = title.replace("[CHAR]", conf.uChar)
96+
97+
elif "[RANDNUM]" in title or "(NULL)" in title:
98+
title = title.replace("[RANDNUM]", "random number")
99+
91100
if test.request.columns == "[COLSTART]-[COLSTOP]":
92101
if conf.uCols is None:
93102
continue
94103
else:
95104
title = title.replace("[COLSTART]", str(conf.uColsStart))
96105
title = title.replace("[COLSTOP]", str(conf.uColsStop))
97-
98-
if "[CHAR]" in title:
99-
title = title.replace("[CHAR]", conf.uChar)
100-
101-
if "[RANDNUM]" in title:
102-
title = title.replace("[RANDNUM]", "random number")
106+
elif conf.uCols is not None:
107+
debugMsg = "skipping test '%s' because the user " % title
108+
debugMsg += "provided custom column range %s" % conf.uCols
109+
logger.debug(debugMsg)
110+
continue
103111

104112
# Skip test if the user's wants to test only for a specific
105113
# technique
@@ -132,8 +140,9 @@ def checkSqlInjection(place, parameter, value):
132140
# value
133141
# Parse test's <level>
134142
if test.level > conf.level:
135-
debugMsg = "skipping test '%s' because the level " % title
136-
debugMsg += "is higher than the provided"
143+
debugMsg = "skipping test '%s' because the level" % title
144+
debugMsg += ", %d, is higher than the provided" % test.level
145+
debugMsg += ", %d" % conf.level
137146
logger.debug(debugMsg)
138147
continue
139148

@@ -195,11 +204,10 @@ def checkSqlInjection(place, parameter, value):
195204
logger.debug(debugMsg)
196205
continue
197206

198-
# Skip test if the user provided custom column
199-
# range and this is not a custom UNION test
200-
if conf.uCols is not None and hasattr(test.request, "columns") and test.request.columns != "[COLSTART]-[COLSTOP]":
201-
debugMsg = "skipping test '%s' because custom " % title
202-
debugMsg += "UNION columns range was provided"
207+
# Skip test if the user provided custom character
208+
if conf.uChar is not None and ("random number" in title or "(NULL)" in title):
209+
debugMsg = "skipping test '%s' because the user " % title
210+
debugMsg += "provided a specific character, %s" % conf.uChar
203211
logger.debug(debugMsg)
204212
continue
205213

lib/core/option.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,7 @@ def __setKnowledgeBaseAttributes(flushAll=True):
13661366
kb.threadContinue = True
13671367
kb.threadException = False
13681368
kb.threadData = {}
1369+
kb.uChar = "NULL"
13691370
kb.xpCmdshellAvailable = False
13701371

13711372
kb.misc = advancedDict()

lib/techniques/inband/union/test.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __findUnionCharCount(comment, place, parameter, value, prefix, suffix, where
6161
min_, max_ = MAX_RATIO, MIN_RATIO
6262

6363
for count in range(lowerCount, upperCount+1):
64-
query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, conf.uChar)
64+
query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, kb.uChar)
6565
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
6666
page, _ = Request.queryPage(payload, place=place, content=True, raise404=False)
6767
ratio = comparison(page, True) or MIN_RATIO
@@ -122,7 +122,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
122122
randQueryUnescaped = unescaper.unescape(randQueryProcessed)
123123

124124
# Forge the inband SQL injection request
125-
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar)
125+
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar)
126126
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
127127

128128
# Perform the request
@@ -141,7 +141,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
141141

142142
if content and phrase in content:
143143
validPayload = payload
144-
vector = (position, count, comment, prefix, suffix, conf.uChar, where)
144+
vector = (position, count, comment, prefix, suffix, kb.uChar, where)
145145

146146
if where == PAYLOAD.WHERE.ORIGINAL:
147147
# Prepare expression with delimiters
@@ -151,15 +151,15 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
151151
randQueryUnescaped2 = unescaper.unescape(randQueryProcessed2)
152152

153153
# Confirm that it is a full inband SQL injection
154-
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar, multipleUnions=randQueryUnescaped2)
154+
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, multipleUnions=randQueryUnescaped2)
155155
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=PAYLOAD.WHERE.NEGATIVE)
156156

157157
# Perform the request
158158
page, headers = Request.queryPage(payload, place=place, content=True, raise404=False)
159159
content = "%s%s".lower() % (page or "", listToStrValue(headers.headers if headers else None) or "")
160160

161161
if content and ((phrase in content and phrase2 not in content) or (phrase not in content and phrase2 in content)):
162-
vector = (position, count, comment, prefix, suffix, conf.uChar, PAYLOAD.WHERE.NEGATIVE)
162+
vector = (position, count, comment, prefix, suffix, kb.uChar, PAYLOAD.WHERE.NEGATIVE)
163163

164164
if not unionErrorCase:
165165
break
@@ -190,7 +190,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
190190

191191
validPayload = None
192192
vector = None
193-
query = agent.prefixQuery("UNION ALL SELECT %s" % conf.uChar)
193+
query = agent.prefixQuery("UNION ALL SELECT %s" % kb.uChar)
194194
total = conf.uColsStop+1 - conf.uColsStart
195195

196196
count = __findUnionCharCount(comment, place, parameter, value, prefix, suffix)
@@ -200,7 +200,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
200200
query = query[:-len(FROM_TABLE[Backend.getIdentifiedDbms()])]
201201

202202
if count:
203-
query += ", %s" % conf.uChar
203+
query += ", %s" % kb.uChar
204204

205205
if Backend.getIdentifiedDbms() in FROM_TABLE:
206206
query += FROM_TABLE[Backend.getIdentifiedDbms()]

lib/techniques/inband/union/use.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,18 @@ def __oneShotUnionUse(expression, unpack=True):
8888

8989
def configUnion(char=None, columns=None):
9090
def __configUnionChar(char):
91-
if isinstance(char, basestring):
92-
if any([char.isdigit(), char == "NULL", char == "[RANDNUM]"]):
93-
conf.uChar = char
94-
else:
95-
conf.uChar = "'%s'" % char.strip("'")
91+
if not isinstance(char, basestring):
92+
return
93+
94+
kb.uChar = char
95+
96+
if conf.uChar is not None:
97+
kb.uChar = char.replace("[CHAR]", conf.uChar if conf.uChar.isdigit() else "'%s'" % conf.uChar.strip("'"))
9698

9799
def __configUnionCols(columns):
100+
if not isinstance(columns, basestring):
101+
return
102+
98103
columns = columns.replace(" ", "")
99104
colsStart, colsStop = columns.split("-")
100105

@@ -109,15 +114,8 @@ def __configUnionCols(columns):
109114
errMsg += "higher number of columns"
110115
raise sqlmapSyntaxException, errMsg
111116

112-
if isinstance(conf.uChar, basestring):
113-
__configUnionChar(conf.uChar)
114-
elif isinstance(char, basestring):
115-
__configUnionChar(char)
116-
117-
if isinstance(conf.uCols, basestring):
118-
__configUnionCols(conf.uCols)
119-
elif isinstance(columns, basestring):
120-
__configUnionCols(columns)
117+
__configUnionChar(char)
118+
__configUnionCols(conf.uCols or columns)
121119

122120
def unionUse(expression, unpack=True, dump=False):
123121
"""

0 commit comments

Comments
 (0)