From d2a9c7584fd4479f98a97d005812a4bf6d5a6037 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 31 Aug 2015 09:51:35 +0200 Subject: [PATCH 01/12] Minor patch --- lib/core/target.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/target.py b/lib/core/target.py index 50158817a..983d54541 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -223,11 +223,11 @@ def _setRequestParams(): message += "in the target URL itself? [Y/n/q] " test = readInput(message, default="Y") - if not test or test[0] not in ("n", "N"): + if test and test[0] in ("q", "Q"): + raise SqlmapUserQuitException + elif not test or test[0] not in ("n", "N"): conf.url = "%s%s" % (conf.url, CUSTOM_INJECTION_MARK_CHAR) kb.processUserMarks = True - elif test[0] in ("q", "Q"): - raise SqlmapUserQuitException for place, value in ((PLACE.URI, conf.url), (PLACE.CUSTOM_POST, conf.data), (PLACE.CUSTOM_HEADER, str(conf.httpHeaders))): _ = re.sub(PROBLEMATIC_CUSTOM_INJECTION_PATTERNS, "", value or "") if place == PLACE.CUSTOM_HEADER else value or "" From d70215ad6c39e6dfe2810e8c6d244f22f0c46519 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 31 Aug 2015 10:24:05 +0200 Subject: [PATCH 02/12] Fixes #1237 --- lib/core/settings.py | 6 +++ lib/utils/google.py | 100 +++++++++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/lib/core/settings.py b/lib/core/settings.py index 2457770d1..2989907ea 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -75,6 +75,12 @@ GOOGLE_REGEX = r"url\?\w+=((?![^>]+webcache\.googleusercontent\.com)http[^>]+)&( # Regular expression used for extracting results from DuckDuckGo search DUCKDUCKGO_REGEX = r'"u":"([^"]+)' +# Regular expression used for extracting results from Disconnect Search +DISCONNECT_SEARCH_REGEX = r'

([^<]+)

