Adding support for FrontBase

This commit is contained in:
Miroslav Stampar 2020-03-02 12:43:12 +01:00
parent dc6e7321e9
commit 125de093df
29 changed files with 1178 additions and 33 deletions

View file

@ -535,7 +535,7 @@ class Agent(object):
"""
prefixRegex = r"(?:\s+(?:FIRST|SKIP|LIMIT(?: \d+)?)\s+\d+)*"
fieldsSelectTop = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
fieldsSelectTop = re.search(r"\ASELECT\s+TOP\s+([\d]|\([^)]+\))+\s+(.+?)\s+FROM", query, re.I)
fieldsSelectRownum = re.search(r"\ASELECT\s+([^()]+?),\s*ROWNUM AS LIMIT FROM", query, re.I)
fieldsSelectDistinct = re.search(r"\ASELECT%s\s+DISTINCT\((.+?)\)\s+FROM" % prefixRegex, query, re.I)
fieldsSelectCase = re.search(r"\ASELECT%s\s+(\(CASE WHEN\s+.+\s+END\))" % prefixRegex, query, re.I)
@ -560,7 +560,7 @@ class Agent(object):
if fieldsSelect:
fieldsToCastStr = fieldsSelect.group(1)
elif fieldsSelectTop:
fieldsToCastStr = fieldsSelectTop.group(1)
fieldsToCastStr = fieldsSelectTop.group(2)
elif fieldsSelectRownum:
fieldsToCastStr = fieldsSelectRownum.group(1)
elif fieldsSelectDistinct:
@ -660,7 +660,7 @@ class Agent(object):
elif fieldsNoSelect:
concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop)
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.EXTREMEDB):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.ALTIBASE, DBMS.MIMERSQL, DBMS.CRATEDB, DBMS.CUBRID, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE):
if fieldsExists:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1)
concatenatedQuery += "||'%s'" % kb.chars.stop
@ -983,6 +983,11 @@ class Agent(object):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num)
limitedQuery += " %s" % limitStr
elif Backend.getIdentifiedDbms() in (DBMS.FRONTBASE,):
limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1)
if query.startswith("SELECT "):
limitedQuery = query.replace("SELECT ", "SELECT %s " % limitStr, 1)
elif Backend.getIdentifiedDbms() in (DBMS.MONETDB,):
if query.startswith("SELECT ") and field is not None and field in query:
original = query.split("SELECT ", 1)[1].split(" FROM", 1)[0]

View file

@ -2821,6 +2821,10 @@ def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False):
>>> urlencode('AND 1>(2+3)#')
'AND%201%3E%282%2B3%29%23'
>>> urlencode('AND COUNT(SELECT name FROM users WHERE name LIKE \\'%DBA%\\')>0')
'AND%20COUNT%28SELECT%20name%20FROM%20users%20WHERE%20name%20LIKE%20%27%25DBA%25%27%29%3E0'
>>> urlencode('AND COUNT(SELECT name FROM users WHERE name LIKE \\'%_SYSTEM%\\')>0')
'AND%20COUNT%28SELECT%20name%20FROM%20users%20WHERE%20name%20LIKE%20%27%25_SYSTEM%25%27%29%3E0'
"""
if conf.get("direct"):
@ -2843,8 +2847,8 @@ def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False):
# encoded (when not representing URL encoded char)
# except in cases when tampering scripts are used
if all('%' in _ for _ in (safe, value)) and not kb.tamperFunctions:
value = re.sub(r"%(?![0-9a-fA-F]{2})", "%25", value)
value = re.sub(r"(?<= ')%", "%25", value) # e.g. LIKE '%DBA%'
value = re.sub(r"%(?![0-9a-fA-F]{2})", "%25", value)
while True:
result = _urllib.parse.quote(getBytes(value), safe)
@ -4086,12 +4090,13 @@ def safeSQLIdentificatorNaming(name, isTable=False):
if _:
retVal = re.sub(r"(?i)\A\[?%s\]?\." % DEFAULT_MSSQL_SCHEMA, "%s." % DEFAULT_MSSQL_SCHEMA, retVal)
if retVal.upper() in kb.keywords or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ('.' if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal)
# Note: SQL 92 has restrictions for identifiers starting with underscore (e.g. http://www.frontbase.com/documentation/FBUsers_4.pdf)
if retVal.upper() in kb.keywords or (not isTable and (retVal or " ")[0] == '_') or (retVal or " ")[0].isdigit() or not re.match(r"\A[A-Za-z0-9_@%s\$]+\Z" % ('.' if _ else ""), retVal): # MsSQL is the only DBMS where we automatically prepend schema to table name (dot is normal)
retVal = unsafeSQLIdentificatorNaming(retVal)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users)
retVal = "`%s`" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE):
retVal = "\"%s\"" % retVal
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = "\"%s\"" % retVal.upper()
@ -4129,7 +4134,7 @@ def unsafeSQLIdentificatorNaming(name):
if isinstance(name, six.string_types):
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.CUBRID, DBMS.SQLITE):
retVal = name.replace("`", "")
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB):
elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CACHE, DBMS.EXTREMEDB, DBMS.FRONTBASE):
retVal = name.replace("\"", "")
elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = name.replace("\"", "").upper()

