diff --git a/lib/core/agent.py b/lib/core/agent.py index 67222ccc2..efedf2180 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -124,11 +124,8 @@ class Agent(object): if header.upper() == HTTP_HEADER.AUTHORIZATION.upper(): origValue = origValue.split(' ')[-1].split(':')[-1] - if conf.prefix: - value = origValue - if value is None: - if where == PAYLOAD.WHERE.ORIGINAL: + if where == PAYLOAD.WHERE.ORIGINAL or conf.prefix: value = origValue elif where == PAYLOAD.WHERE.NEGATIVE: if conf.invalidLogical: diff --git a/lib/core/common.py b/lib/core/common.py index 1a43aaf1f..60f0b97a8 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -202,7 +202,7 @@ class Format(object): if versions is None and Backend.getVersionList(): versions = Backend.getVersionList() - return Backend.getDbms() if versions is None else "%s %s" % (Backend.getDbms(), " and ".join(v for v in versions)) + return Backend.getDbms() if versions is None else "%s %s" % (Backend.getDbms(), " and ".join(filter(None, versions))) @staticmethod def getErrorParsedDBMSes(): @@ -471,15 +471,17 @@ class Backend: @staticmethod def getVersion(): - if len(kb.dbmsVersion) > 0: - return kb.dbmsVersion[0] + versions = filter(None, flattenValue(kb.dbmsVersion)) + if not isNoneValue(versions): + return versions[0] else: return None @staticmethod def getVersionList(): - if len(kb.dbmsVersion) > 0: - return kb.dbmsVersion + versions = filter(None, flattenValue(kb.dbmsVersion)) + if not isNoneValue(versions): + return versions else: return None diff --git a/lib/core/settings.py b/lib/core/settings.py index 4ded4236a..cf28d47fb 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -563,7 +563,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100 CHECK_ZERO_COLUMNS_THRESHOLD = 10 # Boldify all logger messages containing these "patterns" -BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "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") +BOLD_PATTERNS = ("' injectable", "provided empty", "leftover chars", "might be injectable", "' is vulnerable", "is not injectable", "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") # Generic www root directory names GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "httpdocs", "public", "wwwroot", "www") diff --git a/lib/core/update.py b/lib/core/update.py index 7e0b802a7..3636ba40a 100644 --- a/lib/core/update.py +++ b/lib/core/update.py @@ -13,6 +13,7 @@ from subprocess import PIPE from subprocess import Popen as execute from lib.core.common import dataToStdout +from lib.core.common import getSafeExString from lib.core.common import pollProcess from lib.core.data import conf from lib.core.data import logger @@ -26,9 +27,8 @@ def update(): return success = False - rootDir = paths.SQLMAP_ROOT_PATH - if not os.path.exists(os.path.join(rootDir, ".git")): + if not os.path.exists(os.path.join(paths.SQLMAP_ROOT_PATH, ".git")): errMsg = "not a git repository. Please checkout the 'sqlmapproject/sqlmap' repository " errMsg += "from GitHub (e.g. 'git clone https://github.com/sqlmapproject/sqlmap.git sqlmap')" logger.error(errMsg) @@ -41,10 +41,15 @@ def update(): logger.debug(debugMsg) dataToStdout("\r[%s] [INFO] update in progress " % time.strftime("%X")) - process = execute("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=PIPE, stderr=PIPE) - pollProcess(process, True) - stdout, stderr = process.communicate() - success = not process.returncode + + try: + process = execute("git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=PIPE, stderr=PIPE, cwd=paths.SQLMAP_ROOT_PATH) + pollProcess(process, True) + stdout, stderr = process.communicate() + success = not process.returncode + except (IOError, OSError), ex: + success = False + stderr = getSafeExString(ex) if success: import lib.core.settings diff --git a/lib/parse/payloads.py b/lib/parse/payloads.py index a96867082..89e077098 100644 --- a/lib/parse/payloads.py +++ b/lib/parse/payloads.py @@ -9,6 +9,7 @@ import os from xml.etree import ElementTree as et +from lib.core.common import getSafeExString from lib.core.data import conf from lib.core.data import paths from lib.core.datatype import AttribDict @@ -74,7 +75,7 @@ def loadBoundaries(): doc = et.parse(paths.BOUNDARIES_XML) except Exception, ex: errMsg = "something seems to be wrong with " - errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, ex) + errMsg += "the file '%s' ('%s'). Please make " % (paths.BOUNDARIES_XML, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException, errMsg @@ -92,7 +93,7 @@ def loadPayloads(): doc = et.parse(payloadFilePath) except Exception, ex: errMsg = "something seems to be wrong with " - errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, ex) + errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException, errMsg diff --git a/lib/request/basic.py b/lib/request/basic.py index 1c88d327d..90f21f3f9 100755 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -33,6 +33,7 @@ from lib.core.settings import EVENTVALIDATION_REGEX from lib.core.settings import MAX_CONNECTION_TOTAL_SIZE from lib.core.settings import META_CHARSET_REGEX from lib.core.settings import PARSE_HEADERS_LIMIT +from lib.core.settings import UNICODE_ENCODING from lib.core.settings import VIEWSTATE_REGEX from lib.parse.headers import headersParser from lib.parse.html import htmlParser @@ -197,7 +198,7 @@ def checkCharEncoding(encoding, warn=True): # Reference: http://www.iana.org/assignments/character-sets # Reference: http://docs.python.org/library/codecs.html try: - codecs.lookup(encoding) + codecs.lookup(encoding.encode(UNICODE_ENCODING) if isinstance(encoding, unicode) else encoding) except LookupError: if warn: warnMsg = "unknown web page charset '%s'. " % encoding diff --git a/lib/request/comparison.py b/lib/request/comparison.py index 7028b364f..61f503a68 100644 --- a/lib/request/comparison.py +++ b/lib/request/comparison.py @@ -53,6 +53,8 @@ def _comparison(page, headers, code, getRatioValue, pageLength): if page is None and pageLength is None: return None + count = 0 + seqMatcher = threadData.seqMatcher seqMatcher.set_seq1(kb.pageTemplate) @@ -122,7 +124,6 @@ def _comparison(page, headers, code, getRatioValue, pageLength): seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "") seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "") - count = 0 while count < min(len(seq1), len(seq2)): if seq1[count] == seq2[count]: count += 1 @@ -160,7 +161,7 @@ def _comparison(page, headers, code, getRatioValue, pageLength): # If the url is stable and we did not set yet the match ratio and the # current injected value changes the url page content if kb.matchRatio is None: - if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND: + if (count or ratio >= LOWER_RATIO_BOUND) and ratio <= UPPER_RATIO_BOUND: kb.matchRatio = ratio logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio) diff --git a/lib/request/inject.py b/lib/request/inject.py index ecbf65384..64c5a534c 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -190,7 +190,7 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char countFirstField = queries[Backend.getIdentifiedDbms()].count.query % expressionFieldsList[0] countedExpression = expression.replace(expressionFields, countFirstField, 1) - if " ORDER BY " in expression.upper(): + if " ORDER BY " in countedExpression.upper(): _ = countedExpression.upper().rindex(" ORDER BY ") countedExpression = countedExpression[:_] diff --git a/lib/utils/hashdb.py b/lib/utils/hashdb.py index 555be564b..9b7ea8de3 100644 --- a/lib/utils/hashdb.py +++ b/lib/utils/hashdb.py @@ -69,6 +69,7 @@ class HashDB(object): def retrieve(self, key, unserialize=False): retVal = None + if key and (self._write_cache or os.path.isfile(self.filepath)): hash_ = HashDB.hashKey(key) retVal = self._write_cache.get(hash_) @@ -86,7 +87,16 @@ class HashDB(object): raise SqlmapDataException, errMsg else: break - return retVal if not unserialize else unserializeObject(retVal) + + if unserialize: + try: + retVal = unserializeObject(retVal) + except: + warnMsg = "error occurred while unserializing value for session key '%s'. " % key + warnMsg += "If the problem persists please rerun with `--flush-session`" + logger.warn(warnMsg) + + return retVal def write(self, key, value, serialize=False): if key: diff --git a/xml/payloads/01_boolean_blind.xml b/xml/payloads/01_boolean_blind.xml index 19f2b1ce9..f10f65c9b 100644 --- a/xml/payloads/01_boolean_blind.xml +++ b/xml/payloads/01_boolean_blind.xml @@ -196,7 +196,7 @@ Tag: AND [INFERENCE] AND [RANDNUM]=[RANDNUM] - -- + -- - AND [RANDNUM]=[RANDNUM1] @@ -213,7 +213,7 @@ Tag: OR [INFERENCE] OR [RANDNUM]=[RANDNUM] - -- + -- - OR [RANDNUM]=[RANDNUM1] diff --git a/xml/payloads/06_union_query.xml b/xml/payloads/06_union_query.xml index 7de66f9e1..507bf0845 100644 --- a/xml/payloads/06_union_query.xml +++ b/xml/payloads/06_union_query.xml @@ -12,7 +12,7 @@ [UNION] - -- + -- - [CHAR] [COLSTART]-[COLSTOP] @@ -31,7 +31,7 @@ [UNION] - -- + -- - NULL [COLSTART]-[COLSTOP] @@ -50,7 +50,7 @@ [UNION] - -- + -- - [RANDNUM] [COLSTART]-[COLSTOP] @@ -69,7 +69,7 @@ [UNION] - -- + -- - [CHAR] 1-10 @@ -88,7 +88,7 @@ [UNION] - -- + -- - NULL 1-10 @@ -107,7 +107,7 @@ [UNION] - -- + -- - [RANDNUM] 1-10 @@ -126,7 +126,7 @@ [UNION] - -- + -- - [CHAR] 11-20 @@ -145,7 +145,7 @@ [UNION] - -- + -- - NULL 11-20 @@ -164,7 +164,7 @@ [UNION] - -- + -- - [RANDNUM] 11-20 @@ -183,7 +183,7 @@ [UNION] - -- + -- - [CHAR] 21-30 @@ -202,7 +202,7 @@ [UNION] - -- + -- - NULL 21-30 @@ -221,7 +221,7 @@ [UNION] - -- + -- - [RANDNUM] 21-30 @@ -240,7 +240,7 @@ [UNION] - -- + -- - [CHAR] 31-40 @@ -259,7 +259,7 @@ [UNION] - -- + -- - NULL 31-40 @@ -278,7 +278,7 @@ [UNION] - -- + -- - [RANDNUM] 31-40 @@ -297,7 +297,7 @@ [UNION] - -- + -- - [CHAR] 41-50 @@ -315,7 +315,7 @@ [UNION] - -- + -- - NULL 41-50 @@ -334,7 +334,7 @@ [UNION] - -- + -- - [RANDNUM] 41-50