def lin_set_ip_address(self, dev, ip, serverip, netmask): sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: # set IP ifr = struct.pack('<16sH2s4s8s', dev, socket.AF_INET, "\x00" * 2, socket.inet_aton(ip), "\x00" * 8) fcntl.ioctl(sockfd, self.IOCTL_LINUX_SIOCSIFADDR, ifr) # get flags ifr = struct.pack('<16sh', dev, 0) flags = struct.unpack( '<16sh', fcntl.ioctl(sockfd, self.IOCTL_LINUX_SIOCSIFFLAGS, ifr))[1] # set new flags flags = flags | self.IOCTL_LINUX_IFF_UP ifr = struct.pack('<16sh', dev, flags) # iface up fcntl.ioctl(sockfd, self.IOCTL_LINUX_SIOCSIFFLAGS, ifr) except Exception as e: common.internal_print( "Something went wrong with setting up the interface.", -1) print(e) sys.exit(-1) # adding new route for forwarding packets properly. integer_ip = struct.unpack(">I", socket.inet_pton(socket.AF_INET, serverip))[0] rangeip = socket.inet_ntop( socket.AF_INET, struct.pack( ">I", integer_ip & ((2**int(netmask)) - 1) << 32 - int(netmask))) integer_netmask = struct.pack( ">I", ((2**int(netmask)) - 1) << 32 - int(netmask)) netmask = socket.inet_ntoa(integer_netmask) ps = subprocess.Popen( ["route", "add", "-net", rangeip, "netmask", netmask, "dev", dev], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if stderr: if not "File exists" in stderr: common.internal_print( "Error: adding client route: {0}".format(stderr), -1) sys.exit(-1) return
def lin_tun_alloc(self, dev, flags): try: tun = os.open(Interface.LINUX_CLONEDEV, os.O_RDWR | os.O_NONBLOCK, 0) ifr = struct.pack('16sH', dev, flags) fcntl.ioctl(tun, self.IOCTL_LINUX_TUNSETIFF, ifr) except IOError: common.internal_print( "Error: Cannot create tunnel. Is {0} in use?".format(dev), -1) sys.exit(-1) return tun
def lin_check_default_route(self): if len(self.ip.get_default_routes()) < 1: common.internal_print( "No default route. Please set up your routing before executing the tool", -1) sys.exit(-1) if len(self.ip.get_default_routes()) > 1: common.internal_print( "More than one default route. This should be reviewed before executing the tool.", -1) sys.exit(-1) return
def cleanup(self): common.internal_print("Shutting down module: {0}".format(self.get_module_name())) if self.serverorclient: if self.os_type == common.OS_LINUX: os.system("echo {0} > /proc/sys/net/ipv4/icmp_echo_ignore_all".format(self.orig_ieia_value)) #??? try: self.comms_socket.close() except: pass try: os.close(self.tunnel) except: pass
def check(self): try: common.internal_print("Checking module on server: {0}".format( self.get_module_name())) server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.settimeout(3) server_socket.connect( (self.config.get("Global", "remoteserverip"), int( self.config.get(self.get_module_configname(), "serverport")))) client_fake_thread = TCP_generic_thread( 0, 0, None, None, server_socket, None, self.authentication, self.encryption_module, self.verbosity, self.config, self.get_module_name()) client_fake_thread.do_check() client_fake_thread.communication(True) self.cleanup(server_socket) except socket.timeout: common.internal_print( "Checking failed: {0}".format(self.get_module_name()), -1) self.cleanup(server_socket) except socket.error as exception: if exception.args[0] == 111: common.internal_print( "Checking failed: {0}".format(self.get_module_name()), -1) else: common.internal_print( "Connection error: {0}".format(self.get_module_name()), -1) self.cleanup(server_socket) return
def check(self): try: common.internal_print("Checking module on server: {0} ({1}:{2})".format(self.get_module_name(), self.config.get(self.get_module_configname(), "proxyip"), self.config.get(self.get_module_configname(), "proxyport"))) server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.settimeout(3) server_socket.connect((self.config.get(self.get_module_configname(), "proxyip"), int(self.config.get(self.get_module_configname(), "proxyport")))) if self.http_connect_request(server_socket): client_fake_thread = HTTP_CONNECT_thread(0, 0, None, None, server_socket, None, self.auth_module, self.verbosity, self.config, self.get_module_name()) client_fake_thread.do_check() client_fake_thread.communication(True) server_socket.close() except socket.timeout: common.internal_print("Checking failed: {0}".format(self.get_module_name()), -1) self.cleanup(server_socket) except socket.error as exception: if exception.args[0] == 111: common.internal_print("Checking failed: {0}".format(self.get_module_name()), -1) else: common.internal_print("Connection error: {0}".format(self.get_module_name()), -1) self.cleanup(server_socket) return
def send(self, channel_type, message, additional_data): if channel_type == common.CONTROL_CHANNEL_BYTE: transformed_message = self.transform( common.CONTROL_CHANNEL_BYTE + message, 1) else: transformed_message = self.transform( common.DATA_CHANNEL_BYTE + message, 1) common.internal_print( "SCTP sent: {0}".format(len(transformed_message)), 0, self.verbosity, common.DEBUG) return self.comms_socket.send( struct.pack(">H", len(transformed_message)) + transformed_message)
def recv(self): message = "" length2b, addr = self.comms_socket.recvfrom(2, socket.MSG_PEEK) if len(length2b) == 0: if self.serverorclient: common.internal_print("WTF? Client lost. Closing down thread.", -1) else: common.internal_print("WTF? Server lost. Closing down.", -1) return ("", None) if len(length2b) != 2: return ("", None) length = struct.unpack(">H", length2b)[0] + 2 message, addr = self.comms_socket.recvfrom(length, socket.MSG_TRUNC) if (length != len(message)): common.internal_print("Error length mismatch", -1) return ("", None) common.internal_print("UDP read: {0}".format(len(message) - 2), 0, self.verbosity, common.DEBUG) return message[2:], addr
def communication_initialization(self): self.client = client.Client() try: self.client.set_socket(self.comms_socket) common.internal_print("Waiting for upgrade request", 0, self.verbosity, common.DEBUG) response = self.comms_socket.recv(4096) if len(response) == 0: common.internal_print("Connection was dropped", 0, self.verbosity, common.DEBUG) self.cleanup() sys.exit(-1) handshake_key = self.WebSocket_proto.get_handshake_init(response) if handshake_key == None: common.internal_print("No WebSocket-Key in request", -1, self.verbosity, common.DEBUG) self.cleanup() sys.exit(-1) handshake = self.WebSocket_proto.calculate_handshake(handshake_key) response = self.WebSocket_proto.switching_protocol(handshake) self.comms_socket.send(response) except: common.internal_print("Socket error", -1, self.verbosity, common.DEBUG) self.cleanup() sys.exit(-1) return
def recv(self): message = "" length2b = self.comms_socket.recv(2, socket.MSG_PEEK) if len(length2b) == 0: if self.serverorclient: common.internal_print("Client lost. Closing down thread.", -1) else: common.internal_print("Server lost. Closing down.", -1) self.stop() self.cleanup() return "" if len(length2b) != 2: return "" length = struct.unpack(">H", length2b)[0] + 2 received = 0 while received < length: message += self.comms_socket.recv(length - received) received = len(message) if (length != len(message)): common.internal_print("Error length mismatch", -1) return "" common.internal_print("SCTP read: {0}".format(len(message)), 0, self.verbosity, common.DEBUG) return self.transform(message[2:], 0)
def win_restore_routes(self, serverip, clientip, ip): common.internal_print("Restoring default route") ps = subprocess.Popen( ["route", "DELETE", serverip, self.orig_default_gw], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if stderr: common.internal_print( "Delete server route failed: {0}".format(stderr), -1) sys.exit(-1) ps = subprocess.Popen(["route", "-p", "DELETE", "0.0.0.0", ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if stderr: common.internal_print( "Delete default route failed: {0}".format(stderr), -1) sys.exit(-1) ps = subprocess.Popen([ "route", "ADD", "0.0.0.0", "MASK", "0.0.0.0", self.orig_default_gw ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if stderr: common.internal_print( "Add original default route failed: {0}".format(stderr), -1) sys.exit(-1) return
def run_windows(self): import win32file import win32event import pywintypes import winerror import win32api # creating events, overlapped structures and a buffer for reading and writing hEvent_read = win32event.CreateEvent(None, 0, 0, None) overlapped_read = pywintypes.OVERLAPPED() overlapped_read.hEvent = hEvent_read overlapped_write = pywintypes.OVERLAPPED() message = win32file.AllocateReadBuffer(4096) while not self._stop: try: # Overlapped/async read, it either blocks or returns pending hr, _ = win32file.ReadFile(self.tunnel, message, overlapped_read) if (hr == winerror.ERROR_IO_PENDING): # when the event gets signalled or timeout happens it will return rc = win32event.WaitForSingleObject(hEvent_read, int(self.timeout*1000)) if rc == winerror.WAIT_TIMEOUT: # timed out, just rerun read continue if rc == win32event.WAIT_OBJECT_0: # read happened, packet is in "message" if (overlapped_read.InternalHigh < 4) or (message[0:1] != "\x45"): #Only care about IPv4 # too small which should not happen or not IPv4, so we just drop it. continue # reading out the packet from the buffer and discarding the rest readytogo = message[0:overlapped_read.InternalHigh] # looking for client for c in self.clients: if c.get_private_ip_addr() == readytogo[16:20]: # client found, writing packet on client's pipe # ignoring outcome, it is async so it will happen when it will happen ;) win32file.WriteFile(c.get_pipe_w(), readytogo, overlapped_write) except win32api.error as e: if e.args[0] == 995: common.internal_print("Interface disappered, exiting PS thread: {0}".format(e), -1) self.stop() continue common.internal_print("PS Exception: {0}".format(e), -1) return
def lin_set_split_route(self, scope, ip): for entry in scope: ps = subprocess.Popen([ "route", "add", "-net", "{0}/{1}".format(entry[0], entry[2]), "gw", ip ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if stderr: common.internal_print( "Error: add split route: {0}".format(stderr), -1) sys.exit(-1) return
def freebsd_close_tunnel(self, tun): try: os.close(tun) except: pass s = socket.socket(type=socket.SOCK_DGRAM) try: ifr = struct.pack('<16s', self.iface_name) + '\x00' * 16 fcntl.ioctl(s, self.IOCTL_FREEBSD_SIOCIFDESTROY, ifr) except Exception as e: common.internal_print("Cannot destroy interface: {0}".format(dev), -1) return
def cmh_auth(self, module, message, additional_data, cm): if module.auth_module.check_details( message[len(common.CONTROL_AUTH):]): module.setup_authenticated_client( message[len(common.CONTROL_AUTH):], additional_data) common.internal_print("Client authenticated", 1) return module.cmh_struct[cm][3] else: module.send(common.CONTROL_CHANNEL_BYTE, common.CONTROL_AUTH_NOTOK, additional_data) common.internal_print("Client authentication failed", -1) return module.cmh_struct[cm][4]
def freebsd_check_default_route(self): # get default gateway ps = subprocess.Popen(["route", "-n", "get", "default"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() # is there a default gateway entry? if "route has not been found" in stderr: common.internal_print( "No default route. Please set up your routing before executing the tool", -1) sys.exit(-1) return
def authentication_step_1(self, module, message, additional_data, cm): if self.check_details(message[len(self.cmh_struct_authentication[0][0]):]): if module.post_authentication_server(message[len(self.cmh_struct_authentication[0][0]):], additional_data): module.send(common.CONTROL_CHANNEL_BYTE, self.cmh_struct_authentication[1][0], module.modify_additional_data(additional_data, 1)) else: module.send(common.CONTROL_CHANNEL_BYTE, self.cmh_struct_authentication[2][0], module.modify_additional_data(additional_data, 1)) return module.cmh_struct[cm][4+module.is_caller_stateless()] common.internal_print("Client authenticated", 1) return module.cmh_struct[cm][3] else: module.send(common.CONTROL_CHANNEL_BYTE, self.cmh_struct_authentication[2][0], module.modify_additional_data(additional_data, 1)) common.internal_print("Client authentication failed", -1) return module.cmh_struct[cm][4+module.is_caller_stateless()]
def WIN_get_subinterface_name(self): IFACE_NAME_KEY = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\" NetCfgInstanceId = self.WIN_get_device_guid() try: regkey = registry.OpenKey( registry.HKEY_LOCAL_MACHINE, IFACE_NAME_KEY + NetCfgInstanceId + "\\Connection\\") iface_name = registry.QueryValueEx(regkey, "Name")[0] except WindowsError as e: common.internal_print( "Cannot get interface name. Registry key cannot be found: {0}". format(e), -1) sys.exit(-1) return iface_name
def connect(self): try: version = self.config.get(self.get_module_configname(), "version") common.internal_print( "Starting client: {0}, Version: {1} ({2}:{3})".format( self.get_module_name(), version, self.config.get(self.get_module_configname(), "proxyip"), int( self.config.get(self.get_module_configname(), "proxyport")))) client_fake_thread = None server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.settimeout(3) server_socket.connect( (self.config.get(self.get_module_configname(), "proxyip"), int(self.config.get(self.get_module_configname(), "proxyport")))) if self.socks_handshake(server_socket): client_fake_thread = SOCKS_thread(0, 0, self.tunnel, None, server_socket, None, self.authentication, self.encryption_module, self.verbosity, self.config, self.get_module_name()) client_fake_thread.do_hello() client_fake_thread.communication(False) server_socket.close() except KeyboardInterrupt: if client_fake_thread: client_fake_thread.do_logoff() self.cleanup(server_socket) raise except socket.error: common.internal_print( "Connection error: {0}".format(self.get_module_name()), -1) self.cleanup(server_socket) raise self.cleanup(server_socket) return
def win_set_mtu(self, dev, mtu): iface_name = self.WIN_get_subinterface_name() ps = subprocess.Popen([ "netsh", "interface", "ipv4", "set", "subinterface", iface_name, "mtu={0}".format(mtu), "store=active" ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if "Ok." not in stdout: common.internal_print( "Cannot set MTU. netsh failed: {0}".format(stdout), -1) sys.exit(-1) return
def mac_check_default_route(self): # get default gateway ps = subprocess.Popen(["route", "-n", "get", "default"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() # is there a default gateway entry? if "not in table" in stderr: common.internal_print( "No default route. Please set up your routing before executing the tool", -1) sys.exit(-1) # check for multiple default routes # is this even possible on MacOS(X)? return
def websocket_upgrade(self, server_socket): request = self.WebSocket_proto.upgrade( base64.b64encode(os.urandom(9)).replace("/", "").replace("+", ""), self.config.get("Global", "remoteserverhost"), self.config.get(self.get_module_configname(), "serverport"), 13) server_socket.send(request) response = server_socket.recv(4096) if response[9:12] != "101": common.internal_print( "Connection failed: {0}".format( response[0:response.find("\n")]), -1) return False return True
def sanity_check(self): if not super(WebSocket, self).sanity_check(): return False if not self.config.has_option(self.get_module_configname(), "proxyip"): common.internal_print( "'proxyip' option is missing from '{0}' section".format( self.get_module_configname()), -1) return False if not self.config.has_option(self.get_module_configname(), "proxyport"): common.internal_print( "'proxyport' option is missing from '{0}' section".format( self.get_module_configname()), -1) return False if not common.is_ipv4( self.config.get(self.get_module_configname(), "proxyip") ) and not common.is_ipv6( self.config.get(self.get_module_configname(), "proxyip")): common.internal_print( "'proxyip' should be ipv4 or ipv6 address in '{0}' section". format(self.get_module_configname()), -1) return False if not self.config.has_option("Global", "remoteserverhost"): common.internal_print( "'remoteserverhost' option is missing from 'Global' section", -1) return False if not common.is_hostname(self.config.get( "Global", "remoteserverhost")) and not common.is_ipv4( self.config.get( "Global", "remoteserverhost")) and not common.is_ipv6( self.config.get("Global", "remoteserverhost")): common.internal_print( "'remoteserverhost' should be a hostname 'Global' section", -1) return False return True
def send(self, channel_type, message, additional_data): if channel_type == common.CONTROL_CHANNEL_BYTE: transformed_message = self.transform( common.CONTROL_CHANNEL_BYTE + message, 1) else: transformed_message = self.transform( common.DATA_CHANNEL_BYTE + message, 1) websocket_msg = self.WebSocket_proto.build_message( self.serverorclient, 2, transformed_message) common.internal_print( "WebSocket sent: {0} -> {1}".format(len(transformed_message), len(websocket_msg)), 0, self.verbosity, common.DEBUG) return self.comms_socket.send(websocket_msg)
def communication_initialization(self): self.clients = [] if self.serverorclient: if self.os_type == common.OS_LINUX: ps = subprocess.Popen(["cat", "/proc/sys/net/ipv4/icmp_echo_ignore_all"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = ps.communicate() if stderr: common.internal_print("Error: deleting default route: {0}".format(stderr), -1) sys.exit(-1) self.orig_ieia_value = stdout[0:1] os.system("echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all") if self.serverorclient: self.ICMP_send = self.icmp.ICMP_ECHO_RESPONSE else: self.ICMP_send = self.icmp.ICMP_ECHO_REQUEST return
def send(self, channel_type, message, additional_data): addr = additional_data[0] identifier = additional_data[1] sequence = additional_data[2] queue_length = additional_data[3] if queue_length < 256: ql = chr(queue_length) else: ql = chr(255) if channel_type == common.CONTROL_CHANNEL_BYTE: transformed_message = self.transform( self.get_client_encryption(additional_data), ql + common.CONTROL_CHANNEL_BYTE + message, 1) else: transformed_message = self.transform( self.get_client_encryption(additional_data), ql + common.DATA_CHANNEL_BYTE + message, 1) common.internal_print( "ICMP sent: {0} seq: {1} id: {2}".format(len(transformed_message), sequence, identifier), 0, self.verbosity, common.DEBUG) packet = self.icmp.create_packet( self.ICMP_send, identifier, sequence, self.ICMP_prefix + struct.pack(">H", len(transformed_message)) + transformed_message) # WORKAROUND?! # Windows: It looks like when the buffer fills up the OS does not do # congestion control, instead throws and exception/returns with # WSAEWOULDBLOCK which means that we need to try it again later. # So we sleep 100ms and hope that the buffer has more space for us. # If it does then it sends the data, otherwise tries it in an infinite # loop... while True: try: return self.comms_socket.sendto(packet, addr) except socket.error as se: if se.args[0] == 10035: # WSAEWOULDBLOCK time.sleep(0.1) pass else: raise
def __init_thread__(self, threadID, config, tunnel, packetselector, auth_module, verbosity): threading.Thread.__init__(self) self.threadID = threadID self.config = config self.tunnel = tunnel self.packetselector = packetselector self.auth_module = auth_module self.verbosity = verbosity self._stop = False if not self.os_check(): common.internal_print("The module '{0}' does not support your operating system.".format(self.get_module_name()), -1) return False if not self.sanity_check(): return False return True
def load_encryption_module(self, config): if not config.has_section("Encryption"): module_name = "none" else: if config.has_option("Encryption", "module"): module_name = config.get("Encryption", "module") else: module_name = "none" if not os.path.isfile("encryption/enc_"+module_name+".py"): common.internal_print("No such encryption module: enc_{0}.py".format(module_name), -1) sys.exit(-1) imports = __import__("encryption.enc_"+module_name, locals(), globals()) module_reference = getattr(imports, "enc_"+module_name) module = module_reference.Encryption_module() return module
def load_auth_module(self, config): if not config.has_section("Authentication"): module_name = "noauth" else: if config.has_option("Authentication", "module"): module_name = config.get("Authentication", "module") else: module_name = "noauth" if not os.path.isfile("authentication/auth_"+module_name+".py"): common.internal_print("No such authentication module: auth_{0}.py".format(module_name), -1) sys.exit(-1) imports = __import__("authentication.auth_"+module_name, locals(), globals()) module_reference = getattr(imports, "auth_"+module_name) module = module_reference.Authentication_module() return module
def sanity_check(self): if not self.config.has_option(self.get_module_configname(), "serverport"): common.internal_print( "'serverport' option is missing from '{0}' section".format( self.get_module_configname()), -1) return False try: convert = int( self.config.get(self.get_module_configname(), "serverport")) except: common.internal_print( "'serverport' is not an integer in '{0}' section".format( self.get_module_configname()), -1) return False return True