View file

@ -19,6 +19,7 @@ from lib.core.settings import DB2_ALIASES
from lib.core.settings import DERBY_ALIASES
from lib.core.settings import EXTREMEDB_ALIASES
from lib.core.settings import FIREBIRD_ALIASES
from lib.core.settings import FRONTBASE_ALIASES
from lib.core.settings import H2_ALIASES
from lib.core.settings import HSQLDB_ALIASES
from lib.core.settings import INFORMIX_ALIASES
@ -242,6 +243,7 @@ DBMS_DICT = {
DBMS.CUBRID: (CUBRID_ALIASES, "CUBRID-Python", "https://github.com/CUBRID/cubrid-python", None),
DBMS.CACHE: (CACHE_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None),
DBMS.EXTREMEDB: (EXTREMEDB_ALIASES, None, None, None),
DBMS.FRONTBASE: (FRONTBASE_ALIASES, None, None, None),
}
# Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/
@ -255,6 +257,7 @@ FROM_DUMMY_TABLE = {
DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL",
DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1",
DBMS.MIMERSQL: " FROM SYSTEM.ONEROW",
DBMS.FRONTBASE: " FROM INFORMATION_SCHEMA.IO_STATISTICS"
}
HEURISTIC_NULL_EVAL = {

View file

@ -164,7 +164,7 @@ class Dump(object):
self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER)
def currentDb(self, data):
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE):
if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CACHE, DBMS.FRONTBASE):
self.string("current database (equivalent to schema on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB):
self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)

View file

@ -56,6 +56,7 @@ class DBMS(object):
CUBRID = "Cubrid"
CACHE = "InterSystems Cache"
EXTREMEDB = "eXtremeDB"
FRONTBASE = "FrontBase"
class DBMS_DIRECTORY_NAME(object):
ACCESS = "access"
@ -82,6 +83,7 @@ class DBMS_DIRECTORY_NAME(object):
CUBRID = "cubrid"
CACHE = "cache"
EXTREMEDB = "extremedb"
FRONTBASE = "frontbase"
class FORK(object):
MARIADB = "MariaDB"
@ -426,3 +428,8 @@ class TIMEOUT_STATE(object):
class HINT(object):
PREPEND = 0
APPEND = 1
class FUZZ_UNION_COLUMN:
STRING = "<string>"
INTEGER = "<integer>"
NULL = "NULL"

View file

@ -1920,6 +1920,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.forceWhere = None
kb.forkNote = None
kb.futileUnion = None
kb.fuzzUnionTest = None
kb.heavilyDynamic = False
kb.headersFile = None
kb.headersFp = {}
@ -2019,6 +2020,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.uChar = NULL
kb.udfFail = False
kb.unionDuplicates = False
kb.unionTemplate = None
kb.webSocketRecvCount = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False

View file