' + +# Dummy user agent for search (if default one returns different results) +DUMMY_SEARCH_USER_AGENT = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:40.0) Gecko/20100101 Firefox/40.0" + # Regular expression used for extracting content from "textual" tags TEXT_TAG_REGEX = r"(?si)<(abbr|acronym|b|blockquote|br|center|cite|code|dt|em|font|h\d|i|li|p|pre|q|strong|sub|sup|td|th|title|tt|u)(?!\w).*?>(?P[^<]+)" diff --git a/lib/utils/google.py b/lib/utils/google.py index e0f4b08bd..faac0f751 100644 --- a/lib/utils/google.py +++ b/lib/utils/google.py @@ -21,8 +21,11 @@ from lib.core.enums import CUSTOM_LOGGING from lib.core.enums import HTTP_HEADER from lib.core.exception import SqlmapConnectionException from lib.core.exception import SqlmapGenericException -from lib.core.settings import GOOGLE_REGEX +from lib.core.exception import SqlmapUserQuitException +from lib.core.settings import DUMMY_SEARCH_USER_AGENT from lib.core.settings import DUCKDUCKGO_REGEX +from lib.core.settings import DISCONNECT_SEARCH_REGEX +from lib.core.settings import GOOGLE_REGEX from lib.core.settings import HTTP_ACCEPT_ENCODING_HEADER_VALUE from lib.core.settings import UNICODE_ENCODING from lib.request.basic import decodePage @@ -108,54 +111,67 @@ class Google(object): raise SqlmapGenericException(warnMsg) if not retVal: - message = "no usable links found. " - message += "do you want to (re)try with DuckDuckGo? [Y/n] " - output = readInput(message, default="Y") + message = "no usable links found. What do you want to do?" + message += "\n[1] (re)try with DuckDuckGo (default)" + message += "\n[2] (re)try with Disconnect Search" + message += "\n[3] quit" + choice = readInput(message, default="1").strip().upper() - if output.strip().lower() != 'n': + if choice == "Q": + raise SqlmapUserQuitException + elif choice == "2": + url = "https://search.disconnect.me/searchTerms/search?" + url += "start=nav&option=Web" + url += "&query=%s" % urlencode(dork, convall=True) + url += "&ses=Google&location_option=US" + url += "&nextDDG=%s" % urlencode("/search?q=&num=100&hl=en&start=%d&sa=N" % ((gpage - 1) * 10), convall=True) + url += "&sa=N&showIcons=false&filterIcons=none&js_enabled=1" + regex = DISCONNECT_SEARCH_REGEX + else: url = "https://duckduckgo.com/d.js?" url += "q=%s&p=%d&s=100" % (urlencode(dork, convall=True), gpage) + regex = DUCKDUCKGO_REGEX - if not conf.randomAgent: - self.opener.addheaders = [_ for _ in self.opener.addheaders if _[0].lower() != HTTP_HEADER.USER_AGENT.lower()] - self.opener.addheaders.append((HTTP_HEADER.USER_AGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0")) + if not conf.randomAgent: + self.opener.addheaders = [_ for _ in self.opener.addheaders if _[0].lower() != HTTP_HEADER.USER_AGENT.lower()] + self.opener.addheaders.append((HTTP_HEADER.USER_AGENT, DUMMY_SEARCH_USER_AGENT)) - self.opener.addheaders = [_ for _ in self.opener.addheaders if _[0].lower() != HTTP_HEADER.ACCEPT_ENCODING.lower()] - self.opener.addheaders.append((HTTP_HEADER.ACCEPT_ENCODING, HTTP_ACCEPT_ENCODING_HEADER_VALUE)) + self.opener.addheaders = [_ for _ in self.opener.addheaders if _[0].lower() != HTTP_HEADER.ACCEPT_ENCODING.lower()] + self.opener.addheaders.append((HTTP_HEADER.ACCEPT_ENCODING, HTTP_ACCEPT_ENCODING_HEADER_VALUE)) + try: + conn = self.opener.open(url) + + requestMsg = "HTTP request:\nGET %s" % url + requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str + logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) + + page = conn.read() + code = conn.code + status = conn.msg + responseHeaders = conn.info() + page = decodePage(page, responseHeaders.get("Content-Encoding"), responseHeaders.get("Content-Type")) + + responseMsg = "HTTP response (%s - %d):\n" % (status, code) + + if conf.verbose <= 4: + responseMsg += getUnicode(responseHeaders, UNICODE_ENCODING) + elif conf.verbose > 4: + responseMsg += "%s\n%s\n" % (responseHeaders, page) + + logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) + except urllib2.HTTPError, e: try: - conn = self.opener.open(url) + page = e.read() + except socket.timeout: + warnMsg = "connection timed out while trying " + warnMsg += "to get error page information (%d)" % e.code + logger.critical(warnMsg) + return None + except: + errMsg = "unable to connect" + raise SqlmapConnectionException(errMsg) - requestMsg = "HTTP request:\nGET %s" % url - requestMsg += " %s" % httplib.HTTPConnection._http_vsn_str - logger.log(CUSTOM_LOGGING.TRAFFIC_OUT, requestMsg) - - page = conn.read() - code = conn.code - status = conn.msg - responseHeaders = conn.info() - page = decodePage(page, responseHeaders.get("Content-Encoding"), responseHeaders.get("Content-Type")) - - responseMsg = "HTTP response (%s - %d):\n" % (status, code) - - if conf.verbose <= 4: - responseMsg += getUnicode(responseHeaders, UNICODE_ENCODING) - elif conf.verbose > 4: - responseMsg += "%s\n%s\n" % (responseHeaders, page) - - logger.log(CUSTOM_LOGGING.TRAFFIC_IN, responseMsg) - except urllib2.HTTPError, e: - try: - page = e.read() - except socket.timeout: - warnMsg = "connection timed out while trying " - warnMsg += "to get error page information (%d)" % e.code - logger.critical(warnMsg) - return None - except: - errMsg = "unable to connect to DuckDuckGo" - raise SqlmapConnectionException(errMsg) - - retVal = [urllib.unquote(match.group(1)) for match in re.finditer(DUCKDUCKGO_REGEX, page, re.I | re.S)] + retVal = [urllib.unquote(match.group(1)) for match in re.finditer(regex, page, re.I | re.S)] return retVal From 265a78b455e7e1d234d7332860e18688b8daa5c5 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 31 Aug 2015 14:27:47 +0200 Subject: [PATCH 03/12] Fixes #1379 --- extra/cloak/cloak.py | 20 ++++++++++-------- .../windows/shellcodeexec.x32.exe_ | Bin 2972 -> 2758 bytes lib/core/settings.py | 3 +++ lib/takeover/metasploit.py | 12 +++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/extra/cloak/cloak.py b/extra/cloak/cloak.py index a94f6756f..9f220088a 100755 --- a/extra/cloak/cloak.py +++ b/extra/cloak/cloak.py @@ -24,18 +24,20 @@ def hideAscii(data): return retVal -def cloak(inputFile): - f = open(inputFile, 'rb') - data = zlib.compress(f.read()) - f.close() +def cloak(inputFile=None, data=None): + if data is None: + with open(inputFile, "rb") as f: + data = f.read() - return hideAscii(data) + return hideAscii(zlib.compress(data)) -def decloak(inputFile): - f = open(inputFile, 'rb') +def decloak(inputFile=None, data=None): + if data is None: + with open(inputFile, "rb") as f: + data = f.read() try: - data = zlib.decompress(hideAscii(f.read())) - except: + data = zlib.decompress(hideAscii(data)) + except Exception: print 'ERROR: the provided input file \'%s\' does not contain valid cloaked content' % inputFile sys.exit(1) finally: diff --git a/extra/shellcodeexec/windows/shellcodeexec.x32.exe_ b/extra/shellcodeexec/windows/shellcodeexec.x32.exe_ index 4d699f1237a7e9a93f6e1a8417afe2bf2a311ed7..c4204cce6a9c8a12e850cd70436a0ec5b650ab7b 100644 GIT binary patch literal 2758 zcmV;%3OV%$ob6{46C~C3MGlJdCJ2iby29!OiPWu-S-2TiHbof8RIN89=d*US3S;|5 z&#wLKy^oMLIuzv@ss?b!+krQx=XDoq!Tog%o&?WE_uLH5z31FR2;2aYYi&J@f0{WrlH{6`{P&iAsMz!k zdIquhjmg)5p2HIm*OO$0Zgp`nDU+v4#nSQJVOAjNEi)>z0n79p-BJXWwI8_%RjjvqV zA>1=Jldkdx!~bvOo3v)@ht7BAPy>tut;CKsfV(rgK3c1txUL&@p3Fyf9;^kLH z;6e0%>z5Bk&RW%Fp3l3}{m^qP9F`GM=(T$+WRWdlSv^Ycp*}^`(E$t5XEp&`&p~d$f!;M5B~Ivpl@T+Qwp%Y zPEryVLs*;aC$ARUj9nr16vkINX6;?o-GO zuRW*Ef$@BN<5m{E?gwpQehuYNXH|!LN#?Z@efmb?P*_gL>VXdKQysYo+{dyncDj4uFOekoIR=O7IXegCvlM)}c*c zdHkEM{N*DnGc^vp9M09L5j@{{@XTu&jy2og(&Z3-`NybI=z_dCvqN@F-NQC(Dz}3k z7XPsstU_Y=2i*2s^P5aX#+=#PVA@<&Q55L^v*ykD{7Bita;y z=&4|9ovg=$UWwytWNcV}Fi)n$97kZEB-XU)qGqtne*lxnGh>I@3(;5f#W|9iQAItu zkUE$m@$odU8`3w2mma7l5qubJ=Yelas9l~#mV8tp$MY$SK1vxX^9E&TY{=|9W^oD> zmQuN@4tSt+7Om!MVLMvakGZyY1Ql^ZdBtu$IY)UkO5`Aqh7{v4w!rG~YS z!7?%D<=d)_%I>DZ^AsQzsqF3~`_c&3*#A!f3jaHssTJg_%8}|d8VDxiN}(s|NNWD6 z@gO}W?2KNP+R{f@zUV1>eE{s8saC3z88Z)<1Dtm{qFH1Zk-UY_hr9p~&q!TKf z)hz0!rJ2~AULdcnCw5;(>}Z;yAEpgiuCCq{aMld1=6hj2%?|1c?uF1}wEDLyo8zGs z^LxP7xs}HqW?^&(TuVlDFp{oP&Ks}4VCmJ*J?7hz5n#yx1Fy`F~5TUrZnZ_ z7O4joS%EgPPuNJo8{vvb9=VX0?F}ijl;K>N(Nh^>C@pg#fFo*Br0?08j6&16Ti^29 zLD0M}MgFb>iwzMK&Lf(ML=W$!*|>a2N8|y2Os9uA@_+4k7Vo11l=f}yIHCWd0-oAd zWM02|M|e*weBU{LGJi>cb%1jNsJ(WOeFtIS`+whjh<%LK=taJH-(i2Re$0RTa^PD( zX`p}P%zr9>Nr3Ht1b%sbj(^{9&~VUk;Cr}q;ADR(e@w1;2Y3^kx2@RRbJ>*;?*LXv z#>abLncbgTXRzM7M)zywWV8Opq9)?O_?EuvowZgdUL-Ot`&9&Iocwksjji_c^5^fsn*? z@KB4}V&Hsj%a4$feMNf>n3S%J-BbB#7m4uxz_2@Vdz(UDmLq|+T~x_kcLrOIYI{A_ zfl9uhQ#BF4P)~jLcpIV-Ct}7RF<;)fxj;yCgEG8mhVB@>bYAxJ^rX9TN|+-aO%K9CtytKdUC^4 z`L(e`#Ii088cMfHZH@(d_PTF2W&~d?4^M6DZCxQLdjeL&y{yz#bbZS-2I63iy#vlo z+g?;0drO^w5kbsz7Z zfcH;YZ}R$8Bn?OoaNNbIk0p2HP9xhwSv3>5SZ^65JFtMo(ajap7}W5;iXak4-KObs z>vPt>{xHz~&rt)>L4}t4R?t82ICy}gV5Z}psJnh*L9*zZ+wWVXbcE*h-)oygqR57a zJsj524~S@+60*SGTm?o+>~8OKc)UG3jQFKQp%L8UZo{=)^+{CZDZtN)EnrlLkdn=| z`r1X?&hl-mwaLdhCf<0Z5sc0#E~IG!V4Z%f{LTcBVvxqHCwQ9@aCry&B1u&5cEhAx z5IzzhRJ?qxB0@>)Hv!*<+PWn;-Q5a+68IEJrV~3CZoFgE2CrLmpdYm15#Y%@p@8>6 z39NWEVP)+1NpsnU2?y%g`gztt8{65m?ZejOV%P~Ba4G22*Om1|B2uoFwzfh9@9po` Mc%R1nKvYM|*Jm_pTL1t6 literal 2972 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 S_O`b4;M)B2&HsArmJnxle8h_Y diff --git a/lib/core/settings.py b/lib/core/settings.py index 2989907ea..303c10cf4 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -443,6 +443,9 @@ BRUTE_COLUMN_EXISTS_TEMPLATE = "EXISTS(SELECT %s FROM %s)" # Payload used for checking of existence of IDS/WAF (dummier the better) IDS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,2,3,table_name FROM information_schema.tables WHERE 2>1-- ../../../etc/passwd" +# Data inside shellcodeexec to be filled with random string +SHELLCODEEXEC_RANDOM_STRING_MARKER = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + # Vectors used for provoking specific WAF/IDS/IPS behavior(s) WAF_ATTACK_VECTORS = ( "", # NIL diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index 8717b6c73..8befc81ca 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -8,10 +8,13 @@ See the file 'doc/COPYING' for copying permission import os import re import sys +import tempfile import time from subprocess import PIPE +from extra.cloak.cloak import cloak +from extra.cloak.cloak import decloak from lib.core.common import dataToStdout from lib.core.common import Backend from lib.core.common import getLocalIP @@ -34,6 +37,7 @@ from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapGenericException from lib.core.settings import IS_WIN from lib.core.settings import METASPLOIT_SESSION_TIMEOUT +from lib.core.settings import SHELLCODEEXEC_RANDOM_STRING_MARKER from lib.core.settings import UNICODE_ENCODING from lib.core.subprocessng import blockingReadFromFD from lib.core.subprocessng import blockingWriteToFD @@ -640,6 +644,14 @@ class Metasploit: if Backend.isOs(OS.WINDOWS): self.shellcodeexecLocal = os.path.join(self.shellcodeexecLocal, "windows", "shellcodeexec.x%s.exe_" % "32") + content = decloak(self.shellcodeexecLocal) + if SHELLCODEEXEC_RANDOM_STRING_MARKER in content: + content = content.replace(SHELLCODEEXEC_RANDOM_STRING_MARKER, randomStr(len(SHELLCODEEXEC_RANDOM_STRING_MARKER))) + _ = cloak(data=content) + handle, self.shellcodeexecLocal = tempfile.mkstemp(suffix="%s.exe_" % "32") + os.close(handle) + with open(self.shellcodeexecLocal, "w+b") as f: + f.write(_) else: self.shellcodeexecLocal = os.path.join(self.shellcodeexecLocal, "linux", "shellcodeexec.x%s_" % Backend.getArch()) From 401564898df95945eb1216cd92586a712e70c5fd Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 31 Aug 2015 14:43:41 +0200 Subject: [PATCH 04/12] Adding support for 'empty' POST body (if forced by --method) --- lib/core/target.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/target.py b/lib/core/target.py index 983d54541..cdfd538f0 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -92,8 +92,8 @@ def _setRequestParams(): # Perform checks on POST parameters if conf.method == HTTPMETHOD.POST and conf.data is None: - errMsg = "HTTP POST method depends on HTTP data value to be posted" - raise SqlmapSyntaxException(errMsg) + logger.warn("detected empty POST body") + conf.data = "" if conf.data is not None: conf.method = HTTPMETHOD.POST if not conf.method or conf.method == HTTPMETHOD.GET else conf.method From fb5a75c9ada7b5b289922492d27e28576a361286 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Mon, 31 Aug 2015 14:50:51 +0200 Subject: [PATCH 05/12] Removing leftover --- extra/cloak/cloak.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/cloak/cloak.py b/extra/cloak/cloak.py index 9f220088a..5e7d3c6c6 100755 --- a/extra/cloak/cloak.py +++ b/extra/cloak/cloak.py @@ -37,7 +37,7 @@ def decloak(inputFile=None, data=None): data = f.read() try: data = zlib.decompress(hideAscii(data)) - except Exception: + except: print 'ERROR: the provided input file \'%s\' does not contain valid cloaked content' % inputFile sys.exit(1) finally: From 7511023bc215cdcd11d747d445d77e8be6214473 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 3 Sep 2015 10:11:36 +0200 Subject: [PATCH 06/12] Fixes #1385 --- lib/core/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.py b/lib/core/common.py index 9aada65ed..556865764 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -3556,7 +3556,7 @@ def findPageForms(content, url, raise_=False, addToTargets=False): for form in forms: try: for control in form.controls: - if hasattr(control, "items") and not control.disabled: + if hasattr(control, "items") and not any((control.disabled, control.readonly)): # if control has selectable items select first non-disabled for item in control.items: if not item.disabled: From 69563fc24fb573883b2a114357cd2707114c927f Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 3 Sep 2015 10:18:00 +0200 Subject: [PATCH 07/12] Language fix --- plugins/generic/filesystem.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index 21b698b4e..5052aa736 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -70,13 +70,13 @@ class Filesystem: if localFileSize == remoteFileSize: sameFile = True infoMsg = "the local file %s and the remote file " % localFile - infoMsg += "%s have the same size (%db)" % (remoteFile, localFileSize) + infoMsg += "%s have the same size (%dB)" % (remoteFile, localFileSize) elif remoteFileSize > localFileSize: - infoMsg = "the remote file %s is larger (%db) than " % (remoteFile, remoteFileSize) - infoMsg += "the local file %s (%db)" % (localFile, localFileSize) + infoMsg = "the remote file %s is larger (%dB) than " % (remoteFile, remoteFileSize) + infoMsg += "the local file %s (%dB)" % (localFile, localFileSize) else: - infoMsg = "the remote file %s is smaller (%db) than " % (remoteFile, remoteFileSize) - infoMsg += "file %s (%db)" % (localFile, localFileSize) + infoMsg = "the remote file %s is smaller (%dB) than " % (remoteFile, remoteFileSize) + infoMsg += "file %s (%dB)" % (localFile, localFileSize) logger.info(infoMsg) else: From 41c21ab7f2c2e6654576362c84df13ff2d1c7a70 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 3 Sep 2015 10:19:59 +0200 Subject: [PATCH 08/12] Minor consistency patch --- plugins/generic/filesystem.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index 5052aa736..579998016 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -55,10 +55,10 @@ class Filesystem: localFileSize = os.path.getsize(localFile) if fileRead and Backend.isDbms(DBMS.PGSQL): - logger.info("length of read file %s cannot be checked on PostgreSQL" % remoteFile) + logger.info("length of read file '%s' cannot be checked on PostgreSQL" % remoteFile) sameFile = True else: - logger.debug("checking the length of the remote file %s" % remoteFile) + logger.debug("checking the length of the remote file '%s'" % remoteFile) remoteFileSize = inject.getValue(lengthQuery, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) sameFile = None @@ -69,14 +69,14 @@ class Filesystem: if localFileSize == remoteFileSize: sameFile = True - infoMsg = "the local file %s and the remote file " % localFile - infoMsg += "%s have the same size (%dB)" % (remoteFile, localFileSize) + infoMsg = "the local file '%s' and the remote file " % localFile + infoMsg += "'%s' have the same size (%dB)" % (remoteFile, localFileSize) elif remoteFileSize > localFileSize: - infoMsg = "the remote file %s is larger (%dB) than " % (remoteFile, remoteFileSize) - infoMsg += "the local file %s (%dB)" % (localFile, localFileSize) + infoMsg = "the remote file '%s' is larger (%dB) than " % (remoteFile, remoteFileSize) + infoMsg += "the local file '%s' (%dB)" % (localFile, localFileSize) else: - infoMsg = "the remote file %s is smaller (%dB) than " % (remoteFile, remoteFileSize) - infoMsg += "file %s (%dB)" % (localFile, localFileSize) + infoMsg = "the remote file '%s' is smaller (%dB) than " % (remoteFile, remoteFileSize) + infoMsg += "file '%s' (%dB)" % (localFile, localFileSize) logger.info(infoMsg) else: @@ -153,7 +153,7 @@ class Filesystem: 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 + message += "file system ('%s')? [Y/n] " % remoteFile output = readInput(message, default="Y") if forceCheck or (output and output.lower() == "y"): @@ -276,14 +276,14 @@ class Filesystem: if conf.direct or isStackingAvailable(): if isStackingAvailable(): - debugMsg = "going to upload the %s file with " % fileType + debugMsg = "going to upload the file '%s' with " % fileType debugMsg += "stacked query SQL injection technique" logger.debug(debugMsg) written = self.stackedWriteFile(localFile, remoteFile, fileType, forceCheck) self.cleanup(onlyFileTbl=True) elif isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and Backend.isDbms(DBMS.MYSQL): - debugMsg = "going to upload the %s file with " % fileType + debugMsg = "going to upload the file '%s' with " % fileType debugMsg += "UNION query SQL injection technique" logger.debug(debugMsg) From 51a4cb04a578258da037f12440dc00a16fe5885a Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 3 Sep 2015 10:26:46 +0200 Subject: [PATCH 09/12] Another minor language patch --- lib/takeover/icmpsh.py | 4 ++-- lib/takeover/metasploit.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/takeover/icmpsh.py b/lib/takeover/icmpsh.py index 35cfe9881..da64a7b4e 100644 --- a/lib/takeover/icmpsh.py +++ b/lib/takeover/icmpsh.py @@ -32,13 +32,13 @@ class ICMPsh: self._icmpslave = normalizePath(os.path.join(paths.SQLMAP_EXTRAS_PATH, "icmpsh", "icmpsh.exe_")) def _selectRhost(self): - message = "what is the back-end DBMS address? [%s] " % self.remoteIP + message = "what is the back-end DBMS address? [Enter for '%s' (detected)] " % self.remoteIP address = readInput(message, default=self.remoteIP) return address def _selectLhost(self): - message = "what is the local address? [%s] " % self.localIP + message = "what is the local address? [Enter for '%s' (detected)] " % self.localIP address = readInput(message, default=self.localIP) return address diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index 8befc81ca..10d3a3022 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -292,7 +292,7 @@ class Metasploit: def _selectRhost(self): if self.connectionStr.startswith("bind"): - message = "what is the back-end DBMS address? [%s] " % self.remoteIP + message = "what is the back-end DBMS address? [Enter for '%s' (detected)] " % self.remoteIP address = readInput(message, default=self.remoteIP) if not address: @@ -308,7 +308,7 @@ class Metasploit: def _selectLhost(self): if self.connectionStr.startswith("reverse"): - message = "what is the local address? [%s] " % self.localIP + message = "what is the local address? [Enter for '%s' (detected)] " % self.localIP address = readInput(message, default=self.localIP) if not address: From d06646e4120a345cfd1976f6e99d6bd7de35fbd3 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 3 Sep 2015 10:32:22 +0200 Subject: [PATCH 10/12] Miniscule change --- plugins/generic/filesystem.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index 579998016..30daccdc1 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -70,13 +70,13 @@ class Filesystem: if localFileSize == remoteFileSize: sameFile = True infoMsg = "the local file '%s' and the remote file " % localFile - infoMsg += "'%s' have the same size (%dB)" % (remoteFile, localFileSize) + infoMsg += "'%s' have the same size (%d B)" % (remoteFile, localFileSize) elif remoteFileSize > localFileSize: - infoMsg = "the remote file '%s' is larger (%dB) than " % (remoteFile, remoteFileSize) + infoMsg = "the remote file '%s' is larger (%d B) than " % (remoteFile, remoteFileSize) infoMsg += "the local file '%s' (%dB)" % (localFile, localFileSize) else: - infoMsg = "the remote file '%s' is smaller (%dB) than " % (remoteFile, remoteFileSize) - infoMsg += "file '%s' (%dB)" % (localFile, localFileSize) + infoMsg = "the remote file '%s' is smaller (%d B) than " % (remoteFile, remoteFileSize) + infoMsg += "file '%s' (%d B)" % (localFile, localFileSize) logger.info(infoMsg) else: From aee4c93c8b0ca9299134c65700675f8222e8a4d5 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Thu, 3 Sep 2015 10:32:45 +0200 Subject: [PATCH 11/12] Fixes #1384 --- lib/takeover/icmpsh.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/takeover/icmpsh.py b/lib/takeover/icmpsh.py index da64a7b4e..2e5d3253c 100644 --- a/lib/takeover/icmpsh.py +++ b/lib/takeover/icmpsh.py @@ -32,14 +32,26 @@ class ICMPsh: self._icmpslave = normalizePath(os.path.join(paths.SQLMAP_EXTRAS_PATH, "icmpsh", "icmpsh.exe_")) def _selectRhost(self): - message = "what is the back-end DBMS address? [Enter for '%s' (detected)] " % self.remoteIP - address = readInput(message, default=self.remoteIP) + address = None + message = "what is the back-end DBMS address? " + + if self.remoteIP: + message += "[Enter for '%s' (detected)] " % self.remoteIP + + while not address: + address = readInput(message, default=self.remoteIP) return address def _selectLhost(self): - message = "what is the local address? [Enter for '%s' (detected)] " % self.localIP - address = readInput(message, default=self.localIP) + address = None + message = "what is the local address? " + + if self.localIP: + message += "[Enter for '%s' (detected)] " % self.localIP + + while not address: + address = readInput(message, default=self.localIP) return address From 28a60f5be255c6b6a1b05e981eb1ce9d8d10cbf0 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 6 Sep 2015 20:22:07 +0200 Subject: [PATCH 12/12] Fixes #1391 --- lib/utils/google.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/google.py b/lib/utils/google.py index faac0f751..800f366e8 100644 --- a/lib/utils/google.py +++ b/lib/utils/google.py @@ -99,7 +99,7 @@ class Google(object): warnMsg += "to get error page information (%d)" % e.code logger.critical(warnMsg) return None - except (urllib2.URLError, socket.error, socket.timeout): + except (urllib2.URLError, httplib.error, socket.error, socket.timeout): errMsg = "unable to connect to Google" raise SqlmapConnectionException(errMsg)