mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-07-12 03:23:27 +00:00
Minor patches
This commit is contained in:
parent
97c8b45ccc
commit
ab59a4b72a
8 changed files with 62 additions and 13 deletions
|
|
@ -20,7 +20,7 @@ from lib.core.enums import OS
|
|||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.7.80"
|
||||
VERSION = "1.10.7.81"
|
||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
|
|||
See the file 'LICENSE' for copying permission
|
||||
"""
|
||||
|
||||
import binascii
|
||||
import re
|
||||
import time
|
||||
|
||||
|
|
@ -29,6 +30,20 @@ from lib.core.settings import UNICODE_ENCODING
|
|||
from lib.utils.safe2bin import safecharencode
|
||||
from lib.utils.timeout import timeout
|
||||
|
||||
def _hexifyBinary(value):
|
||||
"""
|
||||
Renders a raw binary cell returned by a driver in -d mode as uppercase hex, instead of letting it reach
|
||||
the text channel as a str() like '<memory at 0x...>' (PostgreSQL bytea -> psycopg2 memoryview) or a
|
||||
control-character blob that gets blanked/corrupted (e.g. MSSQL varbinary -> bytes). Text columns come back
|
||||
as native strings, so only genuine binary values are converted (matches HEX()-based rendering elsewhere).
|
||||
"""
|
||||
|
||||
if isinstance(value, memoryview):
|
||||
value = value.tobytes()
|
||||
if isinstance(value, (bytes, bytearray)):
|
||||
return getUnicode(binascii.hexlify(value)).upper()
|
||||
return value
|
||||
|
||||
def direct(query, content=True):
|
||||
select = True
|
||||
query = agent.payloadDirect(query)
|
||||
|
|
@ -63,6 +78,8 @@ def direct(query, content=True):
|
|||
timeout(func=conf.dbmsConnector.execute, args=(query,), duration=conf.timeout, default=None)
|
||||
elif not (output and ("%soutput" % conf.tablePrefix) not in query and ("%sfile" % conf.tablePrefix) not in query):
|
||||
output, state = timeout(func=conf.dbmsConnector.select, args=(query,), duration=conf.timeout, default=None)
|
||||
if output and isListLike(output):
|
||||
output = [tuple(_hexifyBinary(_) for _ in row) if isListLike(row) else _hexifyBinary(row) for row in output]
|
||||
if state == TIMEOUT_STATE.NORMAL:
|
||||
hashDBWrite(query, output, True)
|
||||
elif state == TIMEOUT_STATE.TIMEOUT:
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ class SQLAlchemy(GenericConnector):
|
|||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
|
||||
return None
|
||||
|
||||
def execute(self, query):
|
||||
def execute(self, query, commit=True):
|
||||
retVal = False
|
||||
|
||||
# Reference: https://stackoverflow.com/a/69491015
|
||||
|
|
@ -126,10 +126,14 @@ class SQLAlchemy(GenericConnector):
|
|||
|
||||
try:
|
||||
self.cursor = self.connector.execute(query)
|
||||
if hasattr(self.connector, "commit"): # Note: SQLAlchemy 2.0+ dropped implicit autocommit (otherwise DML changes - e.g. via --sql-query - would be silently lost)
|
||||
# Note: SQLAlchemy 2.0+ dropped implicit autocommit (otherwise DML changes - e.g. via --sql-query -
|
||||
# would be silently lost). SELECT goes through select() with commit=False so the result set is
|
||||
# fetched BEFORE committing: on some drivers (e.g. pymssql) commit() discards the open cursor, which
|
||||
# otherwise made every MSSQL '-d' query silently return empty (banner/is-dba/dump all blank).
|
||||
if commit and hasattr(self.connector, "commit"):
|
||||
self.connector.commit()
|
||||
retVal = True
|
||||
except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError) as ex:
|
||||
except (_sqlalchemy.exc.OperationalError, _sqlalchemy.exc.ProgrammingError, _sqlalchemy.exc.DataError, _sqlalchemy.exc.IntegrityError) as ex:
|
||||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex))
|
||||
# Roll back the failed statement's transaction so it does not poison every following query with
|
||||
# 'InFailedSqlTransaction' (SQLAlchemy 2.0+ keeps the transaction open after an error). Without this
|
||||
|
|
@ -148,7 +152,14 @@ class SQLAlchemy(GenericConnector):
|
|||
def select(self, query):
|
||||
retVal = None
|
||||
|
||||
if self.execute(query):
|
||||
# Fetch BEFORE committing (commit=False): committing can discard the open result cursor on some drivers
|
||||
# (e.g. pymssql), which silently emptied every MSSQL '-d' result. No DML is persisted by a SELECT anyway.
|
||||
if self.execute(query, commit=False):
|
||||
retVal = self.fetchall()
|
||||
if hasattr(self.connector, "commit"):
|
||||
try:
|
||||
self.connector.commit()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return retVal
|
||||
|
|
|
|||
|
|
@ -54,11 +54,20 @@ class Connector(GenericConnector):
|
|||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
|
||||
return None
|
||||
|
||||
def execute(self, query):
|
||||
def execute(self, query, commit=True):
|
||||
retVal = False
|
||||
|
||||
try:
|
||||
self.cursor.execute(getText(query))
|
||||
# Commit non-SELECT (DML/DDL) here: direct() routes those to execute() alone, so without this a
|
||||
# '--sql-query'/'--sql-shell' write was silently rolled back on connection close. select() passes
|
||||
# commit=False and commits only AFTER fetchall(), because on pymssql commit() discards the open
|
||||
# result cursor (which otherwise emptied every SELECT result).
|
||||
if commit:
|
||||
try:
|
||||
self.connector.commit()
|
||||
except pymssql.OperationalError:
|
||||
pass
|
||||
retVal = True
|
||||
except (pymssql.OperationalError, pymssql.ProgrammingError) as ex:
|
||||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
|
||||
|
|
@ -70,7 +79,7 @@ class Connector(GenericConnector):
|
|||
def select(self, query):
|
||||
retVal = None
|
||||
|
||||
if self.execute(query):
|
||||
if self.execute(query, commit=False):
|
||||
retVal = self.fetchall()
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ except:
|
|||
|
||||
import logging
|
||||
import struct
|
||||
import sys
|
||||
|
||||
from lib.core.common import getSafeExString
|
||||
from lib.core.data import conf
|
||||
|
|
@ -34,7 +33,7 @@ class Connector(GenericConnector):
|
|||
self.initConnection()
|
||||
|
||||
try:
|
||||
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)
|
||||
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)
|
||||
except (pymysql.OperationalError, pymysql.InternalError, pymysql.ProgrammingError, struct.error) as ex:
|
||||
raise SqlmapConnectionException(getSafeExString(ex))
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,10 @@ class Connector(GenericConnector):
|
|||
try:
|
||||
self.cursor.execute(query)
|
||||
retVal = True
|
||||
except (psycopg2.OperationalError, psycopg2.ProgrammingError) as ex:
|
||||
# Note: also catch DataError/IntegrityError (e.g. division-by-zero, bad cast, unique violation from a
|
||||
# user '--sql-query') so the commit() below still runs and clears the aborted transaction; otherwise
|
||||
# PostgreSQL poisons every later query with 'InFailedSqlTransaction' and silently returns None
|
||||
except (psycopg2.OperationalError, psycopg2.ProgrammingError, psycopg2.DataError, psycopg2.IntegrityError) as ex:
|
||||
logger.warning(("(remote) '%s'" % getSafeExString(ex)).strip())
|
||||
except psycopg2.InternalError as ex:
|
||||
raise SqlmapConnectionException(getSafeExString(ex))
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from lib.core.common import isNoneValue
|
|||
from lib.core.common import isStackingAvailable
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.compat import LooseVersion
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
|
|
@ -100,7 +101,7 @@ class Takeover(GenericTakeover):
|
|||
def copyExecCmd(self, cmd):
|
||||
output = None
|
||||
|
||||
if isStackingAvailable():
|
||||
if isStackingAvailable() or conf.direct:
|
||||
# Reference: https://medium.com/greenwolf-security/authenticated-arbitrary-command-execution-on-postgresql-9-3-latest-cd18945914d5
|
||||
self._forgedCmd = "DROP TABLE IF EXISTS %s;" % self.cmdTblName
|
||||
self._forgedCmd += "CREATE TABLE %s(%s text);" % (self.cmdTblName, self.tblField)
|
||||
|
|
|
|||
|
|
@ -54,11 +54,20 @@ class Connector(GenericConnector):
|
|||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
|
||||
return None
|
||||
|
||||
def execute(self, query):
|
||||
def execute(self, query, commit=True):
|
||||
retVal = False
|
||||
|
||||
try:
|
||||
self.cursor.execute(getText(query))
|
||||
# Commit non-SELECT (DML/DDL) here: direct() routes those to execute() alone, so without this a
|
||||
# '--sql-query'/'--sql-shell' write was silently rolled back on connection close. select() passes
|
||||
# commit=False and commits only AFTER fetchall(), because on pymssql commit() discards the open
|
||||
# result cursor (which otherwise emptied every SELECT result).
|
||||
if commit:
|
||||
try:
|
||||
self.connector.commit()
|
||||
except pymssql.OperationalError:
|
||||
pass
|
||||
retVal = True
|
||||
except (pymssql.OperationalError, pymssql.ProgrammingError) as ex:
|
||||
logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) '%s'" % getSafeExString(ex).replace("\n", " "))
|
||||
|
|
@ -70,7 +79,7 @@ class Connector(GenericConnector):
|
|||
def select(self, query):
|
||||
retVal = None
|
||||
|
||||
if self.execute(query):
|
||||
if self.execute(query, commit=False):
|
||||
retVal = self.fetchall()
|
||||
|
||||
try:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue