Fixing --common-columns for -T A,B

This commit is contained in:
Miroslav Štampar 2026-07-28 16:42:37 +02:00
parent e8a2fc50e0
commit 356984929f
3 changed files with 27 additions and 6 deletions

View file

@ -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.222"
VERSION = "1.10.7.223"
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)

View file

@ -293,7 +293,9 @@ def columnExists(columnFile, regex=None):
warnMsg = "no column(s) found"
logger.warning(warnMsg)
else:
columns = {}
# Note: a separate name from the 'columns' wordlist (a list reused across the
# conf.tbl loop); reusing it here would rebind it to a dict and break later tables
columnData = {}
for column in threadData.shared.files:
if Backend.getIdentifiedDbms() in (DBMS.MYSQL,):
@ -306,15 +308,15 @@ def columnExists(columnFile, regex=None):
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column)))
if result:
columns[column] = "numeric"
columnData[column] = "numeric"
else:
columns[column] = "non-numeric"
columnData[column] = "non-numeric"
if conf.db not in kb.data.cachedColumns:
kb.data.cachedColumns[conf.db] = {}
kb.data.cachedColumns[conf.db][table] = columns
kb.data.cachedColumns[conf.db][table] = columnData
for _ in ((conf.db, table, item[0], item[1]) for item in columns.items()):
for _ in ((conf.db, table, item[0], item[1]) for item in columnData.items()):
if _ not in kb.brute.columns:
kb.brute.columns.append(_)

View file

@ -184,6 +184,25 @@ class TestBrute(DbmsStateMixin, unittest.TestCase):
self.assertEqual(cols.get(getText(safeSQLIdentificatorNaming("id"))), "numeric")
self.assertEqual(cols.get(getText(safeSQLIdentificatorNaming("name"))), "non-numeric")
def test_column_exists_multiple_tables(self):
# regression: the found-columns dict must not rebind the 'columns' wordlist list,
# else the 2nd table in conf.tbl indexes a dict by int -> KeyError (crash/hang)
set_dbms(DBMS.MYSQL)
conf.tbl = "users,logs"
brute.getFileItems = lambda *a, **k: ["id", "name"]
def _cbe(expression, expectingNone=True):
if not any(_ in expression for _ in ("users", "logs")):
return False # random-name sanity probe
return True # every column exists (type follow-ups don't matter here)
brute.inject.checkBooleanExpression = _cbe
# pre-fix the 2nd table iteration raised KeyError (dict indexed by int); post-fix
# both tables are processed and cached (keys are safeSQLIdentificatorNaming'd)
result = brute.columnExists("/nonexistent/columns.txt")
self.assertEqual(len(result[None]), 2)
self.assertTrue(all(cols for cols in result[None].values()))
def test_add_page_text_words_filters(self):
# restore the real getPageWordSet for this one and drive it directly
brute.getPageWordSet = self._orig_getPageWordSet