mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-06-20 14:40:36 +00:00
107 lines
4.1 KiB
Python
107 lines
4.1 KiB
Python
#!/usr/bin/env python
|
|
|
|
"""
|
|
Copyright (c) 2006-2026 sqlmap developers (https://sqlmap.org)
|
|
See the file 'LICENSE' for copying permission
|
|
|
|
Per-DBMS query building (the injection-engine "dialect" layer).
|
|
|
|
These pin the exact SQL that agent.* emits for each back-end. They are the
|
|
regression net for queries.xml edits and for dialect gates in agent.py - the
|
|
kind of change that silently mis-builds a payload for one DBMS while leaving
|
|
every other green.
|
|
|
|
Includes the SYBASE limitQuery fix: Sybase must now emit a TOP-based limited
|
|
query like MSSQL (previously it fell through and returned the query unchanged).
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import unittest
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
from _testutils import bootstrap, set_dbms
|
|
bootstrap()
|
|
|
|
from lib.core.agent import agent
|
|
from lib.core.enums import DBMS
|
|
|
|
|
|
class TestLimitQuery(unittest.TestCase):
|
|
"""agent.limitQuery(num, query, field) per dialect (probed, not guessed)."""
|
|
|
|
def test_mysql(self):
|
|
set_dbms(DBMS.MYSQL)
|
|
self.assertEqual(agent.limitQuery(0, "SELECT name FROM users", "name"),
|
|
"SELECT name FROM users LIMIT 0,1")
|
|
|
|
def test_pgsql(self):
|
|
set_dbms(DBMS.PGSQL)
|
|
self.assertEqual(agent.limitQuery(0, "SELECT name FROM users", "name"),
|
|
"SELECT name FROM users OFFSET 0 LIMIT 1")
|
|
|
|
def test_oracle(self):
|
|
set_dbms(DBMS.ORACLE)
|
|
self.assertEqual(agent.limitQuery(0, "SELECT name FROM users", "name"),
|
|
"SELECT name FROM (SELECT name,ROWNUM AS CAP FROM users) WHERE CAP=1")
|
|
|
|
def test_mssql_is_top_based(self):
|
|
set_dbms(DBMS.MSSQL)
|
|
q = agent.limitQuery(0, "SELECT name FROM users", "name")
|
|
self.assertTrue(q.startswith("SELECT TOP 1 name FROM users WHERE"), msg=q)
|
|
self.assertIn("ORDER BY 1", q)
|
|
|
|
def test_sybase_limit_fix_is_top_based(self):
|
|
# REGRESSION: the user's limitQuery fix. Sybase must now produce a TOP-based
|
|
# limited query (mirroring MSSQL), NOT the query returned unchanged.
|
|
set_dbms(DBMS.SYBASE)
|
|
q = agent.limitQuery(0, "SELECT name FROM users", "name")
|
|
self.assertTrue(q.startswith("SELECT TOP 1 name FROM users WHERE"), msg=q)
|
|
self.assertIn("ORDER BY 1", q)
|
|
self.assertNotEqual(q, "SELECT name FROM users") # the pre-fix (broken) behavior
|
|
# Sybase casts via CONVERT(VARCHAR(...)), distinguishing it from MSSQL's NVARCHAR
|
|
self.assertIn("CONVERT(VARCHAR", q)
|
|
|
|
|
|
class TestNullAndCastField(unittest.TestCase):
|
|
"""agent.nullAndCastField('col') differs per dialect - pin each."""
|
|
|
|
CASES = {
|
|
DBMS.MYSQL: "IFNULL(CAST(col AS NCHAR),' ')",
|
|
DBMS.MSSQL: "ISNULL(CAST(col AS NVARCHAR(4000)),' ')",
|
|
DBMS.SYBASE: "ISNULL(CONVERT(VARCHAR(4000),col),' ')",
|
|
DBMS.PGSQL: "COALESCE(CAST(col AS VARCHAR(10000))::text,' ')",
|
|
DBMS.ORACLE: "NVL(CAST(col AS VARCHAR(4000)),' ')",
|
|
}
|
|
|
|
def test_per_dbms(self):
|
|
for dbms, expected in self.CASES.items():
|
|
set_dbms(dbms)
|
|
self.assertEqual(agent.nullAndCastField("col"), expected, msg="nullAndCastField for %s" % dbms)
|
|
|
|
|
|
class TestHexConvertField(unittest.TestCase):
|
|
# hexConvertField differs per dialect; pin each (was a one-platform stub before)
|
|
CASES = {
|
|
DBMS.MYSQL: "HEX(name)",
|
|
DBMS.ORACLE: "RAWTOHEX(name)",
|
|
DBMS.PGSQL: "ENCODE(CONVERT_TO((name),'UTF8'),'HEX')",
|
|
DBMS.MSSQL: "master.dbo.fn_varbintohexstr(CAST(name AS VARBINARY(8000)))",
|
|
}
|
|
|
|
def test_per_dbms(self):
|
|
for dbms, expected in self.CASES.items():
|
|
set_dbms(dbms)
|
|
self.assertEqual(agent.hexConvertField("name"), expected, msg="hexConvertField for %s" % dbms)
|
|
|
|
|
|
class TestForgeUnionQuery(unittest.TestCase):
|
|
def test_position_and_count(self):
|
|
# count=3, position=1 -> the real column is slotted at index 1, NULLs elsewhere
|
|
set_dbms(DBMS.MYSQL)
|
|
q = agent.forgeUnionQuery("SELECT a FROM t", 1, 3, None, "", "", "NULL", None)
|
|
self.assertEqual(q, " UNION ALL SELECT NULL,a,NULL FROM t")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|