Merge branch 'master' of github.com:sqlmapproject/sqlmap

This commit is contained in:
Miroslav Stampar 2012-12-19 14:29:08 +01:00
commit 23153e8088
8 changed files with 211 additions and 686 deletions

View File

@ -675,6 +675,71 @@ class Agent(object):
return unionQuery
def limitCondition(self, expression, dump=False):
startLimit = 0
stopLimit = None
limitCond = True
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
if limitRegExp:
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
elif limitRegExp2:
startLimit = 0
stopLimit = limitRegExp2.group(int(limitGroupStart))
limitCond = int(stopLimit) > 1
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
if limitRegExp:
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif topLimit:
startLimit = 0
stopLimit = int(topLimit.group(1))
limitCond = int(stopLimit) > 1
elif Backend.isDbms(DBMS.ORACLE):
limitCond = False
# We assume that only queries NOT containing a "LIMIT #, 1"
# (or equivalent depending on the back-end DBMS) can return
# multiple entries
if limitCond:
if (limitRegExp or limitRegExp2) and stopLimit is not None:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or equivalent, depending on the back-end DBMS) word
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
stopLimit += startLimit
_ = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
expression = expression[:_]
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
stopLimit += startLimit
elif dump:
if conf.limitStart:
startLimit = conf.limitStart - 1
if conf.limitStop:
stopLimit = conf.limitStop
return expression, limitCond, topLimit, startLimit, stopLimit
def limitQuery(self, num, query, field=None, uniqueField=None):
"""
Take in input a query string and return its limited query string.

View File

@ -661,6 +661,9 @@ def filePathToString(filePath):
return strRepl
def singleTimeDebugMessage(message):
singleTimeLogMessage(message, logging.DEBUG)
def singleTimeWarnMessage(message):
singleTimeLogMessage(message, logging.WARN)

View File

@ -129,7 +129,7 @@ def liveTest():
if case.hasAttribute("name"):
name = case.getAttribute("name")
if conf.runCase and ((conf.runCase.isdigit() and conf.runCase != count) or not re.search(conf.runCase, name, re.DOTALL)):
if conf.runCase and ((conf.runCase.isdigit() and conf.runCase != count) or not re.search(conf.runCase, name, re.DOTALL | re.I)):
continue
if case.getElementsByTagName("switches"):
@ -206,7 +206,7 @@ def runCase(switches=None, parse=None):
retVal = False
if parse and retVal:
ifile = open(conf.dumper.getOutputFile(), 'r')
ifile = open(conf.dumper.getOutputFile(), "rb")
content = ifile.read()
ifile.close()
for item in parse:

View File

@ -139,8 +139,6 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
startLimit = 0
stopLimit = None
outputs = BigArray()
untilLimitChar = None
untilOrderChar = None
if not unpack:
return _goInference(payload, expression, charsetType, firstChar, lastChar, dump)
@ -160,69 +158,18 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
# If we have been here from SQL query/shell we have to check if
# the SQL query might return multiple entries and in such case
# forge the SQL limiting the query output one entry per time
# NOTE: I assume that only queries that get data from a table
# forge the SQL limiting the query output one entry at a time
# NOTE: we assume that only queries that get data from a table
# can return multiple entries
if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not \
expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression)
limitCond = True
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
if limitRegExp2:
startLimit = 0
stopLimit = limitRegExp2.group(int(limitGroupStart))
else:
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
if limitRegExp:
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif topLimit:
startLimit = 0
stopLimit = int(topLimit.group(1))
limitCond = int(stopLimit) > 1
elif Backend.isDbms(DBMS.ORACLE):
limitCond = False
# We assume that only queries NOT containing a "LIMIT #, 1"
# (or equivalent depending on the back-end DBMS) can return
# multiple entries
if limitCond:
if (limitRegExp or limitRegExp2) and stopLimit is not None:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or equivalent, depending on the back-end DBMS) word
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
stopLimit += startLimit
untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
expression = expression[:untilLimitChar]
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
stopLimit += startLimit
test = True
if not stopLimit or stopLimit <= 1:
if Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]):
test = False
@ -232,9 +179,9 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
countFirstField = queries[Backend.getIdentifiedDbms()].count.query % expressionFieldsList[0]
countedExpression = expression.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):
untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar]
if " ORDER BY " in expression.upper():
_ = countedExpression.upper().rindex(" ORDER BY ")
countedExpression = countedExpression[:_]
if not stopLimit:
count = _goInference(payload, countedExpression, charsetType=CHARSET_TYPE.DIGITS, firstChar=firstChar, lastChar=lastChar)

View File

@ -238,14 +238,13 @@ def errorUse(expression, dump=False):
stopLimit = None
output = None
outputs = None
untilLimitChar = None
_, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression)
# We have to check if the SQL query might return multiple entries
# and in such case forge the SQL limiting the query output one
# entry per time
# NOTE: I assume that only queries that get data from a table can
# entry at a time
# NOTE: we assume that only queries that get data from a table can
# return multiple entries
if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in \
expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) \
@ -253,70 +252,13 @@ def errorUse(expression, dump=False):
expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
limitCond = True
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
if limitRegExp2:
startLimit = 0
stopLimit = limitRegExp2.group(int(limitGroupStart))
else:
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
if limitRegExp:
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif topLimit:
startLimit = 0
stopLimit = int(topLimit.group(1))
limitCond = int(stopLimit) > 1
elif Backend.isDbms(DBMS.ORACLE):
limitCond = False
# I assume that only queries NOT containing a "LIMIT #, 1"
# (or equivalent depending on the back-end DBMS) can return
# multiple entries
if limitCond:
if (limitRegExp or limitRegExp2) and stopLimit is not None:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or equivalent, depending on the back-end DBMS) word
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
stopLimit += startLimit
untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
expression = expression[:untilLimitChar]
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
stopLimit += startLimit
elif dump:
if conf.limitStart:
startLimit = conf.limitStart - 1
if conf.limitStop:
stopLimit = conf.limitStop
# Count the number of SQL query entries output
countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % ('*' if len(expressionFieldsList) > 1 else expressionFields), 1)
if " ORDER BY " in expression:
if " ORDER BY " in expression.upper():
_ = countedExpression.upper().rindex(" ORDER BY ")
countedExpression = countedExpression[:_]

View File

@ -29,6 +29,7 @@ from lib.core.common import isNumPosStrValue
from lib.core.common import listToStrValue
from lib.core.common import parseUnionPage
from lib.core.common import removeReflectiveValues
from lib.core.common import singleTimeDebugMessage
from lib.core.common import singleTimeWarnMessage
from lib.core.common import wasLastRequestDBMSError
from lib.core.convert import htmlunescape
@ -159,14 +160,17 @@ def unionUse(expression, unpack=True, dump=False):
_, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(origExpr)
if expressionFieldsList and len(expressionFieldsList) > 1 and " ORDER BY " in expression.upper():
# No need for it in multicolumn dumps (one row is retrieved per request) and just slowing down on large table dumps
expression = expression[:expression.upper().rindex(" ORDER BY ")]
if expressionFieldsList and len(expressionFieldsList) > 1 and "ORDER BY" in expression.upper():
# Removed ORDER BY clause because UNION does not play well with it
expression = re.sub("\s*ORDER BY\s+[\w,]+", "", expression, re.I)
debugMsg = "stripping ORDER BY clause from statement because "
debugMsg += "it does not play well with UNION query SQL injection"
singleTimeDebugMessage(debugMsg)
# We have to check if the SQL query might return multiple entries
# and in such case forge the SQL limiting the query output one
# entry per time
# NOTE: I assume that only queries that get data from a table can
# if the technique is partial UNION query and in such case forge the
# SQL limiting the query output one entry at a time
# NOTE: we assume that only queries that get data from a table can
# return multiple entries
if (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or \
(dump and (conf.limitStart or conf.limitStop))) and \
@ -174,66 +178,9 @@ def unionUse(expression, unpack=True, dump=False):
not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE \
and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
limitCond = True
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
if limitRegExp2:
startLimit = 0
stopLimit = limitRegExp2.group(int(limitGroupStart))
else:
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
if limitRegExp:
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif topLimit:
startLimit = 0
stopLimit = int(topLimit.group(1))
limitCond = int(stopLimit) > 1
elif Backend.isDbms(DBMS.ORACLE):
limitCond = False
# I assume that only queries NOT containing a "LIMIT #, 1"
# (or equivalent depending on the back-end DBMS) can return
# multiple entries
if limitCond:
if (limitRegExp or limitRegExp2) and stopLimit is not None:
stopLimit = int(stopLimit)
# From now on we need only the expression until the " LIMIT "
# (or equivalent, depending on the back-end DBMS) word
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
stopLimit += startLimit
untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
expression = expression[:untilLimitChar]
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
stopLimit += startLimit
elif dump:
if conf.limitStart:
startLimit = conf.limitStart - 1
if conf.limitStop:
stopLimit = conf.limitStop
# Count the number of SQL query entries output
countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % ('*' if len(expressionFieldsList) > 1 else expressionFields), 1)
@ -362,7 +309,6 @@ def unionUse(expression, unpack=True, dump=False):
kb.suppressResumeInfo = False
if not value and not abortedFlag:
expression = re.sub("\s*ORDER BY\s+[\w,]+", "", expression, re.I) # full union doesn't play well with ORDER BY
value = _oneShotUnionUse(expression, unpack)
duration = calculateDeltaSeconds(start)

View File

@ -106,16 +106,16 @@ def from_buffer(buffer, mime=False):
try:
libmagic = None
# Let's try to find magic or magic1
dll = ctypes.util.find_library('magic') or ctypes.util.find_library('magic1')
libmagic = None
# Let's try to find magic or magic1
dll = ctypes.util.find_library('magic') or ctypes.util.find_library('magic1')
# This is necessary because find_library returns None if it doesn't find the library
if dll:
# This is necessary because find_library returns None if it doesn't find the library
if dll:
libmagic = ctypes.CDLL(dll)
if not libmagic or not libmagic._name:
if not libmagic or not libmagic._name:
import sys
platform_to_lib = {'darwin': ['/opt/local/lib/libmagic.dylib',
'/usr/local/lib/libmagic.dylib',
@ -127,78 +127,79 @@ if not libmagic or not libmagic._name:
except OSError:
pass
if not libmagic or not libmagic._name:
if not libmagic or not libmagic._name:
# It is better to raise an ImportError since we are importing magic module
raise ImportError('failed to find libmagic. Check your installation')
magic_t = ctypes.c_void_p
magic_t = ctypes.c_void_p
def errorcheck(result, func, args):
def errorcheck(result, func, args):
err = magic_error(args[0])
if err is not None:
raise MagicException(err)
else:
return result
def coerce_filename(filename):
def coerce_filename(filename):
if filename is None:
return None
return filename.encode(sys.getfilesystemencoding())
magic_open = libmagic.magic_open
magic_open.restype = magic_t
magic_open.argtypes = [c_int]
magic_open = libmagic.magic_open
magic_open.restype = magic_t
magic_open.argtypes = [c_int]
magic_close = libmagic.magic_close
magic_close.restype = None
magic_close.argtypes = [magic_t]
magic_close = libmagic.magic_close
magic_close.restype = None
magic_close.argtypes = [magic_t]
magic_error = libmagic.magic_error
magic_error.restype = c_char_p
magic_error.argtypes = [magic_t]
magic_error = libmagic.magic_error
magic_error.restype = c_char_p
magic_error.argtypes = [magic_t]
magic_errno = libmagic.magic_errno
magic_errno.restype = c_int
magic_errno.argtypes = [magic_t]
magic_errno = libmagic.magic_errno
magic_errno.restype = c_int
magic_errno.argtypes = [magic_t]
_magic_file = libmagic.magic_file
_magic_file.restype = c_char_p
_magic_file.argtypes = [magic_t, c_char_p]
_magic_file.errcheck = errorcheck
_magic_file = libmagic.magic_file
_magic_file.restype = c_char_p
_magic_file.argtypes = [magic_t, c_char_p]
_magic_file.errcheck = errorcheck
def magic_file(cookie, filename):
def magic_file(cookie, filename):
return _magic_file(cookie, coerce_filename(filename))
_magic_buffer = libmagic.magic_buffer
_magic_buffer.restype = c_char_p
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
_magic_buffer.errcheck = errorcheck
_magic_buffer = libmagic.magic_buffer
_magic_buffer.restype = c_char_p
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
_magic_buffer.errcheck = errorcheck
def magic_buffer(cookie, buf):
def magic_buffer(cookie, buf):
return _magic_buffer(cookie, buf, len(buf))
_magic_load = libmagic.magic_load
_magic_load.restype = c_int
_magic_load.argtypes = [magic_t, c_char_p]
_magic_load.errcheck = errorcheck
_magic_load = libmagic.magic_load
_magic_load.restype = c_int
_magic_load.argtypes = [magic_t, c_char_p]
_magic_load.errcheck = errorcheck
def magic_load(cookie, filename):
def magic_load(cookie, filename):
return _magic_load(cookie, coerce_filename(filename))
magic_setflags = libmagic.magic_setflags
magic_setflags.restype = c_int
magic_setflags.argtypes = [magic_t, c_int]
magic_setflags = libmagic.magic_setflags
magic_setflags.restype = c_int
magic_setflags.argtypes = [magic_t, c_int]
magic_check = libmagic.magic_check
magic_check.restype = c_int
magic_check.argtypes = [magic_t, c_char_p]
magic_compile = libmagic.magic_compile
magic_compile.restype = c_int
magic_compile.argtypes = [magic_t, c_char_p]
magic_check = libmagic.magic_check
magic_check.restype = c_int
magic_check.argtypes = [magic_t, c_char_p]
magic_compile = libmagic.magic_compile
magic_compile.restype = c_int
magic_compile.argtypes = [magic_t, c_char_p]
except ImportError:
pass
MAGIC_NONE = 0x000000 # No flags

View File

@ -44,7 +44,7 @@
<item value="r'database management system users privileges:.+debian-sys-maint.+\(administrator\).+root.+\(administrator\).+privilege: SUPER'"/>
<item value="r'database management system users roles:.+debian-sys-maint.+\[.+root.+\[.+role: SUPER'"/>
<item value="r'available databases \[.+information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'Database: testdb.+1 table.+users'"/>
<item value="r'Database: testdb.+3 tables.+users'"/>
<item value="r'Database: testdb.+Table: users.+3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'Database: testdb.+Table.+Entries.+users.+5'"/>
<item value="r'Database: testdb.+Table: users.+5 entries.+luther.+nameisnull.+'"/>
@ -87,7 +87,7 @@
<item value="r'database management system users privileges:.+debian-sys-maint.+\(administrator\).+root.+\(administrator\).+privilege: SUPER'"/>
<item value="r'database management system users roles:.+debian-sys-maint.+\[.+root.+\[.+role: SUPER'"/>
<item value="r'available databases \[.+information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'Database: testdb.+1 table.+users'"/>
<item value="r'Database: testdb.+3 tables.+users'"/>
<item value="r'Database: testdb.+Table: users.+3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'Database: testdb.+Table.+Entries.+users.+5'"/>
<item value="r'Database: testdb.+Table: users.+5 entries.+luther.+nameisnull.+'"/>
@ -130,7 +130,7 @@
<item value="r'database management system users privileges:.+debian-sys-maint.+\(administrator\).+root.+\(administrator\).+privilege: SUPER'"/>
<item value="r'database management system users roles:.+debian-sys-maint.+\[.+root.+\[.+role: SUPER'"/>
<item value="r'available databases \[.+information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'Database: testdb.+1 table.+users'"/>
<item value="r'Database: testdb.+3 tables.+users'"/>
<item value="r'Database: testdb.+Table: users.+3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'Database: testdb.+Table.+Entries.+users.+5'"/>
<item value="r'Database: testdb.+Table: users.+5 entries.+luther.+nameisnull.+'"/>
@ -173,7 +173,7 @@
<item value="r'database management system users privileges:.+debian-sys-maint.+\(administrator\).+root.+\(administrator\).+privilege: SUPER'"/>
<item value="r'database management system users roles:.+debian-sys-maint.+\[.+root.+\[.+role: SUPER'"/>
<item value="r'available databases \[.+information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'Database: testdb.+1 table.+users'"/>
<item value="r'Database: testdb.+3 tables.+users'"/>
<item value="r'Database: testdb.+Table: users.+3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'Database: testdb.+Table.+Entries.+users.+5'"/>
<item value="r'Database: testdb.+Table: users.+5 entries.+luther.+nameisnull.+'"/>
@ -190,18 +190,6 @@
<getCurrentDb value="True"/>
<getHostname value="True"/>
<isDba value="True"/>
<getUsers value="True"/>
<getPasswordHashes value="True"/>
<getPrivileges value="True"/>
<getRoles value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<getColumns value="True"/>
<getCount value="True"/>
<dumpTable value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<excludeSysDbs value="True"/>
</switches>
<parse>
<item value="Title: MySQL &gt; 5.0.11 AND time-based blind"/>
@ -211,15 +199,6 @@
<item value="current database: 'testdb'"/>
<item value="hostname: 'debian"/>
<item value="current user is DBA: True"/>
<item value="r'database management system users \[.+'debian-sys-maint'@'localhost'.+'root'@''"/>
<item value="r'database management system users password hashes:.+root \[.+password hash: \*00E247AC5F9AF26AE0194B41E1E769DEE1429A29.+clear-text password: testpass'"/>
<item value="r'database management system users privileges:.+debian-sys-maint.+\(administrator\).+root.+\(administrator\).+privilege: SUPER'"/>
<item value="r'database management system users roles:.+debian-sys-maint.+\[.+root.+\[.+role: SUPER'"/>
<item value="r'available databases \[.+information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'Database: testdb.+1 table.+users'"/>
<item value="r'Database: testdb.+Table: users.+3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'Database: testdb.+Table.+Entries.+users.+5'"/>
<item value="r'Database: testdb.+Table: users.+5 entries.+luther.+nameisnull.+'"/>
</parse>
</case>
<case name="MySQL inline queries multi-threaded enumeration - all entries">
@ -259,7 +238,7 @@
<item value="r'database management system users privileges:.+debian-sys-maint.+\(administrator\).+root.+\(administrator\).+privilege: SUPER'"/>
<item value="r'database management system users roles:.+debian-sys-maint.+\[.+root.+\[.+role: SUPER'"/>
<item value="r'available databases \[.+information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'Database: testdb.+1 table.+users'"/>
<item value="r'Database: testdb.+3 tables.+users'"/>
<item value="r'Database: testdb.+Table: users.+3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'Database: testdb.+Table.+Entries.+users.+5'"/>
<item value="r'Database: testdb.+Table: users.+5 entries.+luther.+nameisnull.+'"/>
@ -304,11 +283,14 @@
<item value="r'Database: testdb.+Table: users.+3 entries.+fluffy.+bunny.+wu.+ming'"/>
</parse>
</case>
<!-- TODO: this fails because of issue #304 -->
<case name="MySQL boolean-based multi-threaded custom enumeration - substring">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int.php?id=1"/>
<!-- TODO: this fails because of issue #305 -->
<!--
<threads value="4"/>
-->
<threads value="1"/>
<tech value="B"/>
<dumpTable value="True"/>
<db value="testdb"/>
@ -366,7 +348,7 @@
<tech value="B"/>
<search value="True"/>
<db value="testdb"/>
<tbl value="a,e,i"/>
<tbl value="foo,se,bar"/>
</switches>
<parse>
<item value="r'Database: testdb.+1 table.+users'"/>
@ -380,7 +362,7 @@
<tech value="E"/>
<search value="True"/>
<db value="testdb"/>
<tbl value="a,e,i"/>
<tbl value="foo,se,bar"/>
</switches>
<parse>
<item value="r'Database: testdb.+1 table.+users'"/>
@ -394,7 +376,7 @@
<tech value="U"/>
<search value="True"/>
<db value="testdb"/>
<tbl value="a,e,i"/>
<tbl value="foo,se,bar"/>
</switches>
<parse>
<item value="r'Database: testdb.+1 table.+users'"/>
@ -653,400 +635,39 @@
<item value="r'SELECT \* FROM users LIMIT 0, 2 \[2\].+1, luther, blissett.+2, fluffy, bunny'"/>
</parse>
</case>
<case name="MySQL boolean-based multi-threaded custom ordered SQL query enumeration">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int.php?id=1"/>
<threads value="4"/>
<tech value="B"/>
<query value="SELECT * FROM users ORDER BY name"/>
</switches>
<parse>
<item value="r'SELECT \* FROM users ORDER BY name \[5\].+2, fluffy, bunny.+1, luther, blissett.+3, wu, ming'"/>
</parse>
</case>
<case name="MySQL error-based multi-threaded custom ordered SQL query enumeration">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int.php?id=1"/>
<threads value="4"/>
<tech value="E"/>
<query value="SELECT * FROM users ORDER BY name"/>
</switches>
<parse>
<item value="r'SELECT \* FROM users ORDER BY name \[5\].+2, fluffy, bunny.+1, luther, blissett.+3, wu, ming'"/>
</parse>
</case>
<case name="MySQL UNION query multi-threaded custom ordered SQL query enumeration">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int.php?id=1"/>
<threads value="4"/>
<tech value="U"/>
<query value="SELECT * FROM users ORDER BY name"/>
</switches>
<parse>
<!-- NOTE: it is not sorted on purpose because UNION does not play well with ORDER BY and it is stripped -->
<item value="r'SELECT \* FROM users ORDER BY name \[5\].+1, luther, blissett.+2, fluffy, bunny.+3, wu, ming'"/>
</parse>
</case>
<!-- End of user's provided statement enumeration switches -->
<!-- Old test cases -->
<case name="MySQL (--technique=E --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="E"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: '5.1.63-0+squeeze2'"/>
<item value="current user: 'root@localhost'"/>
<item value="current database: 'testdb'"/>
<item value="r'information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
<case name="MySQL (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: '5.1.63-0+squeeze1'"/>
<item value="current user: 'root@localhost'"/>
<item value="current database: 'testdb'"/>
<item value="r'information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
<case name="MySQL partial union (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/mysql/get_int_partialunion.php?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: '5.1.63-0+squeeze1'"/>
<item value="current user: 'root@localhost'"/>
<item value="current database: 'testdb'"/>
<item value="r'information_schema.+mysql.+owasp10.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+surname.+varchar\(1000\)'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
<case name="Postgres (--technique=B --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump --threads=4)">
<switches>
<url value="http://debiandev/sqlmap/pgsql/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="B"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
<threads value="4"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="PostgreSQL 8.3.9 on i486-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2"/>
<item value="current user: 'testuser'"/>
<item value="current database: 'testdb'"/>
<item value="r'postgres.+template0.+template1.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+username.+bpchar'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Postgres (--technique=E --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/pgsql/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="E"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="PostgreSQL 8.3.9 on i486-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2"/>
<item value="current user: 'testuser'"/>
<item value="current database: 'testdb'"/>
<item value="r'postgres.+template0.+template1.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+username.+bpchar'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Postgres (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/pgsql/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="PostgreSQL 8.3.9 on i486-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2"/>
<item value="current user: 'testuser'"/>
<item value="current database: 'testdb'"/>
<item value="r'postgres.+template0.+template1.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+username.+bpchar'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Postgres partial union (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/pgsql/get_int_partialunion.php?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="PostgreSQL 8.3.9 on i486-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2"/>
<item value="current user: 'testuser'"/>
<item value="current database: 'testdb'"/>
<item value="r'postgres.+template0.+template1.+testdb'"/>
<item value="r'1 table.+users'"/>
<item value="r'3 columns.+username.+bpchar'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Oracle (--technique=B --is-dba --banner --current-user --current-db --dbs --tables -D SCOTT -T users --columns --dump --threads=4)">
<switches>
<url value="http://debiandev/sqlmap/oracle/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="B"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="SCOTT"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
<threads value="4"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: 'Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod'"/>
<item value="current user: 'SYS'"/>
<item value="'TESTDB.REGRESS.RDBMS.DEV.US.ORACLE.COM'"/>
<item value="r'available databases.+15.+CTXSYS.+DBSNMP.+SCOTT.+SYS.+SYSMAN'"/>
<item value="r'5 tables.+BONUS.+DEPT.+EMP.+SALGRADE.+USERS'"/>
<item value="r'3 columns.+SURNAME.+VARCHAR'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Oracle (--technique=E --is-dba --banner --current-user --current-db --dbs --tables -D SCOTT -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/oracle/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="E"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="SCOTT"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: 'Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod'"/>
<item value="current user: 'SYS'"/>
<item value="'TESTDB.REGRESS.RDBMS.DEV.US.ORACLE.COM'"/>
<item value="r'available databases.+15.+CTXSYS.+DBSNMP.+SCOTT.+SYS.+SYSMAN'"/>
<item value="r'5 tables.+BONUS.+DEPT.+EMP.+SALGRADE.+USERS'"/>
<item value="r'3 columns.+SURNAME.+VARCHAR'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Oracle (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D SCOTT -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/oracle/get_int.php?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="SCOTT"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: 'Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod'"/>
<item value="current user: 'SYS'"/>
<item value="'TESTDB.REGRESS.RDBMS.DEV.US.ORACLE.COM'"/>
<item value="r'available databases.+15.+CTXSYS.+DBSNMP.+SCOTT.+SYS.+SYSMAN'"/>
<item value="r'5 tables.+BONUS.+DEPT.+EMP.+SALGRADE.+USERS'"/>
<item value="r'3 columns.+SURNAME.+VARCHAR'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="Oracle partial union (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D SCOTT -T users --columns --dump)">
<switches>
<url value="http://debiandev/sqlmap/oracle/get_int_partialunion.php?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="SCOTT"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="banner: 'Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod'"/>
<item value="current user: 'SYS'"/>
<item value="'TESTDB.REGRESS.RDBMS.DEV.US.ORACLE.COM'"/>
<item value="r'available databases.+15.+CTXSYS.+DBSNMP.+SCOTT.+SYS.+SYSMAN'"/>
<item value="r'5 tables.+BONUS.+DEPT.+EMP.+SALGRADE.+USERS'"/>
<item value="r'3 columns.+SURNAME.+VARCHAR'"/>
<item value="r'4 entries.+nameisnull'"/>
</parse>
</case>
<case name="MSSQL (--technique=B --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump --threads=4)">
<switches>
<url value="http://windowsdev/sqlmap/mssql/iis/get_int.asp?id=1"/>
<isDba value="True"/>
<tech value="B"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
<threads value="4"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="r'Microsoft SQL Server 2005.+Oct 14 2005 00:33:37'"/>
<item value="current user: 'sa'"/>
<item value="current database: 'testdb'"/>
<item value="r'available databases.+5.+master.+model.+msdb.+tempdb.+testdb'"/>
<item value="r'dbo\.sysdiagrams.+dbo\.users'"/>
<item value="r'3 columns.+surname.+varchar'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
<case name="MSSQL (--technique=E --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://windowsdev/sqlmap/mssql/iis/get_int.asp?id=1"/>
<isDba value="True"/>
<tech value="E"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="r'Microsoft SQL Server 2005.+Oct 14 2005 00:33:37'"/>
<item value="current user: 'sa'"/>
<item value="current database: 'testdb'"/>
<item value="r'available databases.+5.+master.+model.+msdb.+tempdb.+testdb'"/>
<item value="r'dbo\.sysdiagrams.+dbo\.users'"/>
<item value="r'3 columns.+surname.+varchar'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
<case name="MSSQL (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://windowsdev/sqlmap/mssql/iis/get_int.asp?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="r'Microsoft SQL Server 2005.+Oct 14 2005 00:33:37'"/>
<item value="current user: 'sa'"/>
<item value="current database: 'testdb'"/>
<item value="r'available databases.+5.+master.+model.+msdb.+tempdb.+testdb'"/>
<item value="r'dbo\.sysdiagrams.+dbo\.users'"/>
<item value="r'3 columns.+surname.+varchar'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
<case name="MSSQL partial union (--technique=U --is-dba --banner --current-user --current-db --dbs --tables -D testdb -T users --columns --dump)">
<switches>
<url value="http://windowsdev/sqlmap/mssql/iis/get_int_partialunion.asp?id=1"/>
<isDba value="True"/>
<tech value="U"/>
<getBanner value="True"/>
<getCurrentUser value="True"/>
<getCurrentDb value="True"/>
<getDbs value="True"/>
<getTables value="True"/>
<db value="testdb"/>
<tbl value="users"/>
<getColumns value="True"/>
<dumpTable value="True"/>
</switches>
<parse>
<item value="current user is DBA: True"/>
<item value="r'Microsoft SQL Server 2005.+Oct 14 2005 00:33:37'"/>
<item value="current user: 'sa'"/>
<item value="current database: 'testdb'"/>
<item value="r'available databases.+5.+master.+model.+msdb.+tempdb.+testdb'"/>
<item value="r'dbo\.sysdiagrams.+dbo\.users'"/>
<item value="r'3 columns.+surname.+varchar'"/>
<item value="r'5 entries.+nameisnull.+'"/>
</parse>
</case>
</root>