diff --git a/README.md b/README.md index 3329bbef4..23c88ea23 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ To get a list of all options and switches use: python sqlmap.py -hh -You can find a sample run [here](https://gist.github.com/stamparm/5335217). +You can find a sample run [here](https://asciinema.org/a/46601). To get an overview of sqlmap capabilities, list of supported features and description of all options and switches, along with examples, you are advised to consult the [user's manual](https://github.com/sqlmapproject/sqlmap/wiki). Links diff --git a/doc/translations/README-es-MX.md b/doc/translations/README-es-MX.md index 32ca795a6..b4080d802 100644 --- a/doc/translations/README-es-MX.md +++ b/doc/translations/README-es-MX.md @@ -32,7 +32,7 @@ Para obtener una lista de todas las opciones: python sqlmap.py -hh -Se puede encontrar una muestra de su funcionamiento [aquí](https://gist.github.com/stamparm/5335217). +Se puede encontrar una muestra de su funcionamiento [aquí](https://asciinema.org/a/46601). Para obtener una visión general de las capacidades de sqlmap, así como un listado funciones soportadas y descripción de todas las opciones y modificadores, junto con ejemplos, se recomienda consultar el [manual de usuario](https://github.com/sqlmapproject/sqlmap/wiki). Enlaces diff --git a/doc/translations/README-gr-GR.md b/doc/translations/README-gr-GR.md index bb7b5a469..20cc379d5 100644 --- a/doc/translations/README-gr-GR.md +++ b/doc/translations/README-gr-GR.md @@ -33,7 +33,7 @@ python sqlmap.py -hh -Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://gist.github.com/stamparm/5335217). +Μπορείτε να δείτε ένα δείγμα λειτουργίας του προγράμματος [εδώ](https://asciinema.org/a/46601). Για μια γενικότερη άποψη των δυνατοτήτων του sqlmap, μια λίστα των υποστηριζόμενων χαρακτηριστικών και περιγραφή για όλες τις επιλογές, μαζί με παραδείγματα, καλείστε να συμβουλευτείτε το [εγχειρίδιο χρήστη](https://github.com/sqlmapproject/sqlmap/wiki). Σύνδεσμοι diff --git a/doc/translations/README-hr-HR.md b/doc/translations/README-hr-HR.md index f603389b8..16a0bc9c8 100644 --- a/doc/translations/README-hr-HR.md +++ b/doc/translations/README-hr-HR.md @@ -33,7 +33,7 @@ Kako biste dobili listu svih opcija i prekidača koristite: python sqlmap.py -hh -Možete pronaći primjer izvršavanja [ovdje](https://gist.github.com/stamparm/5335217). +Možete pronaći primjer izvršavanja [ovdje](https://asciinema.org/a/46601). Kako biste dobili pregled mogućnosti sqlmap-a, liste podržanih značajki te opis svih opcija i prekidača, zajedno s primjerima, preporučen je uvid u [korisnički priručnik](https://github.com/sqlmapproject/sqlmap/wiki). Poveznice diff --git a/doc/translations/README-id-ID.md b/doc/translations/README-id-ID.md index 801137598..bb0c76e3f 100644 --- a/doc/translations/README-id-ID.md +++ b/doc/translations/README-id-ID.md @@ -34,7 +34,7 @@ Untuk mendapatkan daftar opsi lanjut gunakan: python sqlmap.py -hh -Anda dapat mendapatkan contoh penggunaan [di sini](https://gist.github.com/stamparm/5335217). +Anda dapat mendapatkan contoh penggunaan [di sini](https://asciinema.org/a/46601). Untuk mendapatkan gambaran singkat kemampuan sqlmap, daftar fitur yang didukung, deskripsi dari semua opsi, berikut dengan contohnya, Anda disarankan untuk membaca [manual pengguna](https://github.com/sqlmapproject/sqlmap/wiki). Tautan diff --git a/doc/translations/README-pt-BR.md b/doc/translations/README-pt-BR.md index 6c86c308c..129d50430 100644 --- a/doc/translations/README-pt-BR.md +++ b/doc/translations/README-pt-BR.md @@ -34,7 +34,7 @@ Para obter a lista completa de opções faça: python sqlmap.py -hh -Você pode encontrar alguns exemplos [aqui](https://gist.github.com/stamparm/5335217). +Você pode encontrar alguns exemplos [aqui](https://asciinema.org/a/46601). Para ter uma visão geral dos recursos do sqlmap, lista de recursos suportados e a descrição de todas as opções, juntamente com exemplos, aconselhamos que você consulte o [manual do usuário](https://github.com/sqlmapproject/sqlmap/wiki). Links diff --git a/doc/translations/README-tr-TR.md b/doc/translations/README-tr-TR.md index d6b9cbc92..11ad220f6 100644 --- a/doc/translations/README-tr-TR.md +++ b/doc/translations/README-tr-TR.md @@ -37,7 +37,7 @@ Bütün seçenekleri gösterir python sqlmap.py -hh -Program ile ilgili örnekleri [burada](https://gist.github.com/stamparm/5335217) bulabilirsiniz. Daha fazlası içinsqlmap'in bütün açıklamaları ile birlikte bütün özelliklerinin, örnekleri ile bulunduğu [manuel sayfamıza](https://github.com/sqlmapproject/sqlmap/wiki) bakmanızı tavsiye ediyoruz +Program ile ilgili örnekleri [burada](https://asciinema.org/a/46601) bulabilirsiniz. Daha fazlası içinsqlmap'in bütün açıklamaları ile birlikte bütün özelliklerinin, örnekleri ile bulunduğu [manuel sayfamıza](https://github.com/sqlmapproject/sqlmap/wiki) bakmanızı tavsiye ediyoruz Links ---- diff --git a/doc/translations/README-zh-CN.md b/doc/translations/README-zh-CN.md index 6aea35f7e..293e5d4f9 100644 --- a/doc/translations/README-zh-CN.md +++ b/doc/translations/README-zh-CN.md @@ -33,7 +33,7 @@ sqlmap 可以运行在 [Python](http://www.python.org/download/) **2.6.x** 和 python sqlmap.py -hh -你可以从 [这里](https://gist.github.com/stamparm/5335217) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。 +你可以从 [这里](https://asciinema.org/a/46601) 看到一个sqlmap 的使用样例。除此以外,你还可以查看 [使用手册](https://github.com/sqlmapproject/sqlmap/wiki)。获取sqlmap所有支持的特性、参数、命令行选项开关及说明的使用帮助。 链接 ---- diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 9f3e9a02a..a9a41dfe4 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -98,6 +98,9 @@ def checkSqlInjection(place, parameter, value): tests = getSortedInjectionTests() seenPayload = set() + kb.data.setdefault("randomInt", str(randomInt(10))) + kb.data.setdefault("randomStr", str(randomStr(10))) + while tests: test = tests.pop(0) @@ -174,10 +177,11 @@ def checkSqlInjection(place, parameter, value): lower, upper = int(match.group(1)), int(match.group(2)) for _ in (lower, upper): if _ > 1: + __ = 2 * (_ - 1) + 1 if _ == lower else 2 * _ unionExtended = True - test.request.columns = re.sub(r"\b%d\b" % _, str(2 * _), test.request.columns) - title = re.sub(r"\b%d\b" % _, str(2 * _), title) - test.title = re.sub(r"\b%d\b" % _, str(2 * _), test.title) + test.request.columns = re.sub(r"\b%d\b" % _, str(__), test.request.columns) + title = re.sub(r"\b%d\b" % _, str(__), title) + test.title = re.sub(r"\b%d\b" % _, str(__), test.title) # Skip test if the user's wants to test only for a specific # technique @@ -381,8 +385,6 @@ def checkSqlInjection(place, parameter, value): # Use different page template than the original # one as we are changing parameters value, which # will likely result in a different content - kb.data.setdefault("randomInt", str(randomInt(10))) - kb.data.setdefault("randomStr", str(randomStr(10))) if conf.invalidLogical: _ = int(kb.data.randomInt[:2]) @@ -462,19 +464,28 @@ def checkSqlInjection(place, parameter, value): if errorResult: continue - infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (paramType, parameter, title) + infoMsg = "%s parameter '%s' appears to be '%s' injectable " % (paramType, parameter, title) logger.info(infoMsg) injectable = True if not injectable and not any((conf.string, conf.notString, conf.regexp)) and kb.pageStable: trueSet = set(extractTextTagContent(truePage)) + trueSet = trueSet.union(__ for _ in trueSet for __ in _.split()) + falseSet = set(extractTextTagContent(falsePage)) + falseSet = falseSet.union(__ for _ in falseSet for __ in _.split()) + candidates = filter(None, (_.strip() if _.strip() in (kb.pageTemplate or "") and _.strip() not in falsePage and _.strip() not in threadData.lastComparisonHeaders else None for _ in (trueSet - falseSet))) if candidates: - conf.string = candidates[0] - infoMsg = "%s parameter '%s' seems to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'")) + candidates = sorted(candidates, key=lambda _: len(_)) + for candidate in candidates: + if re.match(r"\A\w+\Z", candidate): + break + conf.string = candidate + + infoMsg = "%s parameter '%s' appears to be '%s' injectable (with --string=\"%s\")" % (paramType, parameter, title, repr(conf.string).lstrip('u').strip("'")) logger.info(infoMsg) injectable = True @@ -519,7 +530,7 @@ def checkSqlInjection(place, parameter, value): trueResult = Request.queryPage(reqPayload, place, timeBasedCompare=True, raise404=False) if trueResult: - infoMsg = "%s parameter '%s' seems to be '%s' injectable " % (paramType, parameter, title) + infoMsg = "%s parameter '%s' appears to be '%s' injectable " % (paramType, parameter, title) logger.info(infoMsg) injectable = True @@ -692,14 +703,15 @@ def checkSqlInjection(place, parameter, value): # Return the injection object if injection.place is not None and injection.parameter is not None: if not conf.dropSetCookie and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data and injection.data[PAYLOAD.TECHNIQUE.BOOLEAN].vector.startswith('OR'): - warnMsg = "in OR boolean-based injections, please consider usage " + warnMsg = "in OR boolean-based injection cases, please consider usage " warnMsg += "of switch '--drop-set-cookie' if you experience any " warnMsg += "problems during data retrieval" logger.warn(warnMsg) if not checkFalsePositives(injection): kb.vulnHosts.remove(conf.hostname) - injection.notes.add(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE) + if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection.notes: + injection.notes.append(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE) else: injection = None @@ -1288,7 +1300,7 @@ def identifyWaf(): if output and output[0] not in ("Y", "y"): raise SqlmapUserQuitException else: - warnMsg = "no WAF/IDS/IPS product has been identified (this doesn't mean that there is none)" + warnMsg = "WAF/IDS/IPS product hasn't been identified (generic protection response)" logger.warn(warnMsg) kb.testType = None diff --git a/lib/controller/controller.py b/lib/controller/controller.py index f93f7811b..24f702f15 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -226,15 +226,15 @@ def _saveToResultsFile(): results = {} techniques = dict(map(lambda x: (x[1], x[0]), getPublicTypeMembers(PAYLOAD.TECHNIQUE))) - for inj in kb.injections + kb.falsePositives: - if inj.place is None or inj.parameter is None: + for injection in kb.injections + kb.falsePositives: + if injection.place is None or injection.parameter is None: continue - key = (inj.place, inj.parameter, ';'.join(inj.notes)) + key = (injection.place, injection.parameter, ';'.join(injection.notes)) if key not in results: results[key] = [] - results[key].extend(inj.data.keys()) + results[key].extend(injection.data.keys()) for key, value in results.items(): place, parameter, notes = key diff --git a/lib/core/agent.py b/lib/core/agent.py index ab97cf07a..5119d58c6 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -102,7 +102,7 @@ class Agent(object): if place == PLACE.URI: origValue = origValue.split(CUSTOM_INJECTION_MARK_CHAR)[0] else: - origValue = re.search(r"\w+\Z", origValue.split(BOUNDED_INJECTION_MARKER)[0]).group(0) + origValue = filter(None, (re.search(_, origValue.split(BOUNDED_INJECTION_MARKER)[0]) for _ in (r"\w+\Z", r"[^\"'><]+\Z", r"[^ ]+\Z")))[0].group(0) origValue = origValue[origValue.rfind('/') + 1:] for char in ('?', '=', ':'): if char in origValue: diff --git a/lib/core/common.py b/lib/core/common.py index 0b78274e0..11bf1e42e 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -304,7 +304,7 @@ class Backend: # Little precaution, in theory this condition should always be false elif kb.dbms is not None and kb.dbms != dbms: - warnMsg = "there seems to be a high probability that " + warnMsg = "there appears to be a high probability that " warnMsg += "this could be a false positive case" logger.warn(warnMsg) @@ -581,7 +581,7 @@ def paramToDict(place, parameters=None): if not conf.multipleTargets and not (conf.csrfToken and parameter == conf.csrfToken): _ = urldecode(testableParameters[parameter], convall=True) if (_.endswith("'") and _.count("'") == 1 - or re.search(r'\A9{3,}', _) or re.search(DUMMY_USER_INJECTION, _))\ + or re.search(r'\A9{3,}', _) or re.search(r'\A-\d+\Z', _) or re.search(DUMMY_USER_INJECTION, _))\ and not parameter.upper().startswith(GOOGLE_ANALYTICS_COOKIE_PREFIX): warnMsg = "it appears that you have provided tainted parameter values " warnMsg += "('%s') with most probably leftover " % element @@ -650,27 +650,28 @@ def paramToDict(place, parameters=None): testableParameters[parameter] = re.sub(regex, "\g<1>%s\g<2>" % BOUNDED_INJECTION_MARKER, testableParameters[parameter]) break - if conf.testParameter and not testableParameters: - paramStr = ", ".join(test for test in conf.testParameter) + if conf.testParameter: + if not testableParameters: + paramStr = ", ".join(test for test in conf.testParameter) - if len(conf.testParameter) > 1: - warnMsg = "provided parameters '%s' " % paramStr - warnMsg += "are not inside the %s" % place - logger.warn(warnMsg) - else: - parameter = conf.testParameter[0] + if len(conf.testParameter) > 1: + warnMsg = "provided parameters '%s' " % paramStr + warnMsg += "are not inside the %s" % place + logger.warn(warnMsg) + else: + parameter = conf.testParameter[0] - if not intersect(USER_AGENT_ALIASES + REFERER_ALIASES + HOST_ALIASES, parameter, True): - debugMsg = "provided parameter '%s' " % paramStr - debugMsg += "is not inside the %s" % place - logger.debug(debugMsg) + if not intersect(USER_AGENT_ALIASES + REFERER_ALIASES + HOST_ALIASES, parameter, True): + debugMsg = "provided parameter '%s' " % paramStr + debugMsg += "is not inside the %s" % place + logger.debug(debugMsg) - elif len(conf.testParameter) != len(testableParameters.keys()): - for parameter in conf.testParameter: - if parameter not in testableParameters: - debugMsg = "provided parameter '%s' " % parameter - debugMsg += "is not inside the %s" % place - logger.debug(debugMsg) + elif len(conf.testParameter) != len(testableParameters.keys()): + for parameter in conf.testParameter: + if parameter not in testableParameters: + debugMsg = "provided parameter '%s' " % parameter + debugMsg += "is not inside the %s" % place + logger.debug(debugMsg) if testableParameters: for parameter, value in testableParameters.items(): @@ -680,7 +681,7 @@ def paramToDict(place, parameters=None): decoded = value.decode(encoding) if len(decoded) > MIN_ENCODED_LEN_CHECK and all(_ in string.printable for _ in decoded): warnMsg = "provided parameter '%s' " % parameter - warnMsg += "seems to be '%s' encoded" % encoding + warnMsg += "appears to be '%s' encoded" % encoding logger.warn(warnMsg) break except: @@ -767,9 +768,14 @@ def getManualDirectories(): for suffix in BRUTE_DOC_ROOT_SUFFIXES: for target in targets: - item = "%s/%s" % (prefix, suffix) + if not prefix.endswith("/%s" % suffix): + item = "%s/%s" % (prefix, suffix) + else: + item = prefix + item = item.replace(BRUTE_DOC_ROOT_TARGET_MARK, target).replace("//", '/').rstrip('/') - directories.append(item) + if item not in directories: + directories.append(item) if BRUTE_DOC_ROOT_TARGET_MARK not in prefix: break @@ -1374,8 +1380,8 @@ def parseTargetUrl(): except UnicodeError: _ = None - if any((_ is None, re.search(r'\s', conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'))): - errMsg = "invalid target URL" + if any((_ is None, re.search(r'\s', conf.hostname), '..' in conf.hostname, conf.hostname.startswith('.'), '\n' in originalUrl)): + errMsg = "invalid target URL ('%s')" % originalUrl raise SqlmapSyntaxException(errMsg) if len(hostnamePort) == 2: @@ -1903,7 +1909,7 @@ def parseXmlFile(xmlFile, handler): with contextlib.closing(StringIO(readCachedFileContent(xmlFile))) as stream: parse(stream, handler) except (SAXParseException, UnicodeError), ex: - errMsg = "something seems to be wrong with " + errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (xmlFile, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException, errMsg @@ -2858,7 +2864,7 @@ def setOptimize(): conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor)) if not conf.nullConnection: - debugMsg = "turning off --null-connection switch used indirectly by switch -o" + debugMsg = "turning off switch '--null-connection' used indirectly by switch '-o'" logger.debug(debugMsg) def initTechnique(technique=None): @@ -3046,7 +3052,10 @@ def decodeIntToUnicode(value): _ = "0%s" % _ raw = hexdecode(_) - if Backend.isDbms(DBMS.MSSQL): + if Backend.isDbms(DBMS.MYSQL): + # https://github.com/sqlmapproject/sqlmap/issues/1531 + retVal = getUnicode(raw, conf.charset or UNICODE_ENCODING) + elif Backend.isDbms(DBMS.MSSQL): retVal = getUnicode(raw, "UTF-16-BE") elif Backend.getIdentifiedDbms() in (DBMS.PGSQL, DBMS.ORACLE): retVal = unichr(value) diff --git a/lib/core/datatype.py b/lib/core/datatype.py index b3df3dae0..cd3e0bb77 100644 --- a/lib/core/datatype.py +++ b/lib/core/datatype.py @@ -8,8 +8,6 @@ See the file 'doc/COPYING' for copying permission import copy import types -from lib.core.exception import SqlmapDataException - class AttribDict(dict): """ This class defines the sqlmap object, inheriting from Python data @@ -43,7 +41,7 @@ class AttribDict(dict): try: return self.__getitem__(item) except KeyError: - raise SqlmapDataException("unable to access item '%s'" % item) + raise AttributeError("unable to access item '%s'" % item) def __setattr__(self, item, value): """ @@ -93,7 +91,7 @@ class InjectionDict(AttribDict): self.prefix = None self.suffix = None self.clause = None - self.notes = set() + self.notes = [] # Note: https://github.com/sqlmapproject/sqlmap/issues/1888 # data is a dict with various stype, each which is a dict with # all the information specific for that stype diff --git a/lib/core/dicts.py b/lib/core/dicts.py index b896ed81d..d2e4e234f 100644 --- a/lib/core/dicts.py +++ b/lib/core/dicts.py @@ -234,6 +234,6 @@ DUMP_DATA_PREPROCESS = { } DEFAULT_DOC_ROOTS = { - OS.WINDOWS: ("C:/xampp/htdocs/", "C:/Inetpub/wwwroot/"), - OS.LINUX: ("/var/www/", "/var/www/html", "/usr/local/apache2/htdocs", "/var/www/nginx-default") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout + OS.WINDOWS: ("C:/xampp/htdocs/", "C:/wamp/www/", "C:/Inetpub/wwwroot/"), + OS.LINUX: ("/var/www/", "/var/www/html", "/usr/local/apache2/htdocs", "/var/www/nginx-default", "/srv/www") # Reference: https://wiki.apache.org/httpd/DistrosDefaultLayout } diff --git a/lib/core/option.py b/lib/core/option.py index 42404a264..2dd8daf70 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -385,7 +385,7 @@ def _loadQueries(): try: tree.parse(paths.QUERIES_XML) except Exception, ex: - errMsg = "something seems to be wrong with " + errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (paths.QUERIES_XML, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException, errMsg @@ -926,7 +926,7 @@ def _setTamperingFunctions(): function.func_name = module.__name__ if check_priority and priority > last_priority: - message = "it seems that you might have mixed " + message = "it appears that you might have mixed " message += "the order of tamper scripts. " message += "Do you want to auto resolve this? [Y/n/q] " test = readInput(message, default="Y") @@ -2310,7 +2310,7 @@ def _checkTor(): page = None if not page or 'Congratulations' not in page: - errMsg = "it seems that Tor is not properly set. Please try using options '--tor-type' and/or '--tor-port'" + errMsg = "it appears that Tor is not properly set. Please try using options '--tor-type' and/or '--tor-port'" raise SqlmapConnectionException(errMsg) else: infoMsg = "Tor is properly being used" diff --git a/lib/core/settings.py b/lib/core/settings.py index e3172f864..1bfb58dac 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from lib.core.enums import OS from lib.core.revision import getRevisionNumber # sqlmap version (...) -VERSION = "1.0.5.36" +VERSION = "1.0.5.63" REVISION = getRevisionNumber() STABLE = VERSION.count('.') <= 2 VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev") @@ -533,7 +533,7 @@ HASHDB_FLUSH_RETRIES = 3 HASHDB_END_TRANSACTION_RETRIES = 3 # Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism) -HASHDB_MILESTONE_VALUE = "zYwqRDymvj" # "".join(random.sample(string.ascii_letters, 10)) +HASHDB_MILESTONE_VALUE = "ERqvmQHalF" # "".join(random.sample(string.ascii_letters, 10)) # Warn user of possible delay due to large page dump in full UNION query injections LARGE_OUTPUT_THRESHOLD = 1024 ** 2 @@ -680,7 +680,7 @@ BRUTE_DOC_ROOT_PREFIXES = { } # Suffixes used in brute force search for web server document root -BRUTE_DOC_ROOT_SUFFIXES = ("", "html", "htdocs", "httpdocs", "php", "public", "src", "site", "build", "web", "data", "sites/all", "www/build") +BRUTE_DOC_ROOT_SUFFIXES = ("", "html", "htdocs", "httpdocs", "php", "public", "src", "site", "build", "web", "www", "data", "sites/all", "www/build") # String used for marking target name inside used brute force web server document root BRUTE_DOC_ROOT_TARGET_MARK = "%TARGET%" diff --git a/lib/core/target.py b/lib/core/target.py index 0208aaf10..94fdf4f2e 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -214,9 +214,9 @@ def _setRequestParams(): if re.search(URI_INJECTABLE_REGEX, conf.url, re.I) and not any(place in conf.parameters for place in (PLACE.GET, PLACE.POST)) and not kb.postHint and not CUSTOM_INJECTION_MARK_CHAR in (conf.data or "") and conf.url.startswith("http"): warnMsg = "you've provided target URL without any GET " - warnMsg += "parameters (e.g. www.site.com/article.php?id=1) " + warnMsg += "parameters (e.g. 'http://www.site.com/article.php?id=1') " warnMsg += "and without providing any POST parameters " - warnMsg += "through --data option" + warnMsg += "through option '--data'" logger.warn(warnMsg) message = "do you want to try URI injections " diff --git a/lib/core/wordlist.py b/lib/core/wordlist.py index 2ba368777..ba375530e 100644 --- a/lib/core/wordlist.py +++ b/lib/core/wordlist.py @@ -44,7 +44,7 @@ class Wordlist(object): try: _ = zipfile.ZipFile(self.current, 'r') except zipfile.error, ex: - errMsg = "something seems to be wrong with " + errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException, errMsg @@ -70,7 +70,7 @@ class Wordlist(object): try: retVal = self.iter.next().rstrip() except zipfile.error, ex: - errMsg = "something seems to be wrong with " + errMsg = "something appears to be wrong with " errMsg += "the file '%s' ('%s'). Please make " % (self.current, getSafeExString(ex)) errMsg += "sure that you haven't made any changes to it" raise SqlmapInstallationException, errMsg diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index 98dd87db9..7f59f593d 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -806,12 +806,12 @@ def cmdLineParser(argv=None): parser.formatter._format_option_strings = parser.formatter.format_option_strings parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser, type(parser)) - # Dirty hack for making a short option -hh + # Dirty hack for making a short option '-hh' option = parser.get_option("--hh") option._short_opts = ["-hh"] option._long_opts = [] - # Dirty hack for inherent help message of switch -h + # Dirty hack for inherent help message of switch '-h' option = parser.get_option("-h") option.help = option.help.capitalize().replace("this help", "basic help") diff --git a/lib/parse/payloads.py b/lib/parse/payloads.py index a453d7d6d..4bf294e2f 100644 --- a/lib/parse/payloads.py +++ b/lib/parse/payloads.py @@ -74,7 +74,7 @@ def loadBoundaries(): try: doc = et.parse(paths.BOUNDARIES_XML) except Exception, ex: - errMsg = "something seems to be wrong with " + errMsg = "something appears to be wrong with " 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 +92,7 @@ def loadPayloads(): try: doc = et.parse(payloadFilePath) except Exception, ex: - errMsg = "something seems to be wrong with " + errMsg = "something appears to be wrong with " 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/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index accd6d134..8368867fb 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -111,8 +111,8 @@ class Xp_cmdshell: errMsg += "storing console output within the back-end file system " errMsg += "does not have writing permissions for the DBMS process. " errMsg += "You are advised to manually adjust it with option " - errMsg += "--tmp-path switch or you will not be able to retrieve " - errMsg += "the commands output" + errMsg += "'--tmp-path' or you won't be able to retrieve " + errMsg += "the command(s) output" logger.error(errMsg) elif isNoneValue(output): logger.error("unable to retrieve xp_cmdshell output") diff --git a/lib/techniques/union/test.py b/lib/techniques/union/test.py index 2374d2d2e..a2398ef45 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -53,10 +53,10 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where= query = agent.suffixQuery(query, suffix=suffix, comment=comment) payload = agent.payload(newValue=query, place=place, parameter=parameter, where=where) page, headers = Request.queryPage(payload, place=place, content=True, raise404=False) - return not re.search(r"(warning|error|order by|failed)", page or "", re.I) and comparison(page, headers) or re.search(r"data types cannot be compared or sorted", page or "", re.I) + return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order by", "unknown column", "failed")) and comparison(page, headers) or re.search(r"data types cannot be compared or sorted", page or "", re.I) if _orderByTest(1) and not _orderByTest(randomInt()): - infoMsg = "ORDER BY technique seems to be usable. " + infoMsg = "ORDER BY technique appears to be usable. " infoMsg += "This should reduce the time needed " infoMsg += "to find the right number " infoMsg += "of query columns. Automatically extending the " diff --git a/lib/utils/pivotdumptable.py b/lib/utils/pivotdumptable.py index a511000e5..a8447ddfa 100644 --- a/lib/utils/pivotdumptable.py +++ b/lib/utils/pivotdumptable.py @@ -134,10 +134,13 @@ def pivotDumpTable(table, colList, count=None, blind=True): value = _(column, pivotValue) if column == colList[0]: if isNoneValue(value): - for pivotValue in filter(None, (" " if pivotValue == " " else None, "%s%s" % (pivotValue[0], unichr(ord(pivotValue[1]) + 1)) if len(pivotValue) > 1 else None, unichr(ord(pivotValue[0]) + 1))): - value = _(column, pivotValue) - if not isNoneValue(value): - break + try: + for pivotValue in filter(None, (" " if pivotValue == " " else None, "%s%s" % (pivotValue[0], unichr(ord(pivotValue[1]) + 1)) if len(pivotValue) > 1 else None, unichr(ord(pivotValue[0]) + 1))): + value = _(column, pivotValue) + if not isNoneValue(value): + break + except ValueError: + pass if isNoneValue(value): breakRetrieval = True diff --git a/plugins/dbms/mssqlserver/connector.py b/plugins/dbms/mssqlserver/connector.py index 89e8847e6..bf569736c 100644 --- a/plugins/dbms/mssqlserver/connector.py +++ b/plugins/dbms/mssqlserver/connector.py @@ -41,7 +41,7 @@ class Connector(GenericConnector): try: self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout) - except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg: + except (pymssql.Error, _mssql.MssqlDatabaseException), msg: raise SqlmapConnectionException(msg) self.initCursor() @@ -50,7 +50,7 @@ class Connector(GenericConnector): def fetchall(self): try: return self.cursor.fetchall() - except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg: + except (pymssql.Error, _mssql.MssqlDatabaseException), msg: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % str(msg).replace("\n", " ")) return None diff --git a/plugins/dbms/sybase/connector.py b/plugins/dbms/sybase/connector.py index 89e8847e6..bf569736c 100644 --- a/plugins/dbms/sybase/connector.py +++ b/plugins/dbms/sybase/connector.py @@ -41,7 +41,7 @@ class Connector(GenericConnector): try: self.connector = pymssql.connect(host="%s:%d" % (self.hostname, self.port), user=self.user, password=self.password, database=self.db, login_timeout=conf.timeout, timeout=conf.timeout) - except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg: + except (pymssql.Error, _mssql.MssqlDatabaseException), msg: raise SqlmapConnectionException(msg) self.initCursor() @@ -50,7 +50,7 @@ class Connector(GenericConnector): def fetchall(self): try: return self.cursor.fetchall() - except (pymssql.ProgrammingError, pymssql.OperationalError, _mssql.MssqlDatabaseException), msg: + except (pymssql.Error, _mssql.MssqlDatabaseException), msg: logger.log(logging.WARN if conf.dbmsHandler else logging.DEBUG, "(remote) %s" % str(msg).replace("\n", " ")) return None diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index 31ad6f470..585442da1 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -19,9 +19,7 @@ from lib.core.common import isListLike from lib.core.common import isNoneValue from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable -from lib.core.common import popValue from lib.core.common import prioritySortColumns -from lib.core.common import pushValue from lib.core.common import readInput from lib.core.common import safeSQLIdentificatorNaming from lib.core.common import unArrayizeValue diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index d90a8fdfc..2dc5a4565 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -87,7 +87,7 @@ class Filesystem: else: sameFile = False warnMsg = "it looks like the file has not been written (usually " - warnMsg += "occurs if the DBMS process' user has no write " + warnMsg += "occurs if the DBMS process user has no write " warnMsg += "privileges in the destination path)" logger.warn(warnMsg) diff --git a/xml/payloads/04_stacked_queries.xml b/xml/payloads/04_stacked_queries.xml index 804b92cc6..d156d693d 100644 --- a/xml/payloads/04_stacked_queries.xml +++ b/xml/payloads/04_stacked_queries.xml @@ -3,7 +3,7 @@ - MySQL > 5.0.11 stacked queries (SELECT - comment) + MySQL > 5.0.11 stacked queries (SLEEP - comment) 4 1 1 @@ -24,7 +24,7 @@ - MySQL > 5.0.11 stacked queries (SELECT) + MySQL > 5.0.11 stacked queries (SLEEP) 4 2 1 diff --git a/xml/payloads/05_time_blind.xml b/xml/payloads/05_time_blind.xml index bc8e5a3bd..4f8223f24 100644 --- a/xml/payloads/05_time_blind.xml +++ b/xml/payloads/05_time_blind.xml @@ -3,7 +3,7 @@ - MySQL >= 5.0.12 AND time-based blind (SELECT) + MySQL >= 5.0.12 AND time-based blind (SLEEP) 5 1 1 @@ -23,7 +23,7 @@ - MySQL >= 5.0.12 OR time-based blind (SELECT) + MySQL >= 5.0.12 OR time-based blind (SLEEP) 5 1 3 @@ -43,7 +43,7 @@ - MySQL >= 5.0.12 AND time-based blind (SELECT - comment) + MySQL >= 5.0.12 AND time-based blind (SLEEP - comment) 5 3 1 @@ -64,7 +64,7 @@ - MySQL >= 5.0.12 OR time-based blind (SELECT - comment) + MySQL >= 5.0.12 OR time-based blind (SLEEP - comment) 5 3 3 @@ -249,7 +249,7 @@ - MySQL >= 5.0.12 RLIKE time-based blind (SELECT) + MySQL >= 5.0.12 RLIKE time-based blind (SLEEP) 5 2 1 @@ -269,7 +269,7 @@ - MySQL >= 5.0.12 RLIKE time-based blind (SELECT - comment) + MySQL >= 5.0.12 RLIKE time-based blind (SLEEP - comment) 5 4 1 @@ -1406,7 +1406,7 @@ - MySQL >= 5.0.12 time-based blind - Parameter replace (SELECT) + MySQL >= 5.0.12 time-based blind - Parameter replace (SLEEP) 5 3 1