Major bug fix to detect UNION query technique and various improvements to parsing and using of --union-char and --union-cols switches

This commit is contained in:
Bernardo Damele 2011-05-10 15:34:54 +00:00
parent 707edc7b1a
commit 3a8309c4b0
5 changed files with 301 additions and 49 deletions

View File

@ -85,21 +85,29 @@ def checkSqlInjection(place, parameter, value):
stype = test.stype stype = test.stype
clause = test.clause clause = test.clause
if stype == 3: if stype == PAYLOAD.TECHNIQUE.UNION:
configUnion(test.request.char) configUnion(test.request.char)
if "[CHAR]" in title:
if conf.uChar is None:
continue
else:
title = title.replace("[CHAR]", conf.uChar)
elif "[RANDNUM]" in title or "(NULL)" in title:
title = title.replace("[RANDNUM]", "random number")
if test.request.columns == "[COLSTART]-[COLSTOP]": if test.request.columns == "[COLSTART]-[COLSTOP]":
if conf.uCols is None: if conf.uCols is None:
continue continue
else: else:
title = title.replace("[COLSTART]", str(conf.uColsStart)) title = title.replace("[COLSTART]", str(conf.uColsStart))
title = title.replace("[COLSTOP]", str(conf.uColsStop)) title = title.replace("[COLSTOP]", str(conf.uColsStop))
elif conf.uCols is not None:
if "[CHAR]" in title: debugMsg = "skipping test '%s' because the user " % title
title = title.replace("[CHAR]", conf.uChar) debugMsg += "provided custom column range %s" % conf.uCols
logger.debug(debugMsg)
if "[RANDNUM]" in title: continue
title = title.replace("[RANDNUM]", "random number")
# Skip test if the user's wants to test only for a specific # Skip test if the user's wants to test only for a specific
# technique # technique
@ -132,8 +140,9 @@ def checkSqlInjection(place, parameter, value):
# value # value
# Parse test's <level> # Parse test's <level>
if test.level > conf.level: if test.level > conf.level:
debugMsg = "skipping test '%s' because the level " % title debugMsg = "skipping test '%s' because the level" % title
debugMsg += "is higher than the provided" debugMsg += ", %d, is higher than the provided" % test.level
debugMsg += ", %d" % conf.level
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
@ -195,11 +204,10 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
# Skip test if the user provided custom column # Skip test if the user provided custom character
# range and this is not a custom UNION test if conf.uChar is not None and ("random number" in title or "(NULL)" in title):
if conf.uCols is not None and hasattr(test.request, "columns") and test.request.columns != "[COLSTART]-[COLSTOP]": debugMsg = "skipping test '%s' because the user " % title
debugMsg = "skipping test '%s' because custom " % title debugMsg += "provided a specific character, %s" % conf.uChar
debugMsg += "UNION columns range was provided"
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue

View File

@ -1366,6 +1366,7 @@ def __setKnowledgeBaseAttributes(flushAll=True):
kb.threadContinue = True kb.threadContinue = True
kb.threadException = False kb.threadException = False
kb.threadData = {} kb.threadData = {}
kb.uChar = "NULL"
kb.xpCmdshellAvailable = False kb.xpCmdshellAvailable = False
kb.misc = advancedDict() kb.misc = advancedDict()

View File

