Added generic and mysql UNION tests from 1 to 25 columns.

Adapted config file and command line removing now outdated --union-test switch.
Minor bug fix.
Minor code refactoring.
Got rid of some debug messages, standardized logging of UNION tests.
This commit is contained in:
Bernardo Damele 2011-01-11 22:56:21 +00:00
parent 300128042c
commit 2f5995a7eb
8 changed files with 208 additions and 71 deletions

View File

@ -17,7 +17,6 @@ from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS
from lib.techniques.brute.use import columnExists
from lib.techniques.brute.use import tableExists
from lib.techniques.inband.union.test import unionTest
def action():
"""
@ -56,10 +55,6 @@ def action():
dataToStdout("%s\n" % conf.dbmsHandler.getFingerprint())
# Techniques options
if conf.unionTest and kb.unionPosition is None:
conf.dumper.technic("inband injection payload", unionTest())
# Enumeration options
if conf.getBanner:
conf.dumper.banner(conf.dbmsHandler.getBanner())

View File

@ -235,7 +235,6 @@ def checkSqlInjection(place, parameter, value):
# default) value
# Parse boundary's <level>
if boundary.level > conf.level:
# NOTE: shall we report every single skipped boundary too?
continue
# Skip boundary if it does not match against test's <clause>
@ -377,9 +376,7 @@ def checkSqlInjection(place, parameter, value):
# In case of UNION query SQL injection
elif method == PAYLOAD.METHOD.UNION:
conf.uChar = test.request.char
conf.uCols = test.request.columns
configUnion()
configUnion(test.request.char, test.request.columns)
reqPayload, unionVector = unionTest(comment, place, parameter, value, prefix, suffix)

View File

@ -2066,16 +2066,18 @@ def openFile(filename, mode='r'):
errMsg += "and that it's not locked by another process."
raise sqlmapFilePathException, errMsg
def configUnion():
if isinstance(conf.uCols, basestring):
debugMsg = "setting the UNION query SQL injection range of columns"
logger.debug(debugMsg)
def __configUnionChar(char):
if char.isdigit() or char == "NULL":
conf.uChar = char
elif not char.startswith("'") or not char.endswith("'"):
conf.uChar = "'%s'" % char
if "-" not in conf.uCols or len(conf.uCols.split("-")) != 2:
def __configUnionCols(columns):
if "-" not in columns or len(columns.split("-")) != 2:
raise sqlmapSyntaxException, "--union-cols must be a range with hyphon (e.g. 1-10)"
conf.uCols = conf.uCols.replace(" ", "")
conf.uColsStart, conf.uColsStop = conf.uCols.split("-")
columns = columns.replace(" ", "")
conf.uColsStart, conf.uColsStop = columns.split("-")
if not conf.uColsStart.isdigit() or not conf.uColsStop.isdigit():
raise sqlmapSyntaxException, "--union-cols must be a range of integers"
@ -2088,12 +2090,13 @@ def configUnion():
errMsg += "higher number of columns"
raise sqlmapSyntaxException, errMsg
if isinstance(conf.uChar, basestring) and conf.uChar != "NULL":
debugMsg = "setting the UNION query SQL injection character to '%s'" % conf.uChar
logger.debug(debugMsg)
def configUnion(char, columns):
if isinstance(conf.uChar, basestring):
__configUnionChar(conf.uChar)
elif isinstance(char, basestring):
__configUnionChar(char)
if not conf.uChar.isdigit() and ( not conf.uChar.startswith("'") or not conf.uChar.endswith("'") ):
debugMsg = "forcing the UNION query SQL injection character to '%s'" % conf.uChar
logger.debug(debugMsg)
conf.uChar = "'%s'" % conf.uChar
if isinstance(conf.uCols, basestring):
__configUnionCols(conf.uCols)
elif isinstance(columns, basestring):
__configUnionCols(columns)

View File

@ -76,7 +76,6 @@ optDict = {
"Techniques": {
"timeSec": "integer",
"unionTest": "boolean",
"uCols": "string",
"uChar": "string"
},

View File

@ -231,14 +231,10 @@ def cmdLineParser():
help="Seconds to delay the DBMS response "
"(default 5)")
techniques.add_option("--union-test", dest="unionTest",
action="store_true", default=False,
help="Test for and use UNION query (inband) SQL injection")
techniques.add_option("--union-cols", dest="uCols",
help="Range of columns to test for UNION query SQL injection")
techniques.add_option("--union-char", dest="uChar", default="NULL",
techniques.add_option("--union-char", dest="uChar",
help="Character to use to bruteforce number of columns")
# Fingerprint options

View File

@ -81,17 +81,11 @@ def __unionConfirm(comment, place, parameter, value, prefix, suffix, count):
# Confirm the inband SQL injection and get the exact column
# position which can be used to extract data
if not isinstance(kb.unionPosition, int):
debugMsg = "testing full inband with %s columns" % count
logger.debug(debugMsg)
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, count)
# Assure that the above function found the exploitable full inband
# SQL injection position
if not isinstance(kb.unionPosition, int):
debugMsg = "testing single-entry inband with %s columns" % count
logger.debug(debugMsg)
validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, count, where=2)
# Assure that the above function found the exploitable partial
@ -125,11 +119,9 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix
if kb.dbms == DBMS.ORACLE:
query += " FROM DUAL"
if conf.verbose in (1, 2):
status = '%d/%d (%d%s)' % (count, conf.uColsStop, round(100.0*count/conf.uColsStop), '%')
dataToStdout("\r[%s] [INFO] number of columns: %s" % (time.strftime("%X"), status), True)
dataToStdout("\n")
debugMsg = "testing number of columns: %s" % status
logger.debug(debugMsg)
validPayload, unionVector = __unionConfirm(comment, place, parameter, value, prefix, suffix, count)
@ -152,12 +144,6 @@ def unionTest(comment, place, parameter, value, prefix, suffix):
oldTechnique = kb.technique
kb.technique = PAYLOAD.TECHNIQUE.UNION
if conf.uChar == "NULL":
technique = "NULL bruteforcing"
else:
technique = "char (%s) bruteforcing" % conf.uChar
validPayload, unionVector = __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
if validPayload:

View File

@ -251,19 +251,15 @@ longestCommon = False
# Default: 5
timeSec = 5
# Test for and use UNION query (inband) SQL injection.
# Valid: True or False
unionTest = False
# Range of columns to test for
# Valid: range of integers
# Default: 1-20
uCols = 1-20
# Example: 1-10
uCols =
# Character to use to bruteforce number of columns
# Valid: string
# Default: NULL
uChar = NULL
# Example: NULL
uChar =
[Fingerprint]

View File

@ -1856,15 +1856,38 @@ Formats:
<!-- TODO: if possible, add payload for Microsoft Access and SAP MaxDB -->
<!-- End of OR time-based blind tests -->
<!-- UNION query tests -->
<test>
<title>MySQL NULL UNION query - 4 to 7 columns</title>
<title>MySQL NULL UNION query - 1 to 3 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>
<payload/>
<comment>#</comment>
<char>NULL</char>
<columns>1-3</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL NULL UNION query - 4 to 7 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>
<payload/>
<comment>#</comment>
@ -1879,6 +1902,72 @@ Formats:
</details>
</test>
<test>
<title>MySQL NULL UNION query - 8 to 12 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>
<payload/>
<comment>#</comment>
<char>NULL</char>
<columns>8-12</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL NULL UNION query - 13 to 18 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>
<payload/>
<comment>#</comment>
<char>NULL</char>
<columns>13-18</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>MySQL NULL UNION query - 19 to 25 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>
<payload/>
<comment>#</comment>
<char>NULL</char>
<columns>19-25</columns>
</request>
<response>
<union/>
</response>
<details>
<dbms>MySQL</dbms>
</details>
</test>
<test>
<title>Generic NULL UNION query - 1 to 3 columns</title>
<stype>3</stype>
@ -1897,6 +1986,82 @@ Formats:
<union/>
</response>
</test>
<test>
<title>Generic NULL UNION query - 4 to 7 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>
<payload/>
<comment>--</comment>
<char>NULL</char>
<columns>4-7</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic NULL UNION query - 8 to 12 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>
<payload/>
<comment>--</comment>
<char>NULL</char>
<columns>8-12</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic NULL UNION query - 13 to 18 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>
<payload/>
<comment>--</comment>
<char>NULL</char>
<columns>13-18</columns>
</request>
<response>
<union/>
</response>
</test>
<test>
<title>Generic NULL UNION query - 19 to 25 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>
<payload/>
<comment>--</comment>
<char>NULL</char>
<columns>19-25</columns>
</request>
<response>
<union/>
</response>
</test>
<!-- End of UNION query tests -->
</root>