diff --git a/lib/controller/checks.py b/lib/controller/checks.py index cb5d57b8e..3b00dcdea 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -137,7 +137,7 @@ def checkSqlInjection(place, parameter, value): SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms): msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms) msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]" - kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else [] + kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y', boolean=True) else [] # If the DBMS has been fingerprinted (via DBMS-specific error # message, via simple heuristic check or via DBMS-specific @@ -152,7 +152,7 @@ def checkSqlInjection(place, parameter, value): msg += " and " if conf.level < 5 and conf.risk < 3 else "" msg += "risk (%d)" % conf.risk if conf.risk < 3 else "" msg += " values? [Y/n]" if conf.level < 5 and conf.risk < 3 else " value? [Y/n]" - kb.extendTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else [] + kb.extendTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y', boolean=True) else [] title = test.title kb.testType = stype = test.stype @@ -631,7 +631,8 @@ def checkSqlInjection(place, parameter, value): msg += "extended UNION tests if there is not " msg += "at least one other (potential) " msg += "technique found. Do you want to skip? [Y/n] " - kb.futileUnion = readInput(msg, default="Y").strip().upper() == 'N' + + kb.futileUnion = not readInput(msg, default='Y', boolean=True) if kb.futileUnion is False: continue @@ -738,11 +739,9 @@ def checkSqlInjection(place, parameter, value): logger.warn(warnMsg) msg = "how do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit]" - choice = readInput(msg, default="S", checkBatch=False) + choice = readInput(msg, default='S', checkBatch=False).strip().upper() - if choice[0] in ("s", "S"): - pass - elif choice[0] in ("c", "C"): + if choice == 'C': choice = None while not ((choice or "").isdigit() and 0 <= int(choice) <= 6): if choice: @@ -752,11 +751,11 @@ def checkSqlInjection(place, parameter, value): conf.verbose = int(choice) setVerbosity() tests.insert(0, test) - elif choice[0] in ("n", "N"): + elif choice == 'N': return None - elif choice[0] in ("e", "E"): + elif choice == 'E': kb.endDetection = True - elif choice[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException finally: @@ -1177,19 +1176,19 @@ def checkStability(): logger.warn(warnMsg) message = "how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] " - test = readInput(message, default="C") + choice = readInput(message, default='C').strip().upper() - if test and test[0] in ("q", "Q"): + if choice == 'Q': raise SqlmapUserQuitException - elif test and test[0] in ("s", "S"): + elif choice == 'S': showStaticWords(firstPage, secondPage) message = "please enter value for parameter 'string': " - test = readInput(message) + string = readInput(message) - if test: - conf.string = test + if string: + conf.string = string if kb.nullConnection: debugMsg = "turning off NULL connection " @@ -1201,12 +1200,12 @@ def checkStability(): errMsg = "Empty value supplied" raise SqlmapNoneDataException(errMsg) - elif test and test[0] in ("r", "R"): + elif choice == 'R': message = "please enter value for parameter 'regex': " - test = readInput(message) + regex = readInput(message) - if test: - conf.regex = test + if regex: + conf.regex = regex if kb.nullConnection: debugMsg = "turning off NULL connection " @@ -1372,13 +1371,13 @@ def identifyWaf(): if retVal: message = "are you sure that you want to " message += "continue with further target testing? [y/N] " - output = readInput(message, default="N") + choice = readInput(message, default='N', boolean=True) if not conf.tamper: warnMsg = "please consider usage of tamper scripts (option '--tamper')" singleTimeWarnMessage(warnMsg) - if output and output[0] not in ("Y", "y"): + if not choice: raise SqlmapUserQuitException else: warnMsg = "WAF/IPS/IDS product hasn't been identified" @@ -1494,7 +1493,7 @@ def checkConnection(suppressOutput=False): return False msg = "it is not recommended to continue in this kind of cases. Do you want to quit and make sure that everything is set up properly? [Y/n] " - if readInput(msg, default="Y") not in ("n", "N"): + if readInput(msg, default='Y', boolean=True): raise SqlmapSilentQuitException else: kb.ignoreNotFound = True diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 91ce1cda1..d487a9dba 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -183,8 +183,8 @@ def _randomFillBlankFields(value): if extractRegexResult(EMPTY_FORM_FIELDS_REGEX, value): message = "do you want to fill blank fields with random values? [Y/n] " - test = readInput(message, default="Y") - if not test or test[0] in ("y", "Y"): + + if readInput(message, default="Y", boolean=True): for match in re.finditer(EMPTY_FORM_FIELDS_REGEX, retVal): item = match.group("result") if not any(_ in item for _ in IGNORE_PARAMETERS) and not re.search(ASP_NET_CONTROL_REGEX, item): @@ -305,7 +305,9 @@ def start(): message = "SQL injection vulnerability has already been detected " message += "against '%s'. Do you want to skip " % conf.hostname message += "further tests involving it? [Y/n]" - kb.skipVulnHost = readInput(message, default="Y").upper() != 'N' + + kb.skipVulnHost = readInput(message, default="Y", boolean=True) + testSqlInj = not kb.skipVulnHost if not testSqlInj: @@ -332,9 +334,8 @@ def start(): continue message += "\ndo you want to test this form? [Y/n/q] " - test = readInput(message, default="Y") - if not test or test[0] in ("y", "Y"): + if readInput(message, default='Y', boolean=True): if conf.method != HTTPMETHOD.GET: message = "Edit %s data [default: %s]%s: " % (conf.method, urlencode(conf.data) if conf.data else "None", " (Warning: blank fields detected)" if conf.data and extractRegexResult(EMPTY_FORM_FIELDS_REGEX, conf.data) else "") conf.data = readInput(message, default=conf.data) @@ -359,14 +360,12 @@ def start(): else: message += "\ndo you want to test this URL? [Y/n/q]" - test = readInput(message, default="Y") + choice = readInput(message, default='Y').strip().upper() - if not test or test[0] in ("y", "Y"): - pass - elif test[0] in ("n", "N"): + if choice == 'N': dataToStdout(os.linesep) continue - elif test[0] in ("q", "Q"): + elif choice == 'Q': break infoMsg = "testing URL '%s'" % targetUrl @@ -543,9 +542,8 @@ def start(): msg = "%s parameter '%s' " % (injection.place, injection.parameter) msg += "is vulnerable. Do you want to keep testing the others (if any)? [y/N] " - test = readInput(msg, default="N") - if test[0] not in ("y", "Y"): + if not readInput(msg, default='N', boolean=True): proceed = False paramKey = (conf.hostname, conf.path, None, None) kb.testedParams.add(paramKey) @@ -629,9 +627,7 @@ def start(): if kb.injection.place is not None and kb.injection.parameter is not None: if conf.multipleTargets: message = "do you want to exploit this SQL injection? [Y/n] " - exploit = readInput(message, default="Y") - - condition = not exploit or exploit[0] in ("y", "Y") + condition = readInput(message, default='Y', boolean=True) else: condition = True @@ -644,13 +640,11 @@ def start(): logger.warn(warnMsg) message = "do you want to skip to the next target in list? [Y/n/q]" - test = readInput(message, default="Y") + choice = readInput(message, default='Y').strip().upper() - if not test or test[0] in ("y", "Y"): - pass - elif test[0] in ("n", "N"): + if choice == 'N': return False - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: raise diff --git a/lib/core/common.py b/lib/core/common.py index 919c496c6..0eaedb1c2 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -601,8 +601,8 @@ def paramToDict(place, parameters=None): logger.warn(warnMsg) message = "are you really sure that you want to continue (sqlmap could have problems)? [y/N] " - test = readInput(message, default="N") - if test[0] not in ("y", "Y"): + + if not readInput(message, default='N', boolean=True): raise SqlmapSilentQuitException elif not _: warnMsg = "provided value for parameter '%s' is empty. " % parameter @@ -644,8 +644,8 @@ def paramToDict(place, parameters=None): if candidates: message = "it appears that provided value for %s parameter '%s' " % (place, parameter) message += "is JSON deserializable. Do you want to inject inside? [y/N] " - test = readInput(message, default="N") - if test[0] in ("y", "Y"): + + if not readInput(message, default='N', boolean=True): del testableParameters[parameter] testableParameters.update(candidates) break @@ -657,8 +657,8 @@ def paramToDict(place, parameters=None): _ = re.sub(regex, "\g<1>%s\g<%d>" % (CUSTOM_INJECTION_MARK_CHAR, len(match.groups())), testableParameters[parameter]) message = "it appears that provided value for %s parameter '%s' " % (place, parameter) message += "has boundaries. Do you want to inject inside? ('%s') [y/N] " % _ - test = readInput(message, default="N") - if test[0] in ("y", "Y"): + + if readInput(message, default='N', boolean=True): testableParameters[parameter] = re.sub(regex, "\g<1>%s\g<2>" % BOUNDED_INJECTION_MARKER, testableParameters[parameter]) break @@ -965,7 +965,7 @@ def dataToOutFile(filename, data): return retVal -def readInput(message, default=None, checkBatch=True): +def readInput(message, default=None, checkBatch=True, boolean=False): """ Reads input from terminal """ @@ -1038,6 +1038,9 @@ def readInput(message, default=None, checkBatch=True): finally: logging._releaseLock() + if boolean: + retVal = retVal.strip().upper == 'Y' + return retVal def randomRange(start=0, stop=1000, seed=None): @@ -1979,9 +1982,8 @@ def getSQLSnippet(dbms, sfile, **variables): logger.error(errMsg) msg = "do you want to provide the substitution values? [y/N] " - choice = readInput(msg, default="N") - if choice and choice[0].lower() == "y": + if readInput(msg, default='N', boolean=True): for var in variables: msg = "insert value for variable '%s': " % var val = readInput(msg, default="") @@ -2370,8 +2372,8 @@ def wasLastResponseDelayed(): if kb.adjustTimeDelay is None: msg = "do you want sqlmap to try to optimize value(s) " msg += "for DBMS delay responses (option '--time-sec')? [Y/n] " - choice = readInput(msg, default='Y') - kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE if choice.upper() == 'N' else ADJUST_TIME_DELAY.YES + + kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE if not readInput(msg, default='Y', boolean=True) else ADJUST_TIME_DELAY.YES if kb.adjustTimeDelay is ADJUST_TIME_DELAY.YES: adjustTimeDelay(threadData.lastQueryDuration, lowerStdLimit) @@ -3263,11 +3265,11 @@ def createGithubIssue(errMsg, excMsg): msg += "with the unhandled exception information at " msg += "the official Github repository? [y/N] " try: - test = readInput(msg, default="N") + choice = readInput(msg, default='N', boolean=True) except: - test = None + choice = None - if test and test[0] in ("y", "Y"): + if choice: ex = None errMsg = errMsg[errMsg.find("\n"):] diff --git a/lib/core/option.py b/lib/core/option.py index e3a731ac4..b054494fc 100755 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -542,8 +542,7 @@ def _doSearch(): elif re.search(URI_INJECTABLE_REGEX, link, re.I): if kb.data.onlyGETs is None and conf.data is None and not conf.googleDork: message = "do you want to scan only results containing GET parameters? [Y/n] " - test = readInput(message, default="Y") - kb.data.onlyGETs = test.lower() != 'n' + kb.data.onlyGETs = readInput(message, default='Y', boolean=True) if not kb.data.onlyGETs or conf.googleDork: kb.targets.add((link, conf.method, conf.data, conf.cookie, None)) @@ -570,9 +569,8 @@ def _doSearch(): message += "for your search dork expression, but none of them " message += "have GET parameters to test for SQL injection. " message += "Do you want to skip to the next result page? [Y/n]" - test = readInput(message, default="Y") - if test[0] in ("n", "N"): + if not readInput(message, default='Y', boolean=True): raise SqlmapSilentQuitException else: conf.googlePage += 1 @@ -946,14 +944,14 @@ def _setTamperingFunctions(): 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") + choice = readInput(message, default='Y').strip().upper() - if not test or test[0] in ("y", "Y"): - resolve_priorities = True - elif test[0] in ("n", "N"): + if choice == 'N': resolve_priorities = False - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException + else: + resolve_priorities = True check_priority = False diff --git a/lib/core/settings.py b/lib/core/settings.py index fe3bb95c3..922c8e8b9 100755 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -19,7 +19,7 @@ from lib.core.enums import DBMS_DIRECTORY_NAME from lib.core.enums import OS # sqlmap version (...) -VERSION = "1.1.4.31" +VERSION = "1.1.4.32" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) diff --git a/lib/core/target.py b/lib/core/target.py index 790687597..0e183ffe4 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -118,11 +118,12 @@ def _setRequestParams(): if kb.processUserMarks is None and CUSTOM_INJECTION_MARK_CHAR in conf.data: message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'--data'. Do you want to process it? [Y/n/q] " - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y') + + if choice == 'Q': raise SqlmapUserQuitException else: - kb.processUserMarks = not test or test[0] not in ("n", "N") + kb.processUserMarks = choice == 'Y' if kb.processUserMarks: kb.testOnlyCustom = True @@ -131,10 +132,11 @@ def _setRequestParams(): if re.search(JSON_RECOGNITION_REGEX, conf.data): message = "JSON data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y') + + if choice == 'Q': raise SqlmapUserQuitException - elif test[0] not in ("n", "N"): + elif choice == 'N': conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r'("(?P[^"]+)"\s*:\s*"[^"]+)"', functools.partial(process, repl=r'\g<1>%s"' % CUSTOM_INJECTION_MARK_CHAR), conf.data) @@ -150,10 +152,11 @@ def _setRequestParams(): elif re.search(JSON_LIKE_RECOGNITION_REGEX, conf.data): message = "JSON-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y').strip().upper() + + if choice == 'Q': raise SqlmapUserQuitException - elif test[0] not in ("n", "N"): + elif choice == 'N': conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"('(?P[^']+)'\s*:\s*'[^']+)'", functools.partial(process, repl=r"\g<1>%s'" % CUSTOM_INJECTION_MARK_CHAR), conf.data) @@ -163,10 +166,11 @@ def _setRequestParams(): elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, conf.data): message = "Array-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y').strip().upper() + + if choice == 'Q': raise SqlmapUserQuitException - elif test[0] not in ("n", "N"): + elif choice == 'N': conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(=[^%s]+)" % DEFAULT_GET_POST_DELIMITER, r"\g<1>%s" % CUSTOM_INJECTION_MARK_CHAR, conf.data) kb.postHint = POST_HINT.ARRAY_LIKE @@ -174,10 +178,11 @@ def _setRequestParams(): elif re.search(XML_RECOGNITION_REGEX, conf.data): message = "SOAP/XML data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y').strip().upper() + + if choice == 'Q': raise SqlmapUserQuitException - elif test[0] not in ("n", "N"): + elif choice == 'N': conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(<(?P[^>]+)( [^<]*)?>)([^<]+)(\g<4>%s\g<5>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) @@ -186,10 +191,11 @@ def _setRequestParams(): elif re.search(MULTIPART_RECOGNITION_REGEX, conf.data): message = "Multipart-like data found in %s data. " % conf.method message += "Do you want to process it? [Y/n/q] " - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y').strip().upper() + + if choice == 'Q': raise SqlmapUserQuitException - elif test[0] not in ("n", "N"): + elif choice == 'N': conf.data = getattr(conf.data, UNENCODED_ORIGINAL_VALUE, conf.data) conf.data = conf.data.replace(CUSTOM_INJECTION_MARK_CHAR, ASTERISK_MARKER) conf.data = re.sub(r"(?si)((Content-Disposition[^\n]+?name\s*=\s*[\"'](?P[^\n]+?)[\"']).+?)(((\r)?\n)+--)", functools.partial(process, repl=r"\g<1>%s\g<4>" % CUSTOM_INJECTION_MARK_CHAR), conf.data) @@ -222,11 +228,11 @@ def _setRequestParams(): message = "do you want to try URI injections " message += "in the target URL itself? [Y/n/q] " - test = readInput(message, default="Y") + choice = readInput(message, default='Y').strip().upper() - if test and test[0] in ("q", "Q"): + if choice == 'Q': raise SqlmapUserQuitException - elif not test or test[0] not in ("n", "N"): + elif choice == 'Y': conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True @@ -237,11 +243,12 @@ def _setRequestParams(): lut = {PLACE.URI: '-u', PLACE.CUSTOM_POST: '--data', PLACE.CUSTOM_HEADER: '--headers/--user-agent/--referer/--cookie'} message = "custom injection marking character ('%s') found in option " % CUSTOM_INJECTION_MARK_CHAR message += "'%s'. Do you want to process it? [Y/n/q] " % lut[place] - test = readInput(message, default="Y") - if test and test[0] in ("q", "Q"): + choice = readInput(message, default='Y').strip().upper() + + if choice == 'Q': raise SqlmapUserQuitException else: - kb.processUserMarks = not test or test[0] not in ("n", "N") + kb.processUserMarks = choice == 'Y' if kb.processUserMarks: kb.testOnlyCustom = True @@ -381,8 +388,8 @@ def _setRequestParams(): if any(parameter.lower().count(_) for _ in CSRF_TOKEN_PARAMETER_INFIXES): message = "%s parameter '%s' appears to hold anti-CSRF token. " % (place, parameter) message += "Do you want sqlmap to automatically update it in further requests? [y/N] " - test = readInput(message, default="N") - if test and test[0] in ("y", "Y"): + + if readInput(message, default='N', boolean=True): conf.csrfToken = parameter break @@ -471,9 +478,8 @@ def _resumeDBMS(): message += "sqlmap assumes the back-end DBMS is '%s'. " % dbms message += "Do you really want to force the back-end " message += "DBMS value? [y/N] " - test = readInput(message, default="N") - if not test or test[0] in ("n", "N"): + if not readInput(message, default='N', boolean=True): conf.dbms = None Backend.setDbms(dbms) Backend.setVersionList(dbmsVersion) @@ -507,9 +513,8 @@ def _resumeOS(): message += "operating system is %s. " % os message += "Do you really want to force the back-end DBMS " message += "OS value? [y/N] " - test = readInput(message, default="N") - if not test or test[0] in ("n", "N"): + if not readInput(message, default='N', boolean=True): conf.os = os else: conf.os = os diff --git a/lib/core/threads.py b/lib/core/threads.py index c1349ace1..6358b7d9a 100644 --- a/lib/core/threads.py +++ b/lib/core/threads.py @@ -67,7 +67,7 @@ ThreadData = _ThreadData() def getCurrentThreadUID(): return hash(threading.currentThread()) -def readInput(message, default=None): +def readInput(message, default=None, checkBatch=True, boolean=False): # It will be overwritten by original from lib.core.common pass diff --git a/lib/parse/sitemap.py b/lib/parse/sitemap.py index 182703283..efd609d15 100644 --- a/lib/parse/sitemap.py +++ b/lib/parse/sitemap.py @@ -41,8 +41,7 @@ def parseSitemap(url, retVal=None): if url.endswith(".xml") and "sitemap" in url.lower(): if kb.followSitemapRecursion is None: message = "sitemap recursion detected. Do you want to follow? [y/N] " - test = readInput(message, default="N") - kb.followSitemapRecursion = test[0] in ("y", "Y") + kb.followSitemapRecursion = readInput(message, default='N', boolean=True) if kb.followSitemapRecursion: parseSitemap(url, retVal) else: diff --git a/lib/request/basic.py b/lib/request/basic.py index ef253f33a..fc3685cd1 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -103,8 +103,8 @@ def forgeHeaders(items=None): message += "The target URL provided its own cookies within " message += "the HTTP %s header which intersect with yours. " % HTTP_HEADER.SET_COOKIE message += "Do you want to merge them in further requests? [Y/n] " - _ = readInput(message, default="Y") - kb.mergeCookies = not _ or _[0] in ("y", "Y") + + kb.mergeCookies = readInput(message, default='Y', boolean=True) if kb.mergeCookies and kb.injection.place != PLACE.COOKIE: _ = lambda x: re.sub(r"(?i)\b%s=[^%s]+" % (re.escape(getUnicode(cookie.name)), conf.cookieDel or DEFAULT_COOKIE_DELIMITER), ("%s=%s" % (getUnicode(cookie.name), getUnicode(cookie.value))).replace('\\', r'\\'), x) @@ -368,8 +368,10 @@ def processResponse(page, responseHeaders): continue else: msg = "do you want to automatically adjust the value of '%s'? [y/N]" % name - if readInput(msg, default='N').strip().upper() != 'Y': + + if not readInput(msg, default='N', boolean=True): continue + conf.paramDict[PLACE.POST][name] = value conf.parameters[PLACE.POST] = re.sub("(?i)(%s=)[^&]+" % re.escape(name), r"\g<1>%s" % re.escape(value), conf.parameters[PLACE.POST]) diff --git a/lib/request/connect.py b/lib/request/connect.py index fb447094e..9c45e5600 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -509,9 +509,8 @@ class Connect(object): msg += "(redirect like response common to login pages). " msg += "Do you want to apply the refresh " msg += "from now on (or stay on the original page)? [Y/n]" - choice = readInput(msg, default="Y") - kb.alwaysRefresh = choice not in ("n", "N") + kb.alwaysRefresh = readInput(msg, default='Y', boolean=True) if kb.alwaysRefresh: if re.search(r"\Ahttps?://", refresh, re.I): @@ -675,7 +674,8 @@ class Connect(object): message = "there seems to be a continuous problem with connection to the target. " message += "Are you sure that you want to continue " message += "with further target testing? [y/N] " - kb.connErrorChoice = readInput(message, default="N") in ("Y", "y") + + kb.connErrorChoice = readInput(message, default='N', boolean=True) if kb.connErrorChoice is False: raise SqlmapConnectionException(warnMsg) @@ -832,7 +832,7 @@ class Connect(object): if kb.cookieEncodeChoice is None: msg = "do you want to URL encode cookie values (implementation specific)? %s" % ("[Y/n]" if not conf.url.endswith(".aspx") else "[y/N]") # Reference: https://support.microsoft.com/en-us/kb/313282 choice = readInput(msg, default='Y' if not conf.url.endswith(".aspx") else 'N') - kb.cookieEncodeChoice = choice.upper().strip() == "Y" + kb.cookieEncodeChoice = choice.upper().strip() == 'Y' if not kb.cookieEncodeChoice: skip = True diff --git a/lib/request/inject.py b/lib/request/inject.py index cd0c396b8..bc221fb97 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -208,22 +208,22 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char message += "entries do you want to retrieve?\n" message += "[a] All (default)\n[#] Specific number\n" message += "[q] Quit" - test = readInput(message, default="a") + choice = readInput(message, default='A').strip().upper() - if not test or test[0] in ("a", "A"): + if choice == 'A': stopLimit = count - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException - elif test.isdigit() and int(test) > 0 and int(test) <= count: - stopLimit = int(test) + elif choice.isdigit() and int(choice) > 0 and int(choice) <= count: + stopLimit = int(choice) infoMsg = "sqlmap is now going to retrieve the " infoMsg += "first %d query output entries" % stopLimit logger.info(infoMsg) - elif test[0] in ("#", "s", "S"): + elif choice in ('#', 'S'): message = "how many? " stopLimit = readInput(message, default="10") diff --git a/lib/request/redirecthandler.py b/lib/request/redirecthandler.py index 81c7163ed..ce22fb14f 100644 --- a/lib/request/redirecthandler.py +++ b/lib/request/redirecthandler.py @@ -50,18 +50,16 @@ class SmartRedirectHandler(urllib2.HTTPRedirectHandler): if kb.redirectChoice is None: msg = "sqlmap got a %d redirect to " % redcode msg += "'%s'. Do you want to follow? [Y/n] " % redurl - choice = readInput(msg, default="Y") - kb.redirectChoice = choice.upper() + kb.redirectChoice = REDIRECTION.YES if readInput(msg, default='Y', boolean=True) else REDIRECTION.NO if kb.redirectChoice == REDIRECTION.YES and method == HTTPMETHOD.POST and kb.resendPostOnRedirect is None: msg = "redirect is a result of a " msg += "POST request. Do you want to " msg += "resend original POST data to a new " msg += "location? [%s] " % ("Y/n" if not kb.originalPage else "y/N") - choice = readInput(msg, default=("Y" if not kb.originalPage else "N")) - kb.resendPostOnRedirect = choice.upper() == 'Y' + kb.resendPostOnRedirect = readInput(msg, default=("Y" if not kb.originalPage else "N"), boolean=True) if kb.resendPostOnRedirect: self.redirect_request = self._redirect_request diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index 77dcdf2c9..f5ef9edaf 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -75,17 +75,17 @@ class Abstraction(Web, UDF, XP_cmdshell): return safechardecode(retVal) def runCmd(self, cmd): - getOutput = None + choice = None if not self.alwaysRetrieveCmdOutput: message = "do you want to retrieve the command standard " message += "output? [Y/n/a] " - getOutput = readInput(message, default="Y") + choice = readInput(message, default='Y') - if getOutput in ("a", "A"): + if choice in ('a', 'A'): self.alwaysRetrieveCmdOutput = True - if not getOutput or getOutput in ("y", "Y") or self.alwaysRetrieveCmdOutput: + if not choice or choice in ('y', 'Y') or self.alwaysRetrieveCmdOutput: output = self.evalCmd(cmd) if output: @@ -166,9 +166,8 @@ class Abstraction(Web, UDF, XP_cmdshell): msg += "statements as another DBMS user since you provided the " msg += "option '--dbms-creds'. If you are DBA, you can enable it. " msg += "Do you want to enable it? [Y/n] " - choice = readInput(msg, default="Y") - if not choice or choice in ("y", "Y"): + if readInput(msg, default='Y', boolean=True): expression = getSQLSnippet(DBMS.MSSQL, "configure_openrowset", ENABLE="1") inject.goStacked(expression) diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index 12f9be470..b5c67bda9 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -42,12 +42,8 @@ class UDF: def _askOverwriteUdf(self, udf): message = "UDF '%s' already exists, do you " % udf message += "want to overwrite it? [y/N] " - output = readInput(message, default="N") - if output and output[0] in ("y", "Y"): - return True - else: - return False + return readInput(message, default='N', boolean=True) def _checkExistUdf(self, udf): logger.info("checking if UDF '%s' already exist" % udf) @@ -327,12 +323,12 @@ class UDF: msg = "do you want to call your injected user-defined " msg += "functions now? [Y/n/q] " - choice = readInput(msg, default="Y") + choice = readInput(msg, default='Y').strip().upper() - if choice[0] in ("n", "N"): + if choice == 'N': self.cleanup(udfDict=self.udfs) return - elif choice[0] in ("q", "Q"): + elif choice == 'Q': self.cleanup(udfDict=self.udfs) raise SqlmapUserQuitException @@ -347,9 +343,9 @@ class UDF: msg += "\n[q] Quit" while True: - choice = readInput(msg) + choice = readInput(msg).strip().upper() - if choice and choice[0] in ("q", "Q"): + if choice == 'Q': break elif isinstance(choice, basestring) and choice.isdigit() and int(choice) > 0 and int(choice) <= len(udfList): choice = int(choice) @@ -390,9 +386,8 @@ class UDF: cmd = cmd[:-1] msg = "do you want to retrieve the return value of the " msg += "UDF? [Y/n] " - choice = readInput(msg, default="Y") - if choice[0] in ("y", "Y"): + if readInput(msg, default='Y', boolean=True): output = self.udfEvalCmd(cmd, udfName=udfToCall) if output: @@ -403,9 +398,8 @@ class UDF: self.udfExecCmd(cmd, udfName=udfToCall, silent=True) msg = "do you want to call this or another injected UDF? [Y/n] " - choice = readInput(msg, default="Y") - if choice[0] not in ("y", "Y"): + if not readInput(msg, default='Y', boolean=True): break self.cleanup(udfDict=self.udfs) diff --git a/lib/takeover/web.py b/lib/takeover/web.py index b1d907156..3d2f8389d 100644 --- a/lib/takeover/web.py +++ b/lib/takeover/web.py @@ -202,9 +202,8 @@ class Web: if not kb.absFilePaths: message = "do you want sqlmap to further try to " message += "provoke the full path disclosure? [Y/n] " - getOutput = readInput(message, default="Y") - if getOutput in ("y", "Y"): + if readInput(message, default='Y', boolean=True): headers = {} been = set([conf.url]) @@ -391,9 +390,8 @@ class Web: message = "do you want to try the same method used " message += "for the file stager? [Y/n] " - getOutput = readInput(message, default="Y") - if getOutput in ("y", "Y"): + if readInput(message, default='Y', boolean=True): self._webFileInject(backdoorContent, backdoorName, directory) else: continue diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index e7ac6a52a..6c9fd6928 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -255,9 +255,8 @@ class XP_cmdshell: message = "xp_cmdshell extended procedure does not seem to " message += "be available. Do you want sqlmap to try to " message += "re-enable it? [Y/n] " - choice = readInput(message, default="Y") - if not choice or choice in ("y", "Y"): + if readInput(message, default='Y', boolean=True): self._xpCmdshellConfigure(1) if self._xpCmdshellCheck(): diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index a4ef3cd90..ef88100a2 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -358,9 +358,8 @@ def errorUse(expression, dump=False): if " ORDER BY " in expression and (stopLimit - startLimit) > SLOW_ORDER_COUNT_THRESHOLD: message = "due to huge table size do you want to remove " message += "ORDER BY clause gaining speed over consistency? [y/N] " - _ = readInput(message, default="N") - if _ and _[0] in ("y", "Y"): + 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 1f2c49a5a..19c41801a 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -283,8 +283,8 @@ 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] " - test = readInput(message, default="Y") - if test[0] not in ("y", "Y"): + + if not readInput(message, default="Y", boolean=True): warnMsg += "usage of option '--union-char' " warnMsg += "(e.g. '--union-char=1') " else: diff --git a/lib/utils/brute.py b/lib/utils/brute.py index 30766786a..255df2983 100644 --- a/lib/utils/brute.py +++ b/lib/utils/brute.py @@ -57,8 +57,7 @@ def tableExists(tableFile, regex=None): logger.warn(warnMsg) message = "are you sure you want to continue? [y/N] " - test = readInput(message, default="N") - kb.tableExistsChoice = test[0] in ("y", "Y") + kb.tableExistsChoice = readInput(message, default='N', boolean=True) if not kb.tableExistsChoice: return None @@ -161,8 +160,7 @@ def columnExists(columnFile, regex=None): logger.warn(warnMsg) message = "are you sure you want to continue? [y/N] " - test = readInput(message, default="N") - kb.columnExistsChoice = test[0] in ("y", "Y") + kb.columnExistsChoice = readInput(message, default='N', boolean=True) if not kb.columnExistsChoice: return None diff --git a/lib/utils/crawler.py b/lib/utils/crawler.py index edeb946fe..4a0b9c138 100644 --- a/lib/utils/crawler.py +++ b/lib/utils/crawler.py @@ -130,8 +130,8 @@ def crawl(target): if not conf.sitemapUrl: message = "do you want to check for the existence of " message += "site's sitemap(.xml) [y/N] " - test = readInput(message, default="n") - if test[0] in ("y", "Y"): + + if readInput(message, default='N', boolean=True): found = True items = None url = urlparse.urljoin(target, "/sitemap.xml") @@ -198,8 +198,8 @@ def storeResultsToFile(results): if kb.storeCrawlingChoice is None: message = "do you want to store crawling results to a temporary file " message += "for eventual further processing with other tools [y/N] " - test = readInput(message, default="N") - kb.storeCrawlingChoice = test[0] in ("y", "Y") + + kb.storeCrawlingChoice = readInput(message, default='N', boolean=True) if kb.storeCrawlingChoice: handle, filename = tempfile.mkstemp(prefix=MKSTEMP_PREFIX.CRAWLER, suffix=".csv" if conf.forms else ".txt") diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 06396223d..5bc23b796 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -382,8 +382,8 @@ def storeHashesToFile(attack_dict): if kb.storeHashesChoice is None: message = "do you want to store hashes to a temporary file " message += "for eventual further processing with other tools [y/N] " - test = readInput(message, default="N") - kb.storeHashesChoice = test[0] in ("y", "Y") + + kb.storeHashesChoice = readInput(message, default='N', boolean=True) if not kb.storeHashesChoice: return @@ -482,11 +482,11 @@ def attackDumpedTable(): storeHashesToFile(attack_dict) message = "do you want to crack them via a dictionary-based attack? %s" % ("[y/N/q]" if conf.multipleTargets else "[Y/n/q]") - test = readInput(message, default="N" if conf.multipleTargets else "Y") + choice = readInput(message, default='N' if conf.multipleTargets else 'Y').strip().upper() - if test[0] in ("n", "N"): + if choice == 'N': return - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException results = dictionaryAttack(attack_dict) @@ -805,9 +805,8 @@ def dictionaryAttack(attack_dict): logger.critical(warnMsg) message = "do you want to use common password suffixes? (slow!) [y/N] " - test = readInput(message, default="N") - if test[0] in ("y", "Y"): + if readInput(message, default='N', boolean=True): suffix_list += COMMON_PASSWORD_SUFFIXES infoMsg = "starting dictionary-based cracking (%s)" % __functions__[hash_regex].func_name diff --git a/plugins/dbms/maxdb/enumeration.py b/plugins/dbms/maxdb/enumeration.py index a506f8207..0acd62534 100644 --- a/plugins/dbms/maxdb/enumeration.py +++ b/plugins/dbms/maxdb/enumeration.py @@ -172,11 +172,11 @@ class Enumeration(GenericEnumeration): return kb.data.cachedColumns message = "do you want to use common column existence check? [y/N/q] " - test = readInput(message, default="Y" if "Y" in message else "N") + choice = readInput(message, default='Y' if 'Y' in message else 'N').strip().upper() - if test[0] in ("n", "N"): + if choice == 'N': return - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) diff --git a/plugins/dbms/mssqlserver/filesystem.py b/plugins/dbms/mssqlserver/filesystem.py index 3ef3075d8..9d1edf9b8 100644 --- a/plugins/dbms/mssqlserver/filesystem.py +++ b/plugins/dbms/mssqlserver/filesystem.py @@ -382,27 +382,24 @@ class Filesystem(GenericFilesystem): if written is False: message = "do you want to try to upload the file with " message += "the custom Visual Basic script technique? [Y/n] " - choice = readInput(message, default="Y") - if not choice or choice.lower() == "y": + if readInput(message, default='Y', boolean=True): self._stackedWriteFileVbs(tmpPath, wFileContent, dFile, fileType) written = self.askCheckWrittenFile(wFile, dFile, forceCheck) if written is False: message = "do you want to try to upload the file with " message += "the built-in debug.exe technique? [Y/n] " - choice = readInput(message, default="Y") - if not choice or choice.lower() == "y": + if readInput(message, default='Y', boolean=True): self._stackedWriteFileDebugExe(tmpPath, wFile, wFileContent, dFile, fileType) written = self.askCheckWrittenFile(wFile, dFile, forceCheck) if written is False: message = "do you want to try to upload the file with " message += "the built-in certutil.exe technique? [Y/n] " - choice = readInput(message, default="Y") - if not choice or choice.lower() == "y": + if readInput(message, default='Y', boolean=True): self._stackedWriteFileCertutilExe(tmpPath, wFile, wFileContent, dFile, fileType) written = self.askCheckWrittenFile(wFile, dFile, forceCheck) diff --git a/plugins/dbms/sybase/enumeration.py b/plugins/dbms/sybase/enumeration.py index 8ba5e7acd..2529ce8ef 100644 --- a/plugins/dbms/sybase/enumeration.py +++ b/plugins/dbms/sybase/enumeration.py @@ -240,11 +240,11 @@ class Enumeration(GenericEnumeration): return kb.data.cachedColumns message = "do you want to use common column existence check? [y/N/q] " - test = readInput(message, default="Y" if "Y" in message else "N") + choice = readInput(message, default='Y' if 'Y' in message else 'N').strip().upper() - if test[0] in ("n", "N"): + if choice == 'N': return - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) diff --git a/plugins/generic/databases.py b/plugins/generic/databases.py index fbac8c999..a95001e88 100644 --- a/plugins/generic/databases.py +++ b/plugins/generic/databases.py @@ -243,11 +243,11 @@ class Databases: 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]") - test = readInput(message, default="Y" if "Y" in message else "N") + choice = readInput(message, default='Y' if 'Y' in message else 'N').strip().upper() - if test[0] in ("n", "N"): + if choice == 'N': return - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: return tableExists(paths.COMMON_TABLES) @@ -486,11 +486,11 @@ class Databases: 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]") - test = readInput(message, default="Y" if "Y" in message else "N") + choice = readInput(message, default='Y' if 'Y' in message else 'N').strip().upper() - if test[0] in ("n", "N"): + if choice == 'N': return - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: return columnExists(paths.COMMON_COLUMNS) diff --git a/plugins/generic/entries.py b/plugins/generic/entries.py index dda0d83ea..989568278 100644 --- a/plugins/generic/entries.py +++ b/plugins/generic/entries.py @@ -422,9 +422,8 @@ class Entries: def dumpFoundColumn(self, dbs, foundCols, colConsider): message = "do you want to dump entries? [Y/n] " - output = readInput(message, default="Y") - if output and output[0] not in ("y", "Y"): + if not readInput(message, default='Y', boolean=True): return dumpFromDbs = [] @@ -435,14 +434,14 @@ class Entries: message += "[%s]\n" % unsafeSQLIdentificatorNaming(db) message += "[q]uit" - test = readInput(message, default="a") + choice = readInput(message, default='a') - if not test or test in ("a", "A"): + if not choice or choice in ('a', 'A'): dumpFromDbs = dbs.keys() - elif test in ("q", "Q"): + elif choice in ('q', 'Q'): return else: - dumpFromDbs = test.replace(" ", "").split(",") + dumpFromDbs = choice.replace(" ", "").split(",") for db, tblData in dbs.items(): if db not in dumpFromDbs or not tblData: @@ -458,16 +457,16 @@ class Entries: message += "[s]kip\n" message += "[q]uit" - test = readInput(message, default="a") + choice = readInput(message, default='a') - if not test or test in ("a", "A"): + if not choice or choice in ('a', 'A'): dumpFromTbls = tblData - elif test in ("s", "S"): + elif choice in ('s', 'S'): continue - elif test in ("q", "Q"): + elif choice in ('q', 'Q'): return else: - dumpFromTbls = test.replace(" ", "").split(",") + dumpFromTbls = choice.replace(" ", "").split(",") for table, columns in tblData.items(): if table not in dumpFromTbls: @@ -479,7 +478,7 @@ class Entries: if conf.excludeCol: colList = [_ for _ in colList if _ not in conf.excludeCol.split(',')] - conf.col = ",".join(colList) + conf.col = ','.join(colList) kb.data.cachedColumns = {} kb.data.dumpedTable = {} @@ -490,9 +489,8 @@ class Entries: def dumpFoundTables(self, tables): message = "do you want to dump tables' entries? [Y/n] " - output = readInput(message, default="Y") - if output and output[0].lower() != "y": + if not readInput(message, default='Y', boolean=True): return dumpFromDbs = [] @@ -503,14 +501,14 @@ class Entries: message += "[%s]\n" % unsafeSQLIdentificatorNaming(db) message += "[q]uit" - test = readInput(message, default="a") + choice = readInput(message, default='a') - if not test or test.lower() == "a": + if not choice or choice.lower() == 'a': dumpFromDbs = tables.keys() - elif test.lower() == "q": + elif choice.lower() == 'q': return else: - dumpFromDbs = test.replace(" ", "").split(",") + dumpFromDbs = choice.replace(" ", "").split(',') for db, tablesList in tables.items(): if db not in dumpFromDbs or not tablesList: @@ -526,16 +524,16 @@ class Entries: message += "[s]kip\n" message += "[q]uit" - test = readInput(message, default="a") + choice = readInput(message, default='a') - if not test or test.lower() == "a": + if not choice or choice.lower() == 'a': dumpFromTbls = tablesList - elif test.lower() == "s": + elif choice.lower() == 's': continue - elif test.lower() == "q": + elif choice.lower() == 'q': return else: - dumpFromTbls = test.replace(" ", "").split(",") + dumpFromTbls = choice.replace(" ", "").split(',') for table in dumpFromTbls: conf.tbl = table diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index fc203db4e..9611c3212 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -156,15 +156,15 @@ class Filesystem: return retVal def askCheckWrittenFile(self, localFile, remoteFile, forceCheck=False): - output = None + choice = None if forceCheck is not True: message = "do you want confirmation that the local file '%s' " % localFile message += "has been successfully written on the back-end DBMS " message += "file system ('%s')? [Y/n] " % remoteFile - output = readInput(message, default="Y") + choice = readInput(message, default='Y', boolean=True) - if forceCheck or (output and output.lower() == "y"): + if forceCheck or choice: return self._checkFileLength(localFile, remoteFile) return True @@ -173,9 +173,8 @@ class Filesystem: message = "do you want confirmation that the remote file '%s' " % remoteFile message += "has been successfully downloaded from the back-end " message += "DBMS file system? [Y/n] " - output = readInput(message, default="Y") - if not output or output in ("y", "Y"): + if readInput(message, default='Y', boolean=True): return self._checkFileLength(localFile, remoteFile, True) return None diff --git a/plugins/generic/misc.py b/plugins/generic/misc.py index 9a4156ce7..032dc9a40 100644 --- a/plugins/generic/misc.py +++ b/plugins/generic/misc.py @@ -169,9 +169,8 @@ class Miscellaneous: for udf, inpRet in udfDict.items(): message = "do you want to remove UDF '%s'? [Y/n] " % udf - output = readInput(message, default="Y") - if not output or output in ("y", "Y"): + if readInput(message, default='Y', boolean=True): dropStr = "DROP FUNCTION %s" % udf if Backend.isDbms(DBMS.PGSQL): diff --git a/plugins/generic/search.py b/plugins/generic/search.py index 840e25c69..ccddb2848 100644 --- a/plugins/generic/search.py +++ b/plugins/generic/search.py @@ -146,18 +146,18 @@ class Search: 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]") - test = readInput(message, default="Y" if "Y" in message else "N") + choice = readInput(message, default='Y' if 'Y' in message else 'N').strip().upper() - if test[0] in ("n", "N"): - return - elif test[0] in ("q", "Q"): + if choice == 'N': + pass + elif choice == 'Q': raise SqlmapUserQuitException else: - regex = "|".join(conf.tbl.split(",")) + regex = '|'.join(conf.tbl.split(',')) return tableExists(paths.COMMON_TABLES, regex) foundTbls = {} - tblList = conf.tbl.split(",") + tblList = conf.tbl.split(',') rootQuery = queries[Backend.getIdentifiedDbms()].search_table tblCond = rootQuery.inband.condition dbCond = rootQuery.inband.condition2 @@ -171,7 +171,7 @@ class Search: tbl = tbl.upper() infoMsg = "searching table" - if tblConsider == "1": + if tblConsider == '1': infoMsg += "s LIKE" infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl) @@ -345,20 +345,19 @@ class Search: 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]") - test = readInput(message, default="Y" if "Y" in message else "N") + choice = readInput(message, default='Y' if 'Y' in message else 'N').upper() - if test[0] in ("n", "N"): + if choice == 'N': return - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: regex = '|'.join(conf.col.split(',')) conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS, regex)) message = "do you want to dump entries? [Y/n] " - output = readInput(message, default="Y") - if output and output[0] not in ("n", "N"): + if readInput(message, default='Y', boolean=True): self.dumpAll() return diff --git a/plugins/generic/takeover.py b/plugins/generic/takeover.py index fc808cdd5..00761cc1a 100644 --- a/plugins/generic/takeover.py +++ b/plugins/generic/takeover.py @@ -336,11 +336,8 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): msg = "this technique is likely to DoS the DBMS process, are you " msg += "sure that you want to carry with the exploit? [y/N] " - choice = readInput(msg, default="N") - dos = choice and choice[0].lower() == "y" - - if dos: + if readInput(msg, default='N', boolean=True): self.initEnv(mandatory=False, detailed=True) self.getRemoteTempPath() self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True) diff --git a/plugins/generic/users.py b/plugins/generic/users.py index f18440909..cbc7d8062 100644 --- a/plugins/generic/users.py +++ b/plugins/generic/users.py @@ -319,11 +319,11 @@ class Users: message = "do you want to perform a dictionary-based attack " message += "against retrieved password hashes? [Y/n/q]" - test = readInput(message, default="Y") + choice = readInput(message, default='Y').strip().upper() - if test[0] in ("n", "N"): + if choice == 'N': pass - elif test[0] in ("q", "Q"): + elif choice == 'Q': raise SqlmapUserQuitException else: attackCachedUsersPasswords() @@ -345,7 +345,7 @@ class Users: conf.user = conf.user.upper() if conf.user: - users = conf.user.split(",") + users = conf.user.split(',') if Backend.isDbms(DBMS.MYSQL): for user in users: diff --git a/txt/checksum.md5 b/txt/checksum.md5 index 76be6dd71..99532a193 100644 --- a/txt/checksum.md5 +++ b/txt/checksum.md5 @@ -21,13 +21,13 @@ c55b400b72acc43e0e59c87dd8bb8d75 extra/shellcodeexec/windows/shellcodeexec.x32. 310efc965c862cfbd7b0da5150a5ad36 extra/sqlharvest/__init__.py 7713aa366c983cdf1f3dbaa7383ea9e1 extra/sqlharvest/sqlharvest.py 7afe836fd97271ccba67b4c0da2482ff lib/controller/action.py -9cb94acd4c59822a5e1a258c4d1a4860 lib/controller/checks.py -8bf4fde39867b94600f61dc7fddcf3b0 lib/controller/controller.py +21c79cf1a79b61c6d90f9bd249f71584 lib/controller/checks.py +fc89abe14a48b8232feba692bde992be lib/controller/controller.py 52a3969f57170e935e3fc0156335bf2c lib/controller/handler.py 310efc965c862cfbd7b0da5150a5ad36 lib/controller/__init__.py 5c4cddb0016d02a57bd1b05b3fc60c54 lib/core/agent.py 6cc95a117fbd34ef31b9aa25520f0e31 lib/core/bigarray.py -1fa78f8104a2b39e87c19cb20e8eab72 lib/core/common.py +96da6283da447e98a7592d6ee59b50dd lib/core/common.py 5065a4242a8cccf72f91e22e1007ae63 lib/core/convert.py a8143dab9d3a27490f7d49b6b29ea530 lib/core/data.py 7936d78b1a7f1f008ff92bf2f88574ba lib/core/datatype.py @@ -40,18 +40,18 @@ b9ff4e622c416116bee6024c0f050349 lib/core/enums.py 310efc965c862cfbd7b0da5150a5ad36 lib/core/__init__.py 9ba39bf66e9ecd469446bdbbeda906c3 lib/core/log.py ebb778c2d26eba8b34d7d8658e4105a6 lib/core/optiondict.py -dd19b4d930d418f8aef498941346ab2d lib/core/option.py +abc734ff83c51edce23ef446b7ee9c4a lib/core/option.py 5f2f56e6c5f274408df61943f1e080c0 lib/core/profiling.py 40be71cd774662a7b420caeb7051e7d5 lib/core/readlineng.py d8e9250f3775119df07e9070eddccd16 lib/core/replication.py 785f86e3f963fa3798f84286a4e83ff2 lib/core/revision.py 40c80b28b3a5819b737a5a17d4565ae9 lib/core/session.py -44b7c1ae1471b223e97e5b741ae725a2 lib/core/settings.py +7dde58404c57c693f426a3466111f2eb lib/core/settings.py d91291997d2bd2f6028aaf371bf1d3b6 lib/core/shell.py 2ad85c130cc5f2b3701ea85c2f6bbf20 lib/core/subprocessng.py -2571146b71f487a3d11867746c033e40 lib/core/target.py +92e35ddfdf0e9676dd51565bcf4fa5cf lib/core/target.py 8970b88627902239d695280b1160e16c lib/core/testing.py -ccea8b6dd69f3012b1262659bb4018d3 lib/core/threads.py +52f2ec61f7df0c4f66452ad14b4ee525 lib/core/threads.py ad74fc58fc7214802fd27067bce18dd2 lib/core/unescaper.py 1f1fa616b5b19308d78c610ec8046399 lib/core/update.py 4d13ed693401a498b6d073a2a494bd83 lib/core/wordlist.py @@ -64,47 +64,47 @@ aa89ea0c7c44eb74eaaeeccaddc94d39 lib/parse/cmdline.py 165dc27660c8559318009d44354f27cb lib/parse/html.py 310efc965c862cfbd7b0da5150a5ad36 lib/parse/__init__.py 0b010b7cdb2e42b5aa0caa59607279ad lib/parse/payloads.py -a0444cc351cd6d29015ad16d9eb46ff4 lib/parse/sitemap.py +997d0452e6fc22411f81a334511bcb3d lib/parse/sitemap.py 403d873f1d2fd0c7f73d83f104e41850 lib/request/basicauthhandler.py -0035612a620934d7ebe6d18426cfb065 lib/request/basic.py +aa8abda6eab79646b1759c0653925328 lib/request/basic.py ef48de622b0a6b4a71df64b0d2785ef8 lib/request/comparison.py -6c7aef40c0ef539a920592d97cae56b3 lib/request/connect.py +95363c8973208dd95295a23acc9674bc lib/request/connect.py fb6b788d0016ab4ec5e5f661f0f702ad lib/request/direct.py cc1163d38e9b7ee5db2adac6784c02bb lib/request/dns.py 5dcdb37823a0b5eff65cd1018bcf09e4 lib/request/httpshandler.py 310efc965c862cfbd7b0da5150a5ad36 lib/request/__init__.py -e68e1f00c7bb47b2c4ea6201995c56fb lib/request/inject.py +27abed3fa36e256508eeeea0b0bf4458 lib/request/inject.py dc1e0af84ee8eb421797d61c8cb8f172 lib/request/methodrequest.py bb9c165b050f7696b089b96b5947fac3 lib/request/pkihandler.py 602d4338a9fceaaee40c601410d8ac0b lib/request/rangehandler.py -b581e0c5e27cd927883f2c7f1705bf4e lib/request/redirecthandler.py +40719fa09d3d82b36badf981a8dc175c lib/request/redirecthandler.py 20a0e6dac2edcf98fa8c47ee9a332c28 lib/request/templates.py -36518b36ae0cf199490457916a85b367 lib/takeover/abstraction.py +992a02767d12254784f15501a7ab8dd8 lib/takeover/abstraction.py c6bc7961a186baabe0a9f5b7e0d8974b lib/takeover/icmpsh.py 310efc965c862cfbd7b0da5150a5ad36 lib/takeover/__init__.py c90c993b020a6ae0f0e497fd84f37466 lib/takeover/metasploit.py ac541a0d38e4ecb4e41e97799a7235f4 lib/takeover/registry.py -4cd0322f22fbc26284cffa9f8f7545ef lib/takeover/udf.py -affad1bb6be45ebed882a02773d08473 lib/takeover/web.py -e5a82481947e798d0c11f3acf3e9db60 lib/takeover/xp_cmdshell.py +6574edede6a96bbfa281e99dce3fecf9 lib/takeover/udf.py +e7f3012f4f9e822d39eabd934d050b0e lib/takeover/web.py +604b087dc52dbcb4c3938ad1bf63829c lib/takeover/xp_cmdshell.py 9f03972ea5ce2df74d43be5f30f068eb lib/techniques/blind/inference.py 310efc965c862cfbd7b0da5150a5ad36 lib/techniques/blind/__init__.py 310efc965c862cfbd7b0da5150a5ad36 lib/techniques/dns/__init__.py ab1601a7f429b47637c4fb8af703d0f1 lib/techniques/dns/test.py d3da4c7ceaf57c4687a052d58722f6bb lib/techniques/dns/use.py 310efc965c862cfbd7b0da5150a5ad36 lib/techniques/error/__init__.py -be752c8075641bc390368c9955f34c91 lib/techniques/error/use.py +18a23760ee5f83ab671b70be6ca3bcdb lib/techniques/error/use.py 310efc965c862cfbd7b0da5150a5ad36 lib/techniques/__init__.py 310efc965c862cfbd7b0da5150a5ad36 lib/techniques/union/__init__.py -19fd73af7a278fd72b46a5a60f5bdd09 lib/techniques/union/test.py +211e6dc49af6ad6bd3590d16d41e86db lib/techniques/union/test.py c2bf28aab749b0de30bfdeea6d09449f lib/techniques/union/use.py 67f0ad96ec2207d7e59c788b858afd6d lib/utils/api.py -ac3a32b7a84517730fa2885f4e8721ba lib/utils/brute.py -c42203069fef3b326b42b464f3aa60d3 lib/utils/crawler.py +600cbc772943f915b2d5ce6193fdff0b lib/utils/brute.py +2b6c7f906e5da25bcd8865c1f86a1dfb lib/utils/crawler.py ba12c69a90061aa14d848b8396e79191 lib/utils/deps.py 3b9fd519164e0bf275d5fd361c3f11ff lib/utils/getch.py ccfdad414ce2ec0c394c3deaa39a82bf lib/utils/hashdb.py -712ef6a703c9101690b9177b09a31b4c lib/utils/hash.py +b36465bd2a1f18e2cd97ced492f91f1f lib/utils/hash.py e76a08237ee6a4cd6855af79610ea8a5 lib/utils/htmlentities.py 310efc965c862cfbd7b0da5150a5ad36 lib/utils/__init__.py 9d8c858417d356e49e1959ba253aede4 lib/utils/pivotdumptable.py @@ -152,7 +152,7 @@ f06d263b2c9b52ea7a120593eb5806c4 plugins/dbms/informix/fingerprint.py 744fb5044f2b9f9d5ebda6e3f08e3be7 plugins/dbms/informix/takeover.py 310efc965c862cfbd7b0da5150a5ad36 plugins/dbms/__init__.py e50b624ff23c3e180d80e065deb1763f plugins/dbms/maxdb/connector.py -053aaccacb4b750472d99e5bdec62414 plugins/dbms/maxdb/enumeration.py +570ec8c20ef01d99bf23f42e32993b16 plugins/dbms/maxdb/enumeration.py 815ea8e7b9bd714d73d9d6c454aff774 plugins/dbms/maxdb/filesystem.py 017c723354eff28188773670d3837c01 plugins/dbms/maxdb/fingerprint.py c03001c1f70e76de39d26241dfcbd033 plugins/dbms/maxdb/__init__.py @@ -160,7 +160,7 @@ e6036f5b2e39aec37ba036a8cf0efd6f plugins/dbms/maxdb/syntax.py 0be362015605e26551e5d79cc83ed466 plugins/dbms/maxdb/takeover.py e3e78fab9b5eb97867699f0b20e59b62 plugins/dbms/mssqlserver/connector.py 16daf973fc7a988c3bf52435b759ff4e plugins/dbms/mssqlserver/enumeration.py -8554437c437052c30237be170ba8ce3a plugins/dbms/mssqlserver/filesystem.py +5de6074ee2f7dc5b04b70307d36dbe1d plugins/dbms/mssqlserver/filesystem.py 13cb15e8abfb05818e6f66c687b78664 plugins/dbms/mssqlserver/fingerprint.py 40bd890988f9acd3942255d687445371 plugins/dbms/mssqlserver/__init__.py 400ce654ff6bc57a40fb291322a18282 plugins/dbms/mssqlserver/syntax.py @@ -194,7 +194,7 @@ ee430d142fa8f9ee571578d0a0916679 plugins/dbms/sqlite/fingerprint.py 4827722159a89652005f49265bb55c43 plugins/dbms/sqlite/syntax.py 02ab8ff465da9dd31ffe6a963c676180 plugins/dbms/sqlite/takeover.py e3e78fab9b5eb97867699f0b20e59b62 plugins/dbms/sybase/connector.py -96698f6e6d8e9ab2020f6a0cf41255c4 plugins/dbms/sybase/enumeration.py +6bb1c376160bb0955c1f800684c83ad2 plugins/dbms/sybase/enumeration.py 62d772c7cd08275e3503304ba90c4e8a plugins/dbms/sybase/filesystem.py deed74334b637767fc9de8f74b37647a plugins/dbms/sybase/fingerprint.py 45436a42c2bb8075e1482a950d993d55 plugins/dbms/sybase/__init__.py @@ -202,17 +202,17 @@ deed74334b637767fc9de8f74b37647a plugins/dbms/sybase/fingerprint.py 654cd5e69cf5e5c644bfa5d284e61206 plugins/dbms/sybase/takeover.py be7481a96214220bcd8f51ca00239bed plugins/generic/connector.py 5390591ca955036d492de11355b52e8f plugins/generic/custom.py -944b900e7e94a478352055d15dbddfed plugins/generic/databases.py -f7387352380136ac05c0bc3decb85638 plugins/generic/entries.py +49236f38b3117b6431c6a6fd35295493 plugins/generic/databases.py +2915f49246e393c038828a73925d153c plugins/generic/entries.py 55802d1d5d65938414c77ccc27731cab plugins/generic/enumeration.py -bc32b21a3ab5421b5307ff7317256229 plugins/generic/filesystem.py +2acc2365955c0dd4cce67ab56d11baa5 plugins/generic/filesystem.py feca57a968c528a2fe3ccafbc83a17f8 plugins/generic/fingerprint.py 310efc965c862cfbd7b0da5150a5ad36 plugins/generic/__init__.py -8fd5913823e97e21a8eea717cd12fc96 plugins/generic/misc.py -43dc0abb3b1ac9eb75e1f8512f95b80e plugins/generic/search.py +6f2d127df31ca068925f614edd1ec858 plugins/generic/misc.py +5f4d46dbfae314cbd7c14ce8f424779d plugins/generic/search.py 562cfa80a15d5f7f1d52e10c5736d7e2 plugins/generic/syntax.py -25cc2788cc3da6f8a0bcff0e41ff586e plugins/generic/takeover.py -02c8da99874f1cfd869d9e3bbb7c84e6 plugins/generic/users.py +3f520f49811197f24a3f223fc995028a plugins/generic/takeover.py +ed88840a88e761c9815bec530a90aa95 plugins/generic/users.py 310efc965c862cfbd7b0da5150a5ad36 plugins/__init__.py b04db3e861edde1f9dd0a3850d5b96c8 shell/backdoor.asp_ 158bfa168128393dde8d6ed11fe9a1b8 shell/backdoor.aspx_