@ -61,7 +61,7 @@ def __findUnionCharCount(comment, place, parameter, value, prefix, suffix, where
min_, max_ = MAX_RATIO, MIN_RATIO min_, max_ = MAX_RATIO, MIN_RATIO
for count in range(lowerCount, upperCount+1): for count in range(lowerCount, upperCount+1):
query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, conf.uChar) query = agent.forgeInbandQuery('', -1, count, comment, prefix, suffix, kb.uChar)
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
page, _ = Request.queryPage(payload, place=place, content=True, raise404=False) page, _ = Request.queryPage(payload, place=place, content=True, raise404=False)
ratio = comparison(page, True) or MIN_RATIO ratio = comparison(page, True) or MIN_RATIO
@ -122,7 +122,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
randQueryUnescaped = unescaper.unescape(randQueryProcessed) randQueryUnescaped = unescaper.unescape(randQueryProcessed)
# Forge the inband SQL injection request # Forge the inband SQL injection request
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar) query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar)
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=where)
# Perform the request # Perform the request
@ -141,7 +141,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
if content and phrase in content: if content and phrase in content:
validPayload = payload validPayload = payload
vector = (position, count, comment, prefix, suffix, conf.uChar, where) vector = (position, count, comment, prefix, suffix, kb.uChar, where)
if where == PAYLOAD.WHERE.ORIGINAL: if where == PAYLOAD.WHERE.ORIGINAL:
# Prepare expression with delimiters # Prepare expression with delimiters
@ -151,7 +151,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
randQueryUnescaped2 = unescaper.unescape(randQueryProcessed2) randQueryUnescaped2 = unescaper.unescape(randQueryProcessed2)
# Confirm that it is a full inband SQL injection # Confirm that it is a full inband SQL injection
query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, conf.uChar, multipleUnions=randQueryUnescaped2) query = agent.forgeInbandQuery(randQueryUnescaped, position, count, comment, prefix, suffix, kb.uChar, multipleUnions=randQueryUnescaped2)
payload = agent.payload(place=place, parameter=parameter, newValue=query, where=PAYLOAD.WHERE.NEGATIVE) payload = agent.payload(place=place, parameter=parameter, newValue=query, where=PAYLOAD.WHERE.NEGATIVE)
# Perform the request # Perform the request
@ -159,7 +159,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, count, whe
content = "%s%s".lower() % (page or "", listToStrValue(headers.headers if headers else None) or "") content = "%s%s".lower() % (page or "", listToStrValue(headers.headers if headers else None) or "")
if content and ((phrase in content and phrase2 not in content) or (phrase not in content and phrase2 in content)): if content and ((phrase in content and phrase2 not in content) or (phrase not in content and phrase2 in content)):
vector = (position, count, comment, prefix, suffix, conf.uChar, PAYLOAD.WHERE.NEGATIVE) vector = (position, count, comment, prefix, suffix, kb.uChar, PAYLOAD.WHERE.NEGATIVE)
if not unionErrorCase: if not unionErrorCase:
break break
@ -190,7 +190,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
validPayload = None validPayload = None
vector = None vector = None
query = agent.prefixQuery("UNION ALL SELECT %s" % conf.uChar) query = agent.prefixQuery("UNION ALL SELECT %s" % kb.uChar)
total = conf.uColsStop+1 - conf.uColsStart total = conf.uColsStop+1 - conf.uColsStart
count = __findUnionCharCount(comment, place, parameter, value, prefix, suffix) count = __findUnionCharCount(comment, place, parameter, value, prefix, suffix)
@ -200,7 +200,7 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
query = query[:-len(FROM_TABLE[Backend.getIdentifiedDbms()])] query = query[:-len(FROM_TABLE[Backend.getIdentifiedDbms()])]
if count: if count:
query += ", %s" % conf.uChar query += ", %s" % kb.uChar
if Backend.getIdentifiedDbms() in FROM_TABLE: if Backend.getIdentifiedDbms() in FROM_TABLE:
query += FROM_TABLE[Backend.getIdentifiedDbms()] query += FROM_TABLE[Backend.getIdentifiedDbms()]

View File

@ -88,13 +88,18 @@ def __oneShotUnionUse(expression, unpack=True):
def configUnion(char=None, columns=None): def configUnion(char=None, columns=None):
def __configUnionChar(char): def __configUnionChar(char):
if isinstance(char, basestring): if not isinstance(char, basestring):
if any([char.isdigit(), char == "NULL", char == "[RANDNUM]"]): return
conf.uChar = char
else: kb.uChar = char
conf.uChar = "'%s'" % char.strip("'")
if conf.uChar is not None:
kb.uChar = char.replace("[CHAR]", conf.uChar if conf.uChar.isdigit() else "'%s'" % conf.uChar.strip("'"))
def __configUnionCols(columns): def __configUnionCols(columns):
if not isinstance(columns, basestring):
return
columns = columns.replace(" ", "") columns = columns.replace(" ", "")
colsStart, colsStop = columns.split("-") colsStart, colsStop = columns.split("-")
@ -109,15 +114,8 @@ def configUnion(char=None, columns=None):
errMsg += "higher number of columns" errMsg += "higher number of columns"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
if isinstance(conf.uChar, basestring): __configUnionChar(char)
__configUnionChar(conf.uChar) __configUnionCols(conf.uCols or columns)
elif isinstance(char, basestring):
__configUnionChar(char)
if isinstance(conf.uCols, basestring):
__configUnionCols(conf.uCols)
elif isinstance(columns, basestring):
__configUnionCols(columns)
def unionUse(expression, unpack=True, dump=False): def unionUse(expression, unpack=True, dump=False):
""" """

