def spoof_devices(ip, devs, logger): tgt = (ip.gateway, ip.dns_servers[0]) if util.is_spoof_dns(ip) else (ip.gateway, ) for entry in devs: dev_ip = util.get_device_ip(entry) dev_hw = ip.redis.get_device_mac( dev_ip, network=util.get_device_net(entry)) for source in tgt: if util.get_device_enabled(entry) == "1": # sendp(Ether(dst=dev_hw) / ARP(op=2, psrc=ip.gateway, pdst=dev_ip, hwdst=dev_hw)) sendp([ Ether(dst=dev_hw) / IPv6(src=source, dst=dev_ip) / ICMPv6ND_NA(tgt=source, R=0, S=1) / ICMPv6NDOptDstLLAddr(lladdr=ip.mac) ]) # sendp(Ether(dst=ip.gate_mac) / ARP(op=2, psrc=dev_ip, pdst=ip.gateway, hwdst=ip.gate_mac)) else: # sendp(Ether(dst=dev_hw) / ARP(op=2, psrc=ip.gateway, pdst=dev_ip, hwdst=dev_hw, hwsrc=ip.gate_mac)) # sendp(Ether(dst=ip.gate_mac) / ARP(op=2, psrc=dev_ip, pdst=ip.gateway, hwsrc=dev_hw)) sendp([ Ether(dst=dev_hw) / IPv6(src=source, dst=dev_ip) / ICMPv6ND_NA(tgt=source, R=0, S=1) / ICMPv6NDOptDstLLAddr(lladdr=ip.gate_mac) ])
def _icmpv6_handler(self, pkt): """"This method is called for each ICMPv6 echo reply packet or multicast listener report packet received through scapy's sniff function. Incoming packets are used to spoof involved devices and add new devices to the redis db. Args: pkt (str): Received packet via scapy's sniff (through socket.recv). """ # add transmitting device to redis db self.ip.redis.add_device(pkt[IPv6].src, pkt[Ether].src) # impersonate gateway if not self.ip.redis.check_device_disabled(pkt[Ether].src): sendp( Ether(dst=pkt[Ether].src) / IPv6(src=self.ip.gateway, dst=pkt[IPv6].src) / ICMPv6ND_NA(tgt=self.ip.gateway, R=0, S=1) / ICMPv6NDOptDstLLAddr(lladdr=self.ip.mac)) # impersonate DNS server if necessary if util.is_spoof_dns(self.ip): if not self.ip.redis.check_device_disabled(pkt[Ether].src): sendp( Ether(dst=pkt[Ether].src) / IPv6(src=self.ip.dns_servers[0], dst=pkt[IPv6].src) / ICMPv6ND_NA(tgt=self.ip.dns_servers[0], R=0, S=1) / ICMPv6NDOptDstLLAddr(lladdr=self.ip.mac))
def run(self): """Starts multiple threads sends out packets to spoof all existing clients on the network and the gateway. This packets are sent every __SLEEP seconds. The existing clients (device entries) are read from the redis database. Threads: A SniffThread, which sniffs for incoming ARP packets and adds new devices to the redis db. Several HostDiscoveryThread, which are searching for existing devices on the network. A PubSubThread, which is listening for redis expiry messages. Note: First, ARP replies to spoof the gateway entry of existing clients arp cache are generated. ARP relpies to spoof the entries of the gateway are generated next. Unlike the holistic mode only packets for existing clients are generated. """ try: for worker in self.threads: self.threads[worker].start() # check if the impersonation of the DNS server is necessary tgt = (self.ipv6.gateway, self.ipv6.dns_servers[0]) if util.is_spoof_dns( self.ipv6) else (self.ipv6.gateway, ) while not self.exit.is_set(): packets = [] for source in tgt: packets.extend([ Ether(dst=dev[1]) / IPv6(src=source, dst=dev[0]) / ICMPv6ND_NA(tgt=source, R=1, S=1, O=1) / ICMPv6NDOptDstLLAddr(lladdr=self.ipv6.mac) for dev in self.ipv6.redis.get_devices_values( filter_values=True) ]) sendp(packets) try: with self.sleeper: self.sleeper.wait(timeout=self.__SLEEP) except RuntimeError as e: # this error is thrown by the with-statement when the thread is stopped if len(e.args) > 0 and e.args[ 0] == "cannot release un-acquired lock": return else: raise e self._return_to_normal() except Exception as e: self.logger.error("Process IPv6") self.logger.exception(e)
def _return_to_normal(self): """This method is called when the daemon is stopping. Apate tells the clients the real gateway via neighbor advertisements. """ # spoof clients with nd advertisements with self.sleeper: # check if the impersonation of the DNS server is necessary tgt = (self.ipv6.gateway, self.ipv6.dns_servers[0]) if util.is_spoof_dns( self.ipv6) else (self.ipv6.gateway, ) for source in tgt: sendp( Ether(dst=ETHER_BROADCAST) / IPv6(src=source, dst=MulticastPingDiscoveryThread._MULTICAST_DEST) / ICMPv6ND_NA(tgt=source, R=1, S=0, O=1) / ICMPv6NDOptDstLLAddr(lladdr=self.ipv6.gate_mac))
def _return_to_normal(self): """This method is called when the daemon is stopping. First, sends a GARP broadcast request to all clients to tell them the real gateway. Then ARP replies for existing clients are sent to the gateway. If IPv6 is enabled, Apate tells the clients the real gateway via neighbor advertisements. """ # spoof clients with GARP broadcast request with self.sleeper: # check if the impersonation of the DNS server is necessary tgt = (self.ipv6.gateway, self.ipv6.dns_servers[0]) if util.is_spoof_dns( self.ipv6) else (self.ipv6.gateway, ) for source in tgt: sendp( Ether(dst=ETHER_BROADCAST) / IPv6(src=source, dst=MulticastPingDiscoveryThread._MULTICAST_DEST) / ICMPv6ND_NA(tgt=source, R=0, S=0) / ICMPv6NDOptDstLLAddr(lladdr=self.ipv6.gate_mac))
def spoof_devices(ip, devs, logger): tgt = (ip.gateway, ip.dns_servers[0]) if util.is_spoof_dns(ip) else (ip.gateway, ) for entry in devs: dev_hw = util.get_device_mac(entry) dev_ip = devs[entry] for source in tgt: if not ip.redis.check_device_disabled( util.get_device_mac(entry)): sendp([ Ether(dst=dev_hw) / IPv6(src=source, dst=dev_ip) / ICMPv6ND_NA(tgt=source, R=1, S=1) / ICMPv6NDOptDstLLAddr(lladdr=ip.mac) ]) else: sendp([ Ether(dst=dev_hw) / IPv6(src=source, dst=dev_ip) / ICMPv6ND_NA(tgt=source, R=1, S=1) / ICMPv6NDOptDstLLAddr(lladdr=ip.gate_mac) ])