Skip to content

Commit ab59a4b

Browse files
committed
Minor patches
1 parent 97c8b45 commit ab59a4b

8 files changed

Lines changed: 62 additions & 13 deletions

File tree

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.7.80"
23+
VERSION = "1.10.7.81"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

lib/request/direct.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
See the file 'LICENSE' for copying permission
66
"""
77

8+
import binascii
89
import re
910
import time
1011

@@ -29,6 +30,20 @@
2930
from lib.utils.safe2bin import safecharencode
3031
from lib.utils.timeout import timeout
3132

33+
def _hexifyBinary(value):
34+
"""
35+
Renders a raw binary cell returned by a driver in -d mode as uppercase hex, instead of letting it reach
36+
the text channel as a str() like '<memory at 0x...>' (PostgreSQL bytea -> psycopg2 memoryview) or a
37+
control-character blob that gets blanked/corrupted (e.g. MSSQL varbinary -> bytes). Text columns come back
38+
as native strings, so only genuine binary values are converted (matches HEX()-based rendering elsewhere).
39+
"""
40+
41+
if isinstance(value, memoryview):
42+
value = value.tobytes()
43+
if isinstance(value, (bytes, bytearray)):
44+
return getUnicode(binascii.hexlify(value)).upper()
45+
return value
46+
3247
def direct(query, content=True):
3348
select = True
3449
query = agent.payloadDirect(query)
@@ -63,6 +78,8 @@ def direct(query, content=True):
6378
timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
6479
elif not (output and ("%soutput" % conf.tablePrefix) not in query and ("%sfile" % conf.tablePrefix) not in query):
6580
output, state = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)
81+
if output and isListLike(output):
82+
output = [tuple(_hexifyBinary(_) for _ in row) if isListLike(row) else _hexifyBinary(row) for row in output]
6683
if state == TIMEOUT_STATE.NORMAL:
6784
hashDBWrite(query, output, True)
6885
elif state == TIMEOUT_STATE.TIMEOUT:

lib/utils/sqlalchemy.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def fetchall(self):
117117
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
118118
return None
119119

120-
def execute(self, query):
120+
def execute(self, query, commit=True):
121121
retVal = False
122122

123123
# Reference: https://stackoverflow.com/a/69491015
@@ -126,10 +126,14 @@ def execute(self, query):
126126

127127
try:
128128
self.cursor = self.connector.execute(query)
129-
if hasattr(self.connector, "commit"): # Note: SQLAlchemy 2.0+ dropped implicit autocommit (otherwise DML changes - e.g. via --sql-query - would be silently lost)
129+
# Note: SQLAlchemy 2.0+ dropped implicit autocommit (otherwise DML changes - e.g. via --sql-query -
130+
# would be silently lost). SELECT goes through select() with commit=False so the result set is
131+
# fetched BEFORE committing: on some drivers (e.g. pymssql) commit() discards the open cursor, which
132+
# otherwise made every MSSQL '-d' query silently return empty (banner/is-dba/dump all blank).
133+
if commit and hasattr(self.connector, "commit"):
130134
self.connector.commit()
131135
retVal = True
132-
except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError) as ex:
136+
except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError, _sqlalchemy.exc.DataError, _sqlalchemy.exc.IntegrityError) as ex:
133137
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
134138
# Roll back the failed statement's transaction so it does not poison every following query with
135139
# 'InFailedSqlTransaction' (SQLAlchemy 2.0+ keeps the transaction open after an error). Without this
@@ -148,7 +152,14 @@ def execute(self, query):
148152
def select(self, query):
149153
retVal = None
150154

151-
if self.execute(query):
155+
# Fetch BEFORE committing (commit=False): committing can discard the open result cursor on some drivers
156+
# (e.g. pymssql), which silently emptied every MSSQL '-d' result. No DML is persisted by a SELECT anyway.
157+
if self.execute(query, commit=False):
152158
retVal = self.fetchall()
159+
if hasattr(self.connector, "commit"):
160+
try:
161+
self.connector.commit()
162+
except Exception:
163+
pass
153164

154165
return retVal

plugins/dbms/mssqlserver/connector.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,20 @@ def fetchall(self):
5454
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
5555
return None
5656

57-
def execute(self, query):
57+
def execute(self, query, commit=True):
5858
retVal = False
5959

6060
try:
6161
self.cursor.execute(getText(query))
62+
# Commit non-SELECT (DML/DDL) here: direct() routes those to execute() alone, so without this a
63+
# '--sql-query'/'--sql-shell' write was silently rolled back on connection close. select() passes
64+
# commit=False and commits only AFTER fetchall(), because on pymssql commit() discards the open
65+
# result cursor (which otherwise emptied every SELECT result).
66+
if commit:
67+
try:
68+
self.connector.commit()
69+
except pymssql.OperationalError:
70+
pass
6271
retVal = True
6372
except (pymssql.OperationalError, pymssql.ProgrammingError) as ex:
6473
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
@@ -70,7 +79,7 @@ def execute(self, query):
7079
def select(self, query):
7180
retVal = None
7281

73-
if self.execute(query):
82+
if self.execute(query, commit=False):
7483
retVal = self.fetchall()
7584

7685
try:

plugins/dbms/mysql/connector.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import logging
1414
import struct
15-
import sys
1615

1716
from lib.core.common import getSafeExString
1817
from lib.core.data import conf
@@ -34,7 +33,7 @@ def connect(self):
3433
self.initConnection()
3534

3635
try:
37-
self.connector = pymysql.connect(host=self.hostname, user=self.user, passwd=self.password.encode(sys.stdin.encoding), db=self.db, port=self.port, connect_timeout=conf.timeout, use_unicode=True)
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)
3837
except (pymysql.OperationalError, pymysql.InternalError, pymysql.ProgrammingError, struct.error) as ex:
3938
raise SqlmapConnectionException(getSafeExString(ex))
4039

plugins/dbms/postgresql/connector.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ def execute(self, query):
5555
try:
5656
self.cursor.execute(query)
5757
retVal = True
58-
except (psycopg2.OperationalError, psycopg2.ProgrammingError) as ex:
58+
# Note: also catch DataError/IntegrityError (e.g. division-by-zero, bad cast, unique violation from a
59+
# user '--sql-query') so the commit() below still runs and clears the aborted transaction; otherwise
60+
# PostgreSQL poisons every later query with 'InFailedSqlTransaction' and silently returns None
61+
except (psycopg2.OperationalError, psycopg2.ProgrammingError, psycopg2.DataError, psycopg2.IntegrityError) as ex:
5962
logger.warning(("(remote) '%s'" % getSafeExString(ex)).strip())
6063
except psycopg2.InternalError as ex:
6164
raise SqlmapConnectionException(getSafeExString(ex))

plugins/dbms/postgresql/takeover.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from lib.core.common import isStackingAvailable
1818
from lib.core.common import randomStr
1919
from lib.core.compat import LooseVersion
20+
from lib.core.data import conf
2021
from lib.core.data import kb
2122
from lib.core.data import logger
2223
from lib.core.data import paths
@@ -100,7 +101,7 @@ def uncPathRequest(self):
100101
def copyExecCmd(self, cmd):
101102
output = None
102103

103-
if isStackingAvailable():
104+
if isStackingAvailable() or conf.direct:
104105
# Reference: https://medium.com/greenwolf-security/authenticated-arbitrary-command-execution-on-postgresql-9-3-latest-cd18945914d5
105106
self._forgedCmd = "DROP TABLE IF EXISTS %s;" % self.cmdTblName
106107
self._forgedCmd += "CREATE TABLE %s(%s text);" % (self.cmdTblName, self.tblField)

plugins/dbms/sybase/connector.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,20 @@ def fetchall(self):
5454
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
5555
return None
5656

57-
def execute(self, query):
57+
def execute(self, query, commit=True):
5858
retVal = False
5959

6060
try:
6161
self.cursor.execute(getText(query))
62+
# Commit non-SELECT (DML/DDL) here: direct() routes those to execute() alone, so without this a
63+
# '--sql-query'/'--sql-shell' write was silently rolled back on connection close. select() passes
64+
# commit=False and commits only AFTER fetchall(), because on pymssql commit() discards the open
65+
# result cursor (which otherwise emptied every SELECT result).
66+
if commit:
67+
try:
68+
self.connector.commit()
69+
except pymssql.OperationalError:
70+
pass
6271
retVal = True
6372
except (pymssql.OperationalError, pymssql.ProgrammingError) as ex:
6473
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
@@ -70,7 +79,7 @@ def execute(self, query):
7079
def select(self, query):
7180
retVal = None
7281

73-
if self.execute(query):
82+
if self.execute(query, commit=False):
7483
retVal = self.fetchall()
7584

7685
try:

0 commit comments

Comments
 (0)