From f2c2864ab49e393ed10117f2fe6525118da032b6 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 30 Aug 2019 14:43:56 +0200 Subject: [PATCH] Couple of trivial updates --- lib/core/agent.py | 8 +++++--- lib/core/compat.py | 4 ++-- lib/core/enums.py | 4 ++-- lib/core/settings.py | 5 ++++- lib/takeover/metasploit.py | 3 --- lib/techniques/error/use.py | 8 ++++---- lib/techniques/union/test.py | 4 ++-- plugins/dbms/oracle/enumeration.py | 7 ++++--- plugins/generic/users.py | 13 +++++++------ thirdparty/identywaf/__init__.py | 9 +++++++++ 10 files changed, 39 insertions(+), 26 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index 46a332da4..5ad3e7c94 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -334,6 +334,7 @@ class Agent(object): if origValue is not None: origValue = getUnicode(origValue) + if "[ORIGVALUE]" in payload: payload = getUnicode(payload).replace("[ORIGVALUE]", origValue if origValue.isdigit() else unescaper.escape("'%s'" % origValue)) if "[ORIGINAL]" in payload: @@ -352,6 +353,7 @@ class Agent(object): inferenceQuery = inference.query payload = payload.replace(INFERENCE_MARKER, inferenceQuery) + elif not kb.testMode: errMsg = "invalid usage of inference payload without " errMsg += "knowledge of underlying DBMS" @@ -394,7 +396,7 @@ class Agent(object): if "hex" in rootQuery: hexField = rootQuery.hex.query % field else: - warnMsg = "switch '--hex' is currently not supported on DBMS %s" % Backend.getIdentifiedDbms() + warnMsg = "switch '--hex' is currently not supported on DBMS '%s'" % Backend.getIdentifiedDbms() singleTimeWarnMessage(warnMsg) return hexField @@ -1008,7 +1010,7 @@ class Agent(object): limitedQuery = "%s WHERE %s " % (limitedQuery, self.nullAndCastField(uniqueField or field)) limitedQuery += "NOT IN (%s" % (limitStr % num) - limitedQuery += "%s %s ORDER BY %s) ORDER BY %s" % (self.nullAndCastField(uniqueField or field), fromFrom, uniqueField or "1", uniqueField or "1") + limitedQuery += "%s %s ORDER BY %s) ORDER BY %s" % (self.nullAndCastField(uniqueField or field), fromFrom, uniqueField or '1', uniqueField or '1') else: match = re.search(r" ORDER BY (\w+)\Z", query) field = match.group(1) if match else field @@ -1082,7 +1084,7 @@ class Agent(object): Removes payload delimiters from inside the input string """ - return value.replace(PAYLOAD_DELIMITER, '') if value else value + return value.replace(PAYLOAD_DELIMITER, "") if value else value def extractPayload(self, value): """ diff --git a/lib/core/compat.py b/lib/core/compat.py index 4661e92f4..0466e7cc0 100644 --- a/lib/core/compat.py +++ b/lib/core/compat.py @@ -13,6 +13,7 @@ import math import os import random import sys +import time import uuid class WichmannHill(random.Random): @@ -40,7 +41,6 @@ class WichmannHill(random.Random): try: a = int(binascii.hexlify(os.urandom(16)), 16) except NotImplementedError: - import time a = int(time.time() * 256) # use fractional seconds if not isinstance(a, int): @@ -132,7 +132,6 @@ class WichmannHill(random.Random): raise ValueError('seeds must be in range(0, 256)') if 0 == x == y == z: # Initialize from current time - import time t = int(time.time() * 256) t = int((t & 0xffffff) ^ (t >> 24)) t, x = divmod(t, 256) @@ -204,6 +203,7 @@ def round(x, d=0): else: return float(math.ceil((x * p) - 0.5)) / p +# Reference: https://code.activestate.com/recipes/576653-convert-a-cmp-function-to-a-key-function/ def cmp_to_key(mycmp): """Convert a cmp= function into a key= function""" class K(object): diff --git a/lib/core/enums.py b/lib/core/enums.py index 2887a3669..a1264fb35 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -244,8 +244,8 @@ class HASHDB_KEYS(object): OS = "OS" class REDIRECTION(object): - YES = "Y" - NO = "N" + YES = 'Y' + NO = 'N' class PAYLOAD(object): SQLINJECTION = { diff --git a/lib/core/settings.py b/lib/core/settings.py index b69e3307c..dfb4e6411 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -18,7 +18,7 @@ from lib.core.enums import OS from thirdparty.six import unichr as _unichr # sqlmap version (...) -VERSION = "1.3.8.30" +VERSION = "1.3.8.31" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) @@ -333,6 +333,9 @@ BLANK = "" # String representation for current database CURRENT_DB = "CD" +# String representation for current user +CURRENT_USER = "CU" + # Name of SQLite file used for storing session data SESSION_SQLITE_FILE = "session.sqlite" diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index cd22b1606..83762aaca 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -227,18 +227,15 @@ class Metasploit(object): if not choice or choice == "2": _payloadStr = "windows/meterpreter" - break elif choice == "3": _payloadStr = "windows/shell" - break elif choice == "1": if Backend.isDbms(DBMS.PGSQL): logger.warn("beware that the VNC injection might not work") - break elif Backend.isDbms(DBMS.MSSQL) and Backend.isVersionWithin(("2005", "2008")): diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index 7ea434386..478aa86ae 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -76,7 +76,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False): threadData.resumed = retVal is not None and not partialValue - if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode: + if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)) and kb.errorChunkLength is None and not chunkTest and not kb.testMode: debugMsg = "searching for error chunk length..." logger.debug(debugMsg) @@ -117,7 +117,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False): if field: nulledCastedField = agent.nullAndCastField(field) - if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest: + if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)) and not any(_ in field for _ in ("COUNT", "CASE")) and kb.errorChunkLength and not chunkTest: extendedField = re.search(r"[^ ,]*%s[^ ,]*" % re.escape(field), expression).group(0) if extendedField != field: # e.g. MIN(surname) nulledCastedField = extendedField.replace(field, nulledCastedField) @@ -177,7 +177,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False): else: output = output.rstrip() - if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.ORACLE)): + if any(Backend.isDbms(dbms) for dbms in (DBMS.MYSQL, DBMS.MSSQL, DBMS.SYBASE, DBMS.ORACLE)): if offset == 1: retVal = output else: @@ -367,7 +367,7 @@ def errorUse(expression, dump=False): message = "due to huge table size do you want to remove " message += "ORDER BY clause gaining speed over consistency? [y/N] " - if readInput(message, default="N", boolean=True): + if readInput(message, default='N', boolean=True): expression = expression[:expression.index(" ORDER BY ")] numThreads = min(conf.threads, (stopLimit - startLimit)) diff --git a/lib/techniques/union/test.py b/lib/techniques/union/test.py index d195e5f22..5e223575d 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -163,7 +163,7 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= if retVal: infoMsg = "target URL appears to be UNION injectable with %d columns" % retVal - singleTimeLogMessage(infoMsg, logging.INFO, re.sub(r"\d+", "N", infoMsg)) + singleTimeLogMessage(infoMsg, logging.INFO, re.sub(r"\d+", 'N', infoMsg)) return retVal @@ -290,7 +290,7 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix) if not conf.uChar and count > 1 and kb.uChar == NULL: message = "injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] " - if not readInput(message, default="Y", boolean=True): + if not readInput(message, default='Y', boolean=True): warnMsg += "usage of option '--union-char' " warnMsg += "(e.g. '--union-char=1') " else: diff --git a/plugins/dbms/oracle/enumeration.py b/plugins/dbms/oracle/enumeration.py index d31679bec..c79a89758 100644 --- a/plugins/dbms/oracle/enumeration.py +++ b/plugins/dbms/oracle/enumeration.py @@ -21,6 +21,7 @@ from lib.core.enums import DBMS from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException +from lib.core.settings import CURRENT_USER from lib.request import inject from plugins.generic.enumeration import Enumeration as GenericEnumeration @@ -30,7 +31,7 @@ class Enumeration(GenericEnumeration): rootQuery = queries[DBMS.ORACLE].roles - if conf.user == "CU": + if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() @@ -55,7 +56,7 @@ class Enumeration(GenericEnumeration): values = inject.getValue(query, blind=False, time=False) if not values and not query2: - infoMsg = "trying with table USER_ROLE_PRIVS" + infoMsg = "trying with table 'USER_ROLE_PRIVS'" logger.info(infoMsg) return self.getRoles(query2=True) @@ -116,7 +117,7 @@ class Enumeration(GenericEnumeration): if not isNumPosStrValue(count): if count != 0 and not query2: - infoMsg = "trying with table USER_SYS_PRIVS" + infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) diff --git a/plugins/generic/users.py b/plugins/generic/users.py index a20707d21..5599404aa 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -39,6 +39,7 @@ from lib.core.enums import EXPECTED from lib.core.enums import PAYLOAD from lib.core.exception import SqlmapNoneDataException from lib.core.exception import SqlmapUserQuitException +from lib.core.settings import CURRENT_USER from lib.core.threads import getCurrentThreadData from lib.request import inject from lib.utils.hash import attackCachedUsersPasswords @@ -153,7 +154,7 @@ class Users(object): rootQuery = queries[Backend.getIdentifiedDbms()].passwords - if conf.user == "CU": + if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() @@ -362,7 +363,7 @@ class Users(object): rootQuery = queries[Backend.getIdentifiedDbms()].privileges - if conf.user == "CU": + if conf.user == CURRENT_USER: infoMsg += " for current user" conf.user = self.getCurrentUser() @@ -410,7 +411,7 @@ class Users(object): values = inject.getValue(query, blind=False, time=False) if not values and Backend.isDbms(DBMS.ORACLE) and not query2: - infoMsg = "trying with table USER_SYS_PRIVS" + infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) @@ -446,7 +447,7 @@ class Users(object): # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise elif Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema: - if privilege.upper() == "Y": + if privilege.upper() == 'Y': privileges.add(MYSQL_PRIVS[count]) # In Firebird we get one letter for each privilege @@ -465,7 +466,7 @@ class Users(object): i = 1 for priv in privs: - if priv.upper() in ("Y", "G"): + if priv.upper() in ('Y', 'G'): for position, db2Priv in DB2_PRIVS.items(): if position == i: privilege += ", " + db2Priv @@ -525,7 +526,7 @@ class Users(object): if not isNumPosStrValue(count): if not retrievedUsers and Backend.isDbms(DBMS.ORACLE) and not query2: - infoMsg = "trying with table USER_SYS_PRIVS" + infoMsg = "trying with table 'USER_SYS_PRIVS'" logger.info(infoMsg) return self.getPrivileges(query2=True) diff --git a/thirdparty/identywaf/__init__.py b/thirdparty/identywaf/__init__.py index e69de29bb..aa130ea22 100644 --- a/thirdparty/identywaf/__init__.py +++ b/thirdparty/identywaf/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 Miroslav Stampar (@stamparm), MIT +# See the file 'LICENSE' for copying permission + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +pass