View File

@ -2320,7 +2320,29 @@ Formats:
<!-- UNION query tests --> <!-- UNION query tests -->
<test> <test>
<title>MySQL UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns</title> <title>MySQL UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom)</title>
<stype>3</stype>
<level>1</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request>
<payload/>
<comment>#</comment>
<char>[CHAR]</char>
<columns>[COLSTART]-[COLSTOP]</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL UNION query (NULL) - [COLSTART] to [COLSTOP] columns (custom)</title>
<stype>3</stype> <stype>3</stype>
<level>1</level> <level>1</level>
<risk>1</risk> <risk>1</risk>
@ -2342,7 +2364,7 @@ Formats:
</test> </test>
<test> <test>
<title>MySQL UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns</title> <title>MySQL UNION query ([RANDNUM]) - [COLSTART] to [COLSTOP] columns (custom)</title>
<stype>3</stype> <stype>3</stype>
<level>3</level> <level>3</level>
<risk>1</risk> <risk>1</risk>
@ -2371,6 +2393,28 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>#</comment>
<char>[CHAR]</char>
<columns>1-10</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL UNION query (NULL) - 1 to 10 columns</title>
<stype>3</stype>
<level>1</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>#</comment> <comment>#</comment>
@ -2386,7 +2430,7 @@ Formats:
</test> </test>
<test> <test>
<title>MySQL UNION query ([CHAR]) - 1 to 10 columns</title> <title>MySQL UNION query ([RANDNUM]) - 1 to 10 columns</title>
<stype>3</stype> <stype>3</stype>
<level>3</level> <level>3</level>
<risk>1</risk> <risk>1</risk>
@ -2415,6 +2459,28 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>#</comment>
<char>[CHAR]</char>
<columns>11-20</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL UNION query (NULL) - 11 to 20 columns</title>
<stype>3</stype>
<level>2</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>#</comment> <comment>#</comment>
@ -2430,7 +2496,7 @@ Formats:
</test> </test>
<test> <test>
<title>MySQL UNION query ([CHAR]) - 11 to 20 columns</title> <title>MySQL UNION query ([RANDNUM]) - 11 to 20 columns</title>
<stype>3</stype> <stype>3</stype>
<level>3</level> <level>3</level>
<risk>1</risk> <risk>1</risk>
@ -2459,6 +2525,28 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>#</comment>
<char>[CHAR]</char>
<columns>21-30</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL UNION query (NULL) - 21 to 30 columns</title>
<stype>3</stype>
<level>3</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>#</comment> <comment>#</comment>
@ -2474,7 +2562,7 @@ Formats:
</test> </test>
<test> <test>
<title>MySQL UNION query ([CHAR]) - 21 to 30 columns</title> <title>MySQL UNION query ([RANDNUM]) - 21 to 30 columns</title>
<stype>3</stype> <stype>3</stype>
<level>4</level> <level>4</level>
<risk>1</risk> <risk>1</risk>
@ -2503,6 +2591,28 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>#</comment>
<char>[CHAR]</char>
<columns>31-40</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL UNION query (NULL) - 31 to 40 columns</title>
<stype>3</stype>
<level>4</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>#</comment> <comment>#</comment>
@ -2518,7 +2628,7 @@ Formats:
</test> </test>
<test> <test>
<title>MySQL UNION query ([CHAR]) - 31 to 40 columns</title> <title>MySQL UNION query ([RANDNUM]) - 31 to 40 columns</title>
<stype>3</stype> <stype>3</stype>
<level>5</level> <level>5</level>
<risk>1</risk> <risk>1</risk>
@ -2547,6 +2657,28 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>#</comment>
<char>[CHAR]</char>
<columns>41-50</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL UNION query (NULL) - 41 to 50 columns</title>
<stype>3</stype>
<level>5</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>#</comment> <comment>#</comment>
@ -2562,7 +2694,7 @@ Formats:
</test> </test>
<test> <test>
<title>MySQL UNION query ([CHAR]) - 41 to 50 columns</title> <title>MySQL UNION query ([RANDNUM]) - 41 to 50 columns</title>
<stype>3</stype> <stype>3</stype>
<level>5</level> <level>5</level>
<risk>1</risk> <risk>1</risk>
@ -2584,7 +2716,26 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns</title> <title>Generic UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom)</title>
<stype>3</stype>
<level>1</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request>
<payload/>
<comment>--</comment>
<char>[CHAR]</char>
<columns>[COLSTART]-[COLSTOP]</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic UNION query (NULL) - [COLSTART] to [COLSTOP] columns (custom)</title>
<stype>3</stype> <stype>3</stype>
<level>1</level> <level>1</level>
<risk>1</risk> <risk>1</risk>
@ -2603,7 +2754,7 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns</title> <title>Generic UNION query ([RANDNUM]) - [COLSTART] to [COLSTOP] columns (custom)</title>
<stype>3</stype> <stype>3</stype>
<level>3</level> <level>3</level>
<risk>1</risk> <risk>1</risk>
@ -2629,6 +2780,25 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>--</comment>
<char>[CHAR]</char>
<columns>1-10</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic UNION query (NULL) - 1 to 10 columns</title>
<stype>3</stype>
<level>1</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>--</comment> <comment>--</comment>
@ -2641,7 +2811,7 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - 1 to 10 columns</title> <title>Generic UNION query ([RANDNUM]) - 1 to 10 columns</title>
<stype>3</stype> <stype>3</stype>
<level>3</level> <level>3</level>
<risk>1</risk> <risk>1</risk>
@ -2667,6 +2837,25 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>--</comment>
<char>[CHAR]</char>
<columns>11-20</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic UNION query (NULL) - 11 to 20 columns</title>
<stype>3</stype>
<level>2</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>--</comment> <comment>--</comment>
@ -2679,7 +2868,7 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - 11 to 20 columns</title> <title>Generic UNION query ([RANDNUM]) - 11 to 20 columns</title>
<stype>3</stype> <stype>3</stype>
<level>3</level> <level>3</level>
<risk>1</risk> <risk>1</risk>
@ -2705,6 +2894,25 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>--</comment>
<char>[CHAR]</char>
<columns>21-30</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic UNION query (NULL) - 21 to 30 columns</title>
<stype>3</stype>
<level>3</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>--</comment> <comment>--</comment>
@ -2717,7 +2925,7 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - 21 to 30 columns</title> <title>Generic UNION query ([RANDNUM]) - 21 to 30 columns</title>
<stype>3</stype> <stype>3</stype>
<level>4</level> <level>4</level>
<risk>1</risk> <risk>1</risk>
@ -2743,6 +2951,25 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>--</comment>
<char>[CHAR]</char>
<columns>31-40</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic UNION query (NULL) - 31 to 40 columns</title>
<stype>3</stype>
<level>4</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>--</comment> <comment>--</comment>
@ -2755,7 +2982,7 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - 31 to 40 columns</title> <title>Generic UNION query ([RANDNUM]) - 31 to 40 columns</title>
<stype>3</stype> <stype>3</stype>
<level>5</level> <level>5</level>
<risk>1</risk> <risk>1</risk>
@ -2781,6 +3008,24 @@ Formats:
<clause>1,2,3,4,5</clause> <clause>1,2,3,4,5</clause>
<where>1</where> <where>1</where>
<vector>[UNION]</vector> <vector>[UNION]</vector>
<request>
<payload/>
<comment>--</comment>
<char>[CHAR]</char>
<columns>41-50</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic UNION query (NULL) - 41 to 50 columns</title>
<stype>3</stype>
<level>5</level>
<risk>1</risk>
<clause>1,2,3,4,5</clause>
<where>1</where>
<vector>[UNION]</vector>
<request> <request>
<payload/> <payload/>
<comment>--</comment> <comment>--</comment>
@ -2793,7 +3038,7 @@ Formats:
</test> </test>
<test> <test>
<title>Generic UNION query ([CHAR]) - 41 to 50 columns</title> <title>Generic UNION query ([RANDNUM]) - 41 to 50 columns</title>
<stype>3</stype> <stype>3</stype>
<level>5</level> <level>5</level>
<risk>1</risk> <risk>1</risk>