+
+
+برای اطلاعات بیشتر برای اجرا از [اینجا](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
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 @@
[](https://travis-ci.org/sqlmapproject/sqlmap) [](https://www.python.org/) [](https://raw.githubusercontent.com/sqlmapproject/sqlmap/master/LICENSE) [](https://badge.fury.io/py/sqlmap) [](https://github.com/sqlmapproject/sqlmap/issues?q=is%3Aissue+is%3Aclosed) [](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
----
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 e4ea94d74..8f22c5e2c 100755
--- a/extra/shutils/pyflakes.sh
+++ b/extra/shutils/pyflakes.sh
@@ -1,7 +1,7 @@
#!/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)
-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/extra/shutils/pypi.sh b/extra/shutils/pypi.sh
index 016853a06..4111954f6 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
"""
@@ -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/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 d70f52f17..b5175711b 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
"""
@@ -16,8 +16,10 @@ import sys
import threading
import traceback
-if sys.version_info >= (3, 0):
- from http.client import FOUND
+PY3 = sys.version_info >= (3, 0)
+UNICODE_ENCODING = "utf-8"
+
+if PY3:
from http.client import INTERNAL_SERVER_ERROR
from http.client import NOT_FOUND
from http.client import OK
@@ -29,7 +31,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
@@ -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:
")
@@ -171,7 +172,7 @@ class ReqHandler(BaseHTTPRequestHandler):
self.end_headers()
else:
self.end_headers()
- self.wfile.write(output.encode("utf8"))
+ self.wfile.write(output if isinstance(output, bytes) else output.encode(UNICODE_ENCODING))
else:
self.send_response(NOT_FOUND)
self.send_header("Connection", "close")
@@ -190,8 +191,27 @@ 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, "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/__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 6ae232373..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
"""
@@ -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/controller/checks.py b/lib/controller/checks.py
index f0630ec89..9e558a414 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
"""
@@ -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
@@ -53,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
@@ -96,6 +98,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
@@ -518,8 +521,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
@@ -600,7 +601,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
@@ -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))
@@ -881,12 +882,17 @@ def heuristicCheckDbms(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
+ 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 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
@@ -930,6 +936,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/controller/controller.py b/lib/controller/controller.py
index 3f122f5f9..57414dcfb 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
"""
@@ -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
@@ -456,18 +466,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))
diff --git a/lib/controller/handler.py b/lib/controller/handler.py
index 6ab21b71a..97f87c407 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
"""
@@ -11,47 +11,74 @@ 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 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
+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 MIMERSQL_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 VERTICA_ALIASES
from lib.utils.sqlalchemy import SQLAlchemy
-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.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.hsqldb import HSQLDBMap
-from plugins.dbms.hsqldb.connector import Connector as HSQLDBConn
-from plugins.dbms.h2 import H2Map
+from plugins.dbms.db2 import DB2Map
+from plugins.dbms.derby.connector import Connector as DerbyConn
+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.informix import InformixMap
+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.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
+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():
"""
@@ -73,6 +100,15 @@ 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),
+ (DBMS.DERBY, DERBY_ALIASES, DerbyMap, DerbyConn),
+ (DBMS.VERTICA, VERTICA_ALIASES, VerticaMap, VerticaConn),
+ (DBMS.MCKOI, MCKOI_ALIASES, MckoiMap, MckoiConn),
+ (DBMS.PRESTO, PRESTO_ALIASES, PrestoMap, PrestoConn),
+ (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/__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 5b0a1e21c..51f79017e 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
"""
@@ -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
@@ -44,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
@@ -184,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))
@@ -247,7 +253,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
@@ -294,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() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")):
- comment = queries[DBMS.ACCESS].comment.query
+ if any((comment or "").startswith(_) for _ in ("--", GENERIC_SQL_COMMENT_MARKER)):
+ 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:
expression += comment
@@ -381,6 +388,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) 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)
+
return payload
def getComment(self, request):
@@ -438,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:
@@ -446,7 +458,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
@@ -648,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):
+ 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
@@ -708,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):
@@ -937,10 +971,28 @@ 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, DBMS.PRESTO, DBMS.MIMERSQL, DBMS.CUBRID):
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, DBMS.CRATEDB):
+ 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]
+ 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:
@@ -1036,12 +1088,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/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 21c9845e2..dee8fc2f3 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
"""
@@ -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
@@ -76,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
@@ -139,6 +139,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
@@ -147,6 +148,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
@@ -557,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
@@ -943,6 +949,13 @@ 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"))
+
+ 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
@@ -1080,7 +1093,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:
@@ -1104,7 +1117,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:
@@ -1123,8 +1139,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):
"""
@@ -1372,7 +1390,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")
@@ -1393,7 +1410,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")
@@ -1458,7 +1474,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")
@@ -1643,15 +1659,15 @@ 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):
+ 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]
@@ -1970,7 +1986,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
@@ -2018,6 +2034,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()):
@@ -2043,7 +2061,7 @@ def safeStringFormat(format_, params):
else:
break
- retVal = getText(retVal)
+ retVal = getText(retVal).replace(PARAMETER_PERCENTAGE_MARKER, '%')
return retVal
@@ -2315,16 +2333,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.
@@ -2707,6 +2715,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):
@@ -2830,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)
@@ -3003,9 +3018,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):
@@ -3617,16 +3634,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)
@@ -4068,11 +4089,11 @@ 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.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.SQLITE, DBMS.HSQLDB, DBMS.H2, DBMS.INFORMIX):
+ 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,):
+ elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.ALTIBASE, DBMS.MIMERSQL):
retVal = "\"%s\"" % retVal.upper()
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
if isTable:
@@ -4106,11 +4127,11 @@ 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.CUBRID, 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.HSQLDB, DBMS.H2, DBMS.INFORMIX, DBMS.MONETDB, DBMS.VERTICA, DBMS.MCKOI, DBMS.PRESTO, DBMS.CRATEDB):
retVal = name.replace("\"", "")
- elif Backend.getIdentifiedDbms() in (DBMS.ORACLE,):
+ 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/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 51e7d7b85..4337e0525 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
"""
@@ -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
@@ -31,6 +32,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
@@ -221,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
@@ -231,6 +237,14 @@ def getBytes(value, encoding=UNICODE_ENCODING, errors="strict", unsafe=True):
retVal = value
+ if encoding is None:
+ encoding = conf.get("encoding") or UNICODE_ENCODING
+
+ try:
+ codecs.lookup(encoding)
+ except (LookupError, TypeError):
+ encoding = UNICODE_ENCODING
+
if isinstance(value, six.text_type):
if INVALID_UNICODE_PRIVATE_AREA:
if unsafe:
@@ -289,7 +303,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:
@@ -391,4 +405,4 @@ def getConsoleLength(value):
else:
retVal = len(value)
- return retVal
\ No newline at end of file
+ return retVal
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..8ddf00c63 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
"""
@@ -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/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..57c6b9bca 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
"""
@@ -10,20 +10,29 @@ 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 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
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 MIMERSQL_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
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
FIREBIRD_TYPES = {
261: "BLOB",
@@ -108,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",
@@ -198,8 +231,18 @@ 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"),
+ 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),
+ 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/
FROM_DUMMY_TABLE = {
DBMS.ORACLE: " FROM DUAL",
DBMS.ACCESS: " FROM MSysAccessObjects",
@@ -207,7 +250,29 @@ 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",
+ DBMS.MIMERSQL: " FROM SYSTEM.ONEROW",
+}
+
+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.H2: "STRINGTOUTF8(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)",
+ DBMS.MIMERSQL: "ASCII_CHAR(256)",
+ DBMS.CRATEDB: "MD5(NULL~NULL)", # Note: NULL~NULL also being evaluated on H2 and Ignite
+ DBMS.CUBRID: "(NULL SETEQ NULL)",
}
SQL_STATEMENTS = {
diff --git a/lib/core/dump.py b/lib/core/dump.py
index 31ca30326..4a6680be5 100644
--- a/lib/core/dump.py
+++ b/lib/core/dump.py
@@ -1,11 +1,10 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
-import cgi
import hashlib
import os
import re
@@ -31,6 +30,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
@@ -69,13 +69,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()
@@ -108,16 +107,12 @@ 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)
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)
@@ -137,8 +132,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:
@@ -151,7 +144,6 @@ class Dump(object):
if conf.api:
self._write(elements, content_type=content_type)
- return
if elements:
self._write("%s [%d]:" % (header, len(elements)))
@@ -172,10 +164,10 @@ 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):
- self.string("current schema (equivalent to database on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
+ if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.PGSQL, DBMS.HSQLDB, DBMS.H2, DBMS.MONETDB, DBMS.VERTICA, DBMS.CRATEDB):
+ self.string("current database (equivalent to schema on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
+ elif Backend.getIdentifiedDbms() in (DBMS.ALTIBASE, DBMS.DB2, DBMS.MIMERSQL, DBMS.MAXDB):
+ self.string("current database (equivalent to owner on %s)" % Backend.getIdentifiedDbms(), data, content_type=CONTENT_TYPE.CURRENT_DB)
else:
self.string("current database", data, content_type=CONTENT_TYPE.CURRENT_DB)
@@ -203,7 +195,6 @@ class Dump(object):
if conf.api:
self._write(userSettings, content_type=content_type)
- return
if userSettings:
self._write("%s:" % header)
@@ -237,7 +228,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
@@ -280,7 +270,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:
@@ -354,7 +343,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")
@@ -413,7 +401,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))
@@ -559,7 +546,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
@@ -631,7 +618,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
@@ -651,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:
@@ -669,7 +656,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":
diff --git a/lib/core/enums.py b/lib/core/enums.py
index a1264fb35..45e96c263 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
"""
@@ -42,9 +42,18 @@ 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"
+ MIMERSQL = "MimerSQL"
+ CRATEDB = "CrateDB"
+ CUBRID = "Cubrid"
class DBMS_DIRECTORY_NAME(object):
ACCESS = "access"
@@ -60,6 +69,28 @@ class DBMS_DIRECTORY_NAME(object):
HSQLDB = "hsqldb"
H2 = "h2"
INFORMIX = "informix"
+ MONETDB = "monetdb"
+ DERBY = "derby"
+ VERTICA = "vertica"
+ MCKOI = "mckoi"
+ PRESTO = "presto"
+ ALTIBASE = "altibase"
+ MIMERSQL = "mimersql"
+ CRATEDB = "cratedb"
+ CUBRID = "cubrid"
+
+class FORK(object):
+ MARIADB = "MariaDB"
+ MEMSQL = "MemSQL"
+ PERCONA = "Percona"
+ COCKROACHDB = "CockroachDB"
+ TIDB = "TiDB"
+ REDSHIFT = "Amazon Redshift"
+ GREENPLUM = "Greenplum"
+ DRIZZLE = "Drizzle"
+ IGNITE = "Apache Ignite"
+ AURORA = "Aurora"
+ ENTERPRISEDB = "EnterpriseDB"
class CUSTOM_LOGGING(object):
PAYLOAD = 9
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 bfb34326d..63c62f2e1 100644
--- a/lib/core/gui.py
+++ b/lib/core/gui.py
@@ -1,48 +1,55 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2020 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
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
+alive = None
line = ""
process = None
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
@@ -54,23 +61,23 @@ 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):
+ def _on_tab_changed(self, event):
event.widget.update_idletasks()
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()
- settings = {"TNotebook.Tab": {"configure": {"padding": [5, 1], "background": "#fdd57e" }, "map": {"background": [("selected", "#C70039"), ("active", "#fc9292")], "foreground": [("selected", "#ffffff"), ("active", "#000000")]}}}
+ 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")
@@ -110,48 +117,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
+ event.widget.insert(_tkinter.END, "\n")
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,18 +146,40 @@ 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)
- top = tkinter.Toplevel()
+ 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")
# 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()
@@ -187,24 +187,37 @@ def runGui(parser):
center(top)
- menubar = tkinter.Menu(window)
+ while True:
+ 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()
- filemenu = tkinter.Menu(menubar, tearoff=0)
- filemenu.add_command(label="Open", state=tkinter.DISABLED)
- filemenu.add_command(label="Save", state=tkinter.DISABLED)
+ if not alive:
+ break
+
+ 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.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))
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)
@@ -216,33 +229,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
@@ -251,15 +264,15 @@ 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()
first.focus()
- window.mainloop()
\ No newline at end of file
+ window.mainloop()
diff --git a/lib/core/log.py b/lib/core/log.py
index 096fdfd90..4142f60db 100644
--- a/lib/core/log.py
+++ b/lib/core/log.py
@@ -1,11 +1,12 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
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) 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)
+ 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/option.py b/lib/core/option.py
index 526693768..524945510 100644
--- a/lib/core/option.py
+++ b/lib/core/option.py
@@ -1,12 +1,13 @@
#!/usr/bin/env python
"""
-Copyright (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 __future__ import division
+import codecs
import functools
import glob
import inspect
@@ -120,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
@@ -329,8 +331,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:
@@ -340,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():
@@ -994,7 +1001,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]
@@ -1138,7 +1145,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():
@@ -1524,6 +1531,13 @@ def _cleanupOptions():
Cleanup configuration attributes.
"""
+ if conf.encoding:
+ try:
+ codecs.lookup(conf.encoding)
+ except LookupError:
+ errMsg = "unknown encoding '%s'" % conf.encoding
+ raise SqlmapValueException(errMsg)
+
debugMsg = "cleaning up configuration parameters"
logger.debug(debugMsg)
@@ -1721,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()
@@ -1751,6 +1764,13 @@ def _cleanupOptions():
conf.binaryFields = conf.binaryFields.replace(" ", "")
conf.binaryFields = re.split(PARAMETER_SPLITTING_REGEX, conf.binaryFields)
+ 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)
+
+ conf.proxy = envProxy
+
if any((conf.proxy, conf.proxyFile, conf.tor)):
conf.disablePrecon = True
@@ -1898,6 +1918,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
@@ -1998,6 +2019,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.uChar = NULL
kb.udfFail = False
kb.unionDuplicates = False
+ kb.webSocketRecvCount = None
kb.wizardMode = False
kb.xpCmdshellAvailable = False
@@ -2457,6 +2479,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)
@@ -2464,6 +2490,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)
@@ -2582,7 +2615,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)
@@ -2649,7 +2682,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 8da3b0399..472690076 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
"""
@@ -252,9 +252,6 @@ optDict = {
"forceDns": "boolean",
"murphyRate": "integer",
"smokeTest": "boolean",
- "liveTest": "boolean",
- "stopFail": "boolean",
- "runCase": "string",
},
"API": {
diff --git a/lib/core/patch.py b/lib/core/patch.py
index 60ac0ef10..b23651b57 100644
--- a/lib/core/patch.py
+++ b/lib/core/patch.py
@@ -1,11 +1,12 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import codecs
+import random
import lib.controller.checks
import lib.core.common
@@ -25,13 +26,18 @@ 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
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
+_rand = 0
+
def dirtyPatches():
"""
Place for "dirty" Python related patches
@@ -40,6 +46,18 @@ 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
@@ -87,3 +105,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/profiling.py b/lib/core/profiling.py
index 0fe0836d6..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
"""
@@ -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/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 3f4794336..b3e156dd1 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
"""
@@ -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.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)
@@ -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__"
@@ -74,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"
@@ -232,6 +234,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]
@@ -252,35 +257,60 @@ 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")
+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",)
+CRATEDB_SYSTEM_DBS = ("information_schema", "pg_catalog", "sys")
+CUBRID_SYSTEM_DBS = ("DBA",)
+# Note: () + ()
MSSQL_ALIASES = ("microsoft sql server", "mssqlserver", "mssql", "ms")
-MYSQL_ALIASES = ("mysql", "my", "mariadb", "maria")
-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")
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",)
+DERBY_ALIASES = ("derby", "apache derby",)
+VERTICA_ALIASES = ("vertica",)
+MCKOI_ALIASES = ("mckoi",)
+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
+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_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")
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"
+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")
@@ -382,7 +412,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+).*?(?P[^<]+)"
# 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 = ";()'"
@@ -558,11 +594,11 @@ 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/"
+# 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 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')#"
@@ -601,6 +637,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
@@ -653,7 +692,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"
@@ -713,7 +752,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")
@@ -758,7 +797,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"
diff --git a/lib/core/shell.py b/lib/core/shell.py
index e147223fd..47c00c050 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
"""
@@ -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)
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 d23fbb49d..49a93681d 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
"""
@@ -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()
@@ -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)
diff --git a/lib/core/testing.py b/lib/core/testing.py
index 99a280dce..d4cd8ae43 100644
--- a/lib/core/testing.py
+++ b/lib/core/testing.py
@@ -1,62 +1,37 @@
#!/usr/bin/env python
"""
-Copyright (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 __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.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 randomInt
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
-from lib.core.convert import getUnicode
-from lib.core.data import conf
+from lib.core.convert import encodeBase64
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.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
-
-class Failures(object):
- failedItems = None
- failedParseOn = None
- failedTraceBack = None
-
-_failures = Failures()
-_rand = 0
+from lib.core.patch import unisonRandom
def vulnTest():
"""
@@ -64,22 +39,33 @@ 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 --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 --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 --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")),
+ ("-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 --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=\"id2=2\" --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 --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 --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 --banner --schema --sql-query=\"SELECT 987654321\"", ("banner: '3", "INTEGER", "TEXT", "id", "name", "surname", "[*] 987654321",)),
+ ("-u '&query=*' --flush-session --technique=Q --banner", ("Title: SQLite inline queries", "banner: '3.")),
+ ("-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")),
)
retVal = True
@@ -102,6 +88,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)
@@ -112,19 +101,28 @@ 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\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)))
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))
+ 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 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
@@ -139,44 +137,183 @@ def vulnTest():
return retVal
-def dirtyPatchRandom():
+def bedTest():
"""
- Unifying random generated data across different Python versions
+ Runs the testing against 'testbed'
"""
- def _lcg():
- global _rand
- a = 1140671485
- c = 128201163
- m = 2 ** 24
- _rand = (a * _rand + c) % m
- return _rand
+ 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: 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 |")),
- def _randint(a, b):
- _ = a + (_lcg() % (b - a + 1))
- return _
+ # 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 |")),
- def _choice(seq):
- return seq[_randint(0, len(seq) - 1)]
+ # 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 database (equivalent to owner on Altibase): 'SYS'", "current user: 'SYS'", "[1 column]", "| SURNAME | VARCHAR |")),
- def _sample(population, k):
- return [_choice(population) for _ in xrange(k)]
+ # 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 database (equivalent to schema on PostgreSQL): 'public'", "current user: 'root'", "[1 column]", "| surname | varchar |")),
- def _seed(seed):
- global _rand
- _rand = seed
+ # 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 database (equivalent to schema on CrateDB): 'doc'", "current user: 'crate'", "[1 column]", "| surname |")),
- random.choice = _choice
- random.randint = _randint
- random.sample = _sample
- random.seed = _seed
+ # 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 |")),
+
+ # 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 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 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 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'")),
+ ("-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", "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 database (equivalent to schema on PostgreSQL): 'public'", "current user: 'testuser'", "[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)
+
+ 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 any(_ in lines[j] for _ in ("googleDork",)):
+ continue
+
+ 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 --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:
+ dataToStdout("---\n\n$ %s\n" % cmd)
+ dataToStdout("%s---\n" % clearColors(output))
+
+ 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
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):
+ 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
@@ -194,7 +331,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('.')
@@ -250,233 +387,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 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
- _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/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..5d26f7a48 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
"""
@@ -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/core/update.py b/lib/core/update.py
index 9cd588263..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
"""
@@ -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/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 c1a6cac4e..0c41c14d8 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
"""
@@ -78,10 +78,12 @@ 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
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
@@ -251,7 +253,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")
@@ -780,22 +782,22 @@ 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)
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)
- parser.add_argument("--stop-fail", dest="stopFail", action="store_true",
+ parser.add_argument("--bed-test", dest="bedTest", 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
@@ -863,10 +865,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()
@@ -930,6 +932,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"):
@@ -941,6 +945,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]
@@ -1002,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.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.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/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..9f73c519b 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
"""
@@ -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,20 +52,31 @@ 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")
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
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:
@@ -79,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
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 649fe5fc8..7b93a8705 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
"""
@@ -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]
@@ -568,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)
@@ -1038,11 +1053,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/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..af6244c9e 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
"""
@@ -11,10 +11,58 @@ import binascii
import os
import re
import socket
+import struct
import threading
import time
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""
+
+ 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
+ j = ord(raw[i:i + 1])
+ except TypeError:
+ pass
+
+ def response(self, resolution):
+ """
+ Crafts raw DNS resolution response packet
+ """
+
+ 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
+
+ return retVal
+
+class DNSServer(object):
"""
Used for making fake DNS resolution responses based on received
raw request
@@ -24,43 +72,6 @@ class DNSQuery(object):
https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py
"""
- def __init__(self, raw):
- self._raw = raw
- self._query = ""
-
- type_ = (ord(raw[2]) >> 3) & 15 # Opcode bits
-
- if type_ == 0: # Standard query
- i = 12
- j = ord(raw[i])
-
- while j != 0:
- self._query += raw[i + 1:i + j + 1] + '.'
- i = i + j + 1
- j = ord(raw[i])
-
- def response(self, resolution):
- """
- Crafts raw DNS resolution response packet
- """
-
- retVal = ""
-
- 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
-
- return retVal
-
-class DNSServer(object):
def __init__(self):
self._check_localhost()
self._requests = []
@@ -95,9 +106,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
@@ -148,7 +165,7 @@ if __name__ == "__main__":
if _ is None:
break
else:
- print("[i] %s" % _)
+ print("[i] %s" % _.decode())
time.sleep(1)
diff --git a/lib/request/httpshandler.py b/lib/request/httpshandler.py
index ff08ea3a2..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
"""
@@ -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/inject.py b/lib/request/inject.py
index 8b17a3941..ce9a2c0ec 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
"""
@@ -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, 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
+ 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)
@@ -410,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:
@@ -494,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) else ""
+ warnMsg += "or switch '--hex'" if hasattr(queries[Backend.getIdentifiedDbms()], "hex") else ""
singleTimeWarnMessage(warnMsg)
# Dirty patch (safe-encoded unicode characters)
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 e7889941f..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
"""
@@ -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
@@ -142,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()
@@ -152,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):
@@ -163,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
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..0abc6c574 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
"""
@@ -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/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 cd6289b88..7219814b4 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
"""
@@ -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
@@ -107,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:
@@ -118,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
@@ -129,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)
@@ -425,6 +434,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:
@@ -637,7 +650,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/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..ce63ba203 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
"""
@@ -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/__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 5e223575d..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
"""
@@ -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
diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py
index bdec4e797..64ef7b96a 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
"""
@@ -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 "
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 84d2327e1..4e30c9b6d 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
"""
@@ -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
@@ -459,7 +461,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})
@@ -705,23 +707,25 @@ 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):
logger.debug("Calling '%s'" % url)
try:
- data = None
- if options is not None:
- data = jsonize(options)
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()
+ text = getText(response.read())
except:
if options:
logger.error("Failed to load and parse %s" % url)
diff --git a/lib/utils/brute.py b/lib/utils/brute.py
index 7a004d261..f3877dae1 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
"""
@@ -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_DBMSES
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_DBMSES:
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()
@@ -163,7 +168,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:
@@ -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_DBMSES:
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()
@@ -289,6 +297,10 @@ 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)))
+ 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/lib/utils/crawler.py b/lib/utils/crawler.py
index d99b51fcb..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
"""
@@ -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
diff --git a/lib/utils/deps.py b/lib/utils/deps.py
index aec75c9cb..1c330931d 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
"""
@@ -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")
@@ -46,6 +46,18 @@ def checkDependencies():
__import__("jpype")
elif dbmsName == DBMS.INFORMIX:
__import__("ibm_db_dbi")
+ elif dbmsName == DBMS.MONETDB:
+ __import__("pymonetdb")
+ elif dbmsName == DBMS.DERBY:
+ __import__("drda")
+ elif dbmsName == DBMS.VERTICA:
+ __import__("vertica_python")
+ elif dbmsName == DBMS.PRESTO:
+ __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 "
@@ -81,7 +93,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:
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..fff9bdbd6 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
"""
@@ -33,7 +33,6 @@ else:
import base64
import binascii
import gc
-import hashlib
import os
import re
import tempfile
@@ -248,18 +247,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)
@@ -740,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
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..97874854a 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
"""
@@ -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/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..f11a9ab3b 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
"""
@@ -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, headers=requestHeaders)
+ req = _urllib.request.Request(url, data=getBytes(data), headers=requestHeaders)
conn = _urllib.request.urlopen(req)
requestMsg = "HTTP request:\nGET %s" % url
diff --git a/lib/utils/sqlalchemy.py b/lib/utils/sqlalchemy.py
index ac862498b..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
"""
@@ -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
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/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/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/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/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..d2235b0f5 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
"""
@@ -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 list 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/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/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..91a5e0c5d
--- /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 Apache Derby 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..cd2bf4671
--- /dev/null
+++ b/plugins/dbms/derby/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 Apache Derby it is not possible to execute commands"
+ raise SqlmapUnsupportedFeatureException(errMsg)
+
+ 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/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..d43ffdc8b 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
"""
@@ -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/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..e9cb9707d 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
"""
@@ -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/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..69c836396 100644
--- a/plugins/dbms/h2/fingerprint.py
+++ b/plugins/dbms/h2/fingerprint.py
@@ -1,16 +1,20 @@
#!/usr/bin/env python
"""
-Copyright (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 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()
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..506d2675e 100644
--- a/plugins/dbms/maxdb/enumeration.py
+++ b/plugins/dbms/maxdb/enumeration.py
@@ -1,13 +1,14 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
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 = {}
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/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/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/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..c798ce012
--- /dev/null
+++ b/plugins/dbms/monetdb/enumeration.py
@@ -0,0 +1,38 @@
+#!/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 {}
+
+ def getHostname(self):
+ warnMsg = "on MonetDB it is not possible to enumerate the hostname"
+ logger.warn(warnMsg)
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..07eaa609c
--- /dev/null
+++ b/plugins/dbms/monetdb/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 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()
+
+ 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..42e969858
--- /dev/null
+++ b/plugins/dbms/monetdb/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 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))
+
+ return Syntax._escape(expression, quote, escaper)
diff --git a/plugins/dbms/monetdb/takeover.py b/plugins/dbms/monetdb/takeover.py
new file mode 100644
index 000000000..921e01df7
--- /dev/null
+++ b/plugins/dbms/monetdb/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 MonetDB it is not possible to execute commands"
+ raise SqlmapUnsupportedFeatureException(errMsg)
+
+ 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/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..ae2c05a03 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
"""
@@ -89,18 +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"),
+ ("2019", "CHARINDEX('15.0.',@@VERSION)>0"),
+ ("Azure", "@@VERSION LIKE '%Azure%'"),
+ ("2017", "TRIM(NULL) IS NULL"),
("2016", "ISJSON(NULL) IS NULL"),
- ("2017", "TRIM(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()))
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..da83ab735 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
"""
@@ -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
@@ -44,57 +45,64 @@ 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):
+ fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK)
+
+ if fork is None:
+ if inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'"):
+ 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
+ elif inject.checkBooleanExpression("AURORA_VERSION() LIKE '%'"): # Reference: https://aws.amazon.com/premiumsupport/knowledge-center/aurora-version-number/
+ fork = FORK.AURORA
+ else:
+ fork = ""
+
+ hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork)
+
value = ""
wsOsFp = Format.getOs("web server", kb.headersFp)
@@ -110,12 +118,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()
@@ -141,6 +147,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):
@@ -175,15 +184,19 @@ 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)
return False
- if hashDBRetrieve(HASHDB_KEYS.DBMS_FORK) is None:
- hashDBWrite(HASHDB_KEYS.DBMS_FORK, inject.checkBooleanExpression("VERSION() LIKE '%MariaDB%'") and "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/mysql/syntax.py b/plugins/dbms/mysql/syntax.py
index 542e094ef..b9b841828 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
"""
@@ -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)
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 41d5ebb3d..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
"""
@@ -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)
diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py
index f21c6b5ec..c309fc156 100644
--- a/plugins/dbms/postgresql/fingerprint.py
+++ b/plugins/dbms/postgresql/fingerprint.py
@@ -1,16 +1,20 @@
#!/usr/bin/env python
"""
-Copyright (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 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,24 @@ class Fingerprint(GenericFingerprint):
GenericFingerprint.__init__(self, DBMS.PGSQL)
def getFingerprint(self):
+ fork = hashDBRetrieve(HASHDB_KEYS.DBMS_FORK)
+
+ 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
+ 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:
+ fork = ""
+
+ hashDBWrite(HASHDB_KEYS.DBMS_FORK, fork)
+
value = ""
wsOsFp = Format.getOs("web server", kb.headersFp)
@@ -38,6 +60,8 @@ class Fingerprint(GenericFingerprint):
if not conf.extensiveFp:
value += DBMS.PGSQL
+ if fork:
+ value += " (%s fork)" % fork
return value
actVer = Format.getDbms()
@@ -56,6 +80,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):
@@ -75,7 +102,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
@@ -99,7 +127,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"])
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/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/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/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..c72e24982
--- /dev/null
+++ b/plugins/dbms/vertica/fingerprint.py
@@ -0,0 +1,106 @@
+#!/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 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..4337628e4
--- /dev/null
+++ b/plugins/dbms/vertica/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 Vertica it is not possible to execute commands"
+ raise SqlmapUnsupportedFeatureException(errMsg)
+
+ 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/__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 7fb200d30..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
"""
@@ -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:
diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py
index 7f80357b5..e88b957ba 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
"""
@@ -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
@@ -36,17 +37,21 @@ 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
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
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_DBMSES
+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
@@ -76,11 +81,19 @@ 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, 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"
singleTimeWarnMessage(warnMsg)
+ 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"
+ singleTimeWarnMessage(warnMsg)
return kb.data.currentDb
@@ -96,7 +109,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.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"
@@ -104,6 +117,14 @@ class Databases(object):
infoMsg = "fetching database (schema) names"
+ 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"
+ logger.warn(warnMsg)
+
+ infoMsg = "fetching database (user) names"
+
else:
infoMsg = "fetching database names"
@@ -136,7 +157,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:
@@ -203,7 +224,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:
@@ -211,7 +235,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:
@@ -220,7 +244,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 UPPER_CASE_DBMSES:
conf.db = conf.db.upper()
if conf.db:
@@ -251,7 +275,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':
@@ -307,7 +331,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, DBMS.ALTIBASE):
query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper()))
else:
query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table))
@@ -343,7 +367,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)
@@ -364,13 +388,13 @@ 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:
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
@@ -389,7 +413,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, DBMS.ALTIBASE):
query = _.query % (unsafeSQLIdentificatorNaming(db.upper()), unsafeSQLIdentificatorNaming(table.upper()))
else:
query = _.query % (unsafeSQLIdentificatorNaming(db), unsafeSQLIdentificatorNaming(table))
@@ -449,7 +473,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 UPPER_CASE_DBMSES:
conf.db = conf.db.upper()
if ',' in conf.db:
@@ -460,7 +484,7 @@ class Databases(object):
conf.db = safeSQLIdentificatorNaming(conf.db)
if conf.col:
- if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
+ if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
conf.col = conf.col.upper()
colList = conf.col.split(',')
@@ -476,7 +500,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 UPPER_CASE_DBMSES:
conf.tbl = conf.tbl.upper()
tblList = conf.tbl.split(',')
@@ -509,9 +533,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
@@ -542,7 +566,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':
@@ -580,11 +604,14 @@ 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, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID):
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
query += condQuery
- elif Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
+ 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
@@ -660,7 +687,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 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))
@@ -680,6 +707,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:
@@ -722,11 +751,11 @@ 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, DBMS.VERTICA, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID):
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, DBMS.ALTIBASE, DBMS.MIMERSQL):
query = rootQuery.blind.count % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
query += condQuery
@@ -789,7 +818,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, DBMS.PRESTO, DBMS.CRATEDB, DBMS.CUBRID):
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(conf.db))
query += condQuery
field = None
@@ -797,7 +826,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.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
+ 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):
query = rootQuery.blind.query % (unsafeSQLIdentificatorNaming(tbl.upper()), unsafeSQLIdentificatorNaming(conf.db.upper()))
query += condQuery
field = None
@@ -821,7 +857,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 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))
@@ -836,9 +872,9 @@ 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, DBMS.PRESTO, DBMS.CRATEDB):
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, 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])
@@ -846,6 +882,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
@@ -901,7 +939,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():
@@ -921,11 +959,11 @@ 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()
- 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))
@@ -953,7 +991,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)
@@ -982,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)
@@ -1005,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:
@@ -1013,7 +1058,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:
@@ -1029,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/entries.py b/plugins/generic/entries.py
index e54927675..117d9a221 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
"""
@@ -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):
+ 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):
+ if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
conf.tbl = conf.tbl.upper()
tblList = conf.tbl.split(',')
@@ -176,9 +177,9 @@ class Entries(object):
entries = []
query = None
- if Backend.getIdentifiedDbms() in (DBMS.ORACLE, DBMS.DB2):
+ 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):
+ 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
@@ -232,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):
+ 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)
@@ -285,9 +286,9 @@ 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, 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):
+ 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,12 +326,10 @@ 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)
- 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)
@@ -380,7 +379,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:
@@ -405,16 +404,20 @@ 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, 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):
+ 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):
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])
+ else:
+ query = rootQuery.blind.query % (agent.preprocessField(tbl, column), conf.db, tbl, index)
query = agent.whereQuery(query)
diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py
index c8b40728e..affeb3f3e 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
"""
@@ -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)
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..db717f4a4 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
"""
@@ -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):
+ if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
db = db.upper()
infoMsg = "searching database"
@@ -148,7 +149,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':
@@ -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):
+ if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
tbl = tbl.upper()
conf.db = conf.db.upper() if conf.db else conf.db
@@ -344,13 +345,15 @@ 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"
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':
@@ -393,7 +396,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 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
@@ -405,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))
@@ -445,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 []
@@ -537,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)
@@ -558,8 +570,12 @@ 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))
else:
query += " AND %s" % (colQuery + whereTblsQuery)
@@ -602,7 +618,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/syntax.py b/plugins/generic/syntax.py
index fcbaf4adc..f6476382a 100644
--- a/plugins/generic/syntax.py
+++ b/plugins/generic/syntax.py
@@ -1,14 +1,16 @@
#!/usr/bin/env python
"""
-Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
+Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
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):
@@ -26,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:
- 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)
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..1ea627eb1 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
"""
@@ -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
@@ -128,16 +140,19 @@ 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:
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:
@@ -293,7 +308,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:
@@ -441,7 +456,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.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID):
privileges.add(privilege)
# In MySQL < 5.0 we get Y if the privilege is
@@ -541,7 +556,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:
@@ -580,7 +595,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.getIdentifiedDbms() in (DBMS.VERTICA, DBMS.MIMERSQL, DBMS.CUBRID):
privileges.add(privilege)
# In MySQL < 5.0 we get Y if the privilege is
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
diff --git a/sqlmap.py b/sqlmap.py
index e50f57456..118c51178 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
"""
@@ -173,9 +173,12 @@ 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)
+ 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()
else:
from lib.controller.controller import start
if conf.profile and six.PY2:
@@ -255,32 +258,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,10 +278,8 @@ 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
+ elif all(_ in excMsg for _ in ("Permission denied", "metasploit")):
+ errMsg = "permission error occurred while using Metasploit"
logger.critical(errMsg)
raise SystemExit
@@ -373,6 +349,70 @@ def main():
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)
+ 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)
+ 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 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
+
+ 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 "
@@ -380,11 +420,6 @@ def main():
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)
- 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 "")
@@ -392,12 +427,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:
diff --git a/sqlmapapi.py b/sqlmapapi.py
index 28da90369..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
"""
@@ -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
@@ -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")
@@ -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()
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
"""
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
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
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)
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
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/data.json b/thirdparty/identywaf/data.json
old mode 100644
new mode 100755
index de90fdbbe..8bd55c273
--- 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": [
@@ -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..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
@@ -60,7 +60,7 @@ else:
HTTPCookieProcessor = urllib2.HTTPCookieProcessor
NAME = "identYwaf"
-VERSION = "1.0.122"
+VERSION = "1.0.124"
BANNER = r"""
` __ __ `
____ ___ ___ ____ ______ `| T T` __ __ ____ _____
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()
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'