From 15c8f534590ae57f73e1dc1a23e0ed3f8578d8ec Mon Sep 17 00:00:00 2001 From: Gifts Date: Thu, 12 Jan 2017 15:46:40 +0300 Subject: [PATCH] Python 2.4 syntax compatibility (try-except-finally, ternary operator) Backported functions check_output and CalledProcessError Lack of ssl module is now non-blocker. Responder will start with HTTPS server disabled --- Responder.py | 11 +- packets.py | 2 +- servers/HTTP.py | 6 +- servers/HTTP_Proxy.py | 68 ++++++------ settings.py | 37 ++++++- tools/DHCP.py | 5 +- tools/MultiRelay/RelayMultiCore.py | 41 ++++--- tools/MultiRelay/RelayMultiPackets.py | 2 +- .../creddump/framework/win32/hashdump.py | 17 ++- tools/RunFinger.py | 2 +- tools/SMBFinger/Finger.py | 5 +- utils.py | 101 +++++++++++------- 12 files changed, 188 insertions(+), 109 deletions(-) diff --git a/Responder.py b/Responder.py index ed238d5..307fa29 100755 --- a/Responder.py +++ b/Responder.py @@ -15,7 +15,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . import optparse -import ssl from SocketServer import TCPServer, UDPServer, ThreadingMixIn from threading import Thread @@ -23,6 +22,12 @@ from utils import * import struct banner() +try: + import ssl +except ImportError: + ssl = False + print color("[!] Module 'ssl' is unavailable. HTTPS is disabled") + parser = optparse.OptionParser(usage='python %prog -I eth0 -w -r -f\nor:\npython %prog -I eth0 -wrf', version=settings.__version__, prog=sys.argv[0]) parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.", dest="Analyze", default=False) parser.add_option('-I','--interface', action="store", help="Network interface to use, you can use 'ALL' as a wildcard for all interfaces", dest="Interface", metavar="eth0", default=None) @@ -35,7 +40,7 @@ parser.add_option('-r', '--wredir', action="store_true", help="Enable ans parser.add_option('-d', '--NBTNSdomain', action="store_true", help="Enable answers for netbios domain suffix queries. Answering to domain suffixes will likely break stuff on the network. Default: False", dest="NBTNSDomain", default=False) parser.add_option('-f','--fingerprint', action="store_true", help="This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", dest="Finger", default=False) parser.add_option('-w','--wpad', action="store_true", help="Start the WPAD rogue proxy server. Default value is False", dest="WPAD_On_Off", default=False) -parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=None) +parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=False) parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False) parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective when combined with -r. Default: False", dest="ProxyAuth_On_Off", default=False) @@ -237,7 +242,7 @@ def main(): from servers.HTTP import HTTP threads.append(Thread(target=serve_thread_tcp, args=('', 80, HTTP,))) - if settings.Config.SSL_On_Off: + if settings.Config.SSL_On_Off and ssl: from servers.HTTP import HTTPS threads.append(Thread(target=serve_thread_SSL, args=('', 443, HTTPS,))) diff --git a/packets.py b/packets.py index 9820e26..435c35b 100644 --- a/packets.py +++ b/packets.py @@ -22,7 +22,7 @@ from odict import OrderedDict from utils import HTTPCurrentDate, RespondWithIPAton # Packet class handling all packet generation (see odict.py). -class Packet(): +class Packet: fields = OrderedDict([ ("data", ""), ]) diff --git a/servers/HTTP.py b/servers/HTTP.py index 6f170fc..85508d5 100644 --- a/servers/HTTP.py +++ b/servers/HTTP.py @@ -144,8 +144,10 @@ def ServeOPTIONS(data): return False def ServeFile(Filename): - with open (Filename, "rb") as bk: - return bk.read() + bk = open(Filename, "rb") + data = bk.read() + bk.close() + return data def RespondWithFile(client, filename, dlname=None): diff --git a/servers/HTTP_Proxy.py b/servers/HTTP_Proxy.py index 71e6e75..9ab73af 100644 --- a/servers/HTTP_Proxy.py +++ b/servers/HTTP_Proxy.py @@ -236,17 +236,17 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: - if self._connect_to(self.path, soc): - self.wfile.write(self.protocol_version +" 200 Connection established\r\n") - self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) - self.wfile.write("\r\n") - try: - self._read_write(soc, 300) - except: - pass - except: - pass - + try: + if self._connect_to(self.path, soc): + self.wfile.write(self.protocol_version +" 200 Connection established\r\n") + self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) + self.wfile.write("\r\n") + try: + self._read_write(soc, 300) + except: + pass + except: + pass finally: soc.close() self.connection.close() @@ -266,36 +266,36 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler): soc = self.socket_proxy(socket.AF_INET, socket.SOCK_STREAM) else: soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - URL_Unparse = urlparse.urlunparse(('', '', path, params, query, '')) + try: + URL_Unparse = urlparse.urlunparse(('', '', path, params, query, '')) - if self._connect_to(netloc, soc): - soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)) + if self._connect_to(netloc, soc): + soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)) - Cookie = self.headers['Cookie'] if "Cookie" in self.headers else '' + Cookie = self.headers.get('Cookie', '') - if settings.Config.Verbose: - print text("[PROXY] Client : %s" % color(self.client_address[0], 3)) - print text("[PROXY] Requested URL : %s" % color(self.path, 3)) - print text("[PROXY] Cookie : %s" % Cookie) + if settings.Config.Verbose: + print text("[PROXY] Client : %s" % color(self.client_address[0], 3)) + print text("[PROXY] Requested URL : %s" % color(self.path, 3)) + print text("[PROXY] Cookie : %s" % Cookie) - self.headers['Connection'] = 'close' - del self.headers['Proxy-Connection'] - del self.headers['If-Range'] - del self.headers['Range'] - - for k, v in self.headers.items(): - soc.send("%s: %s\r\n" % (k.title(), v)) - soc.send("\r\n") + self.headers['Connection'] = 'close' + del self.headers['Proxy-Connection'] + del self.headers['If-Range'] + del self.headers['Range'] - try: - self._read_write(soc, netloc) - except: - pass + for k, v in self.headers.items(): + soc.send("%s: %s\r\n" % (k.title(), v)) + soc.send("\r\n") - except: - pass + try: + self._read_write(soc, netloc) + except: + pass + + except: + pass finally: soc.close() diff --git a/settings.py b/settings.py index e02dff9..abed838 100644 --- a/settings.py +++ b/settings.py @@ -22,6 +22,35 @@ from utils import * __version__ = 'Responder 2.3.3.2' +# Backport (monkeypatch) check_output and CalledProcessError +if not hasattr(subprocess, 'CalledProcessError'): + class CalledProcessError(Exception): + def __init__(self, returncode, cmd, output=None): + self.returncode = returncode + self.cmd = cmd + self.output = output + + def __str__(self): + return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) + + subprocess.CalledProcessError = CalledProcessError + +if not hasattr(subprocess, 'check_output'): + def check_output(*popenargs, **kwargs): + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise subprocess.CalledProcessError(retcode, cmd, output=output) + return output + + subprocess.check_output = check_output + class Settings: def __init__(self): @@ -229,17 +258,17 @@ class Settings: try: NetworkCard = subprocess.check_output(["ifconfig", "-a"]) - except subprocess.CalledProcessError as ex: + except Exception,ex: NetworkCard = "Error fetching Network Interfaces:", ex pass try: DNS = subprocess.check_output(["cat", "/etc/resolv.conf"]) - except subprocess.CalledProcessError as ex: + except subprocess.CalledProcessError,ex: DNS = "Error fetching DNS configuration:", ex pass try: RoutingInfo = subprocess.check_output(["netstat", "-rn"]) - except subprocess.CalledProcessError as ex: + except subprocess.CalledProcessError,ex: RoutingInfo = "Error fetching Routing information:", ex pass @@ -247,7 +276,7 @@ class Settings: try: utils.DumpConfig(self.ResponderConfigDump, Message) utils.DumpConfig(self.ResponderConfigDump,str(self)) - except AttributeError as ex: + except AttributeError, ex: print "Missing Module:", ex pass diff --git a/tools/DHCP.py b/tools/DHCP.py index 20f02b0..f02c124 100755 --- a/tools/DHCP.py +++ b/tools/DHCP.py @@ -222,7 +222,10 @@ class DHCPInformACK(Packet): self.fields["Op252Len"] = struct.pack(">b",len(str(self.fields["Op252Str"]))) def SpoofIP(Spoof): - return ROUTERIP if Spoof else Responder_IP + if Spoof: + return ROUTERIP + else: + return Responder_IP def RespondToThisIP(ClientIp): if ClientIp.startswith('127.0.0.'): diff --git a/tools/MultiRelay/RelayMultiCore.py b/tools/MultiRelay/RelayMultiCore.py index 20ccfdb..fc5008a 100644 --- a/tools/MultiRelay/RelayMultiCore.py +++ b/tools/MultiRelay/RelayMultiCore.py @@ -39,7 +39,7 @@ def longueur(payload): length = struct.pack(">i", len(''.join(payload))) return length -class Packet(): +class Packet: fields = OrderedDict([ ("data", ""), ]) @@ -55,22 +55,30 @@ class Packet(): # Function used to write captured hashs to a file. def WriteData(outfile, data, user): - if not os.path.isfile(outfile): - with open(outfile,"w") as outf: - outf.write(data + '\n') - return - with open(outfile,"r") as filestr: - if re.search(user.encode('hex'), filestr.read().encode('hex')): - return False - elif re.search(re.escape("$"), user): - return False - with open(outfile,"a") as outf2: - outf2.write(data + '\n') + if not os.path.isfile(outfile): + outf = open(outfile,"w") + outf.write(data + '\n') + outf.close() + return + + filestr = open(outfile,"r") + try: + if re.search(user.encode('hex'), filestr.read().encode('hex')): + return False + elif re.search(re.escape("$"), user): + return False + finally: + filestr.close() + + outf2 = open(outfile,"a") + outf2.write(data + '\n') + outf2.close() #Function used to verify if a previous auth attempt was made. def ReadData(Outfile, Client, User, Domain, Target, cmd): try: - with open(Logs_Path+"logs/"+Outfile,"r") as filestr: + filestr = open(Logs_Path+"logs/"+Outfile,"r") + try: Login = Client+":"+User+":"+Domain+":"+Target+":Logon Failure" if re.search(Login.encode('hex'), filestr.read().encode('hex')): print "[+] User %s\\%s previous login attempt returned logon_failure. Not forwarding anymore to prevent account lockout\n"%(Domain,User) @@ -78,6 +86,8 @@ def ReadData(Outfile, Client, User, Domain, Target, cmd): else: return False + finally: + filestr.close() except: raise @@ -267,8 +277,9 @@ def GetReadableSize(size,precision=2): return "%.*f%s"%(precision,size,suffixes[suffixIndex]) def WriteOutputToFile(data, File): - with open(SaveSam_Path+"/"+File, "wb") as file: - file.write(data) + file = open(SaveSam_Path+"/"+File, "wb") + file.write(data) + file.close() ##This function is one of the main SMB read function. We request all the time 65520 bytes to the server. #Add (+32 (SMBHeader) +4 Netbios Session Header + 27 for the ReadAndx structure) +63 and you end up with 65583. diff --git a/tools/MultiRelay/RelayMultiPackets.py b/tools/MultiRelay/RelayMultiPackets.py index cedcaaf..0e25134 100644 --- a/tools/MultiRelay/RelayMultiPackets.py +++ b/tools/MultiRelay/RelayMultiPackets.py @@ -20,7 +20,7 @@ from odict import OrderedDict import datetime from base64 import b64decode, b64encode -class Packet(): +class Packet: fields = OrderedDict([ ("data", ""), ]) diff --git a/tools/MultiRelay/creddump/framework/win32/hashdump.py b/tools/MultiRelay/creddump/framework/win32/hashdump.py index 6acc808..59d4543 100644 --- a/tools/MultiRelay/creddump/framework/win32/hashdump.py +++ b/tools/MultiRelay/creddump/framework/win32/hashdump.py @@ -176,11 +176,20 @@ def get_user_hashes(user_key, hbootkey): hash_offset = unpack("