@ -93,6 +93,12 @@ PERMISSION_DENIED_REGEX = r"(?P<result>(command|permission|access)\s*(was|is)?\s
# Regular expression used in recognition of generic protection mechanisms
GENERIC_PROTECTION_REGEX = r"(?i)\b(rejected|blocked|protection|incident|denied|detected|dangerous|firewall)\b"
# Regular expression used to detect errors in fuzz(y) UNION test
FUZZ_UNION_ERROR_REGEX = r"(?i)data\s?type|comparable|compatible|conversion|converting|failed|error"
# Upper threshold for starting the fuzz(y) UNION test
FUZZ_UNION_MAX_COLUMNS = 10
# Regular expression used for recognition of generic maximum connection messages
MAX_CONNECTIONS_REGEX = r"\bmax.+?\bconnection"
@ -270,6 +276,7 @@ CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys")
CUBRID_SYSTEM_DBS = ("DBA",)
CACHE_SYSTEM_DBS = ("%Dictionary", "INFORMATION_SCHEMA", "%SYS")
EXTREMEDB_SYSTEM_DBS = ("",)
FRONTBASE_SYSTEM_DBS = ("DEFINITION_SCHEMA", "INFORMATION_SCHEMA")
# Note: (<regular>) + (<forks>)
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
@ -296,13 +303,14 @@ CRATEDB_ALIASES = ("cratedb", "crate")
CUBRID_ALIASES = ("cubrid",)
CACHE_ALIASES = ("cachedb", "cache")
EXTREMEDB_ALIASES = ("extremedb", "extreme")
FRONTBASE_ALIASES = ("frontbase",)
DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_"))
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES + SQLITE_ALIASES + ACCESS_ALIASES + FIREBIRD_ALIASES + MAXDB_ALIASES + SYBASE_ALIASES + DB2_ALIASES + HSQLDB_ALIASES + H2_ALIASES + INFORMIX_ALIASES + MONETDB_ALIASES + DERBY_ALIASES + VERTICA_ALIASES + MCKOI_ALIASES + PRESTO_ALIASES + ALTIBASE_ALIASES + MIMERSQL_ALIASES + CRATEDB_ALIASES + CUBRID_ALIASES + CACHE_ALIASES + EXTREMEDB_ALIASES
SUPPORTED_OS = ("linux", "windows")
DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES), (DBMS.HSQLDB, HSQLDB_ALIASES), (DBMS.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_ALIASES), (DBMS.VERTICA, VERTICA_ALIASES), (DBMS.MCKOI, MCKOI_ALIASES), (DBMS.PRESTO, PRESTO_ALIASES), (DBMS.ALTIBASE, ALTIBASE_ALIASES), (DBMS.MIMERSQL, MIMERSQL_ALIASES), (DBMS.CRATEDB, CRATEDB_ALIASES), (DBMS.CUBRID, CUBRID_ALIASES), (DBMS.CACHE, CACHE_ALIASES), (DBMS.EXTREMEDB, EXTREMEDB_ALIASES))
DBMS_ALIASES = ((DBMS.MSSQL, MSSQL_ALIASES), (DBMS.MYSQL, MYSQL_ALIASES), (DBMS.PGSQL, PGSQL_ALIASES), (DBMS.ORACLE, ORACLE_ALIASES), (DBMS.SQLITE, SQLITE_ALIASES), (DBMS.ACCESS, ACCESS_ALIASES), (DBMS.FIREBIRD, FIREBIRD_ALIASES), (DBMS.MAXDB, MAXDB_ALIASES), (DBMS.SYBASE, SYBASE_ALIASES), (DBMS.DB2, DB2_ALIASES), (DBMS.HSQLDB, HSQLDB_ALIASES), (DBMS.H2, H2_ALIASES), (DBMS.INFORMIX, INFORMIX_ALIASES), (DBMS.MONETDB, MONETDB_ALIASES), (DBMS.DERBY, DERBY_ALIASES), (DBMS.VERTICA, VERTICA_ALIASES), (DBMS.MCKOI, MCKOI_ALIASES), (DBMS.PRESTO, PRESTO_ALIASES), (DBMS.ALTIBASE, ALTIBASE_ALIASES), (DBMS.MIMERSQL, MIMERSQL_ALIASES), (DBMS.CRATEDB, CRATEDB_ALIASES), (DBMS.CUBRID, CUBRID_ALIASES), (DBMS.CACHE, CACHE_ALIASES), (DBMS.EXTREMEDB, EXTREMEDB_ALIASES), (DBMS.FRONTBASE, FRONTBASE_ALIASES))
USER_AGENT_ALIASES = ("ua", "useragent", "user-agent")
REFERER_ALIASES = ("ref", "referer", "referrer")

View file

@ -22,7 +22,7 @@ class Unescaper(AttribDict):
if dbms is not None:
retVal = self[dbms](expression, quote=quote)
elif identifiedDbms is not None:
elif identifiedDbms is not None and identifiedDbms in self:
retVal = self[identifiedDbms](expression, quote=quote)
else:
retVal = expression