Beispiel #1
0
    def _process_packet_helper(self, pkt):

        if sc.ARP in pkt:
            return self._process_arp(pkt)

        if sc.DHCP in pkt:
            return self._process_dhcp(pkt)

        # SYN-ACK response to SYN scans
        if sc.TCP in pkt and pkt[sc.TCP].flags == 'SA' and sc.IP in pkt:
            tcp_layer = pkt[sc.TCP]
            if tcp_layer.dport == SYN_SCAN_SOURCE_PORT and tcp_layer.ack == SYN_SCAN_SEQ_NUM + 1:
                return self._process_syn_scan(pkt)

        # Must have Ether frame and IP frame.
        if not (sc.Ether in pkt and sc.IP in pkt):
            return

        src_mac = pkt[sc.Ether].src
        dst_mac = pkt[sc.Ether].dst

        src_oui = utils.get_oui(src_mac)
        dst_oui = utils.get_oui(dst_mac)

        # Include only devices for internal testing (if set)
        if utils.TEST_OUI_LIST:
            if not (src_oui in utils.TEST_OUI_LIST
                    or dst_oui in utils.TEST_OUI_LIST):
                return

        # Ignore traffic to and from this host's IP
        if self._host_state.host_ip in (pkt[sc.IP].src, pkt[sc.IP].dst):
            return

        # DNS
        if sc.DNS in pkt:
            self._process_dns(pkt)

        # Commented out the following. We want to see traffic between device and gateway.
        # # Ignore traffic to and from the gateway's IP
        # if self._host_state.gateway_ip in (pkt[sc.IP].src, pkt[sc.IP].dst):
        #    return

        # TCP/UDP
        if sc.TCP in pkt:
            protocol = 'tcp'
        elif sc.UDP in pkt:
            protocol = 'udp'
        else:
            return

        return self._process_tcp_udp_flow(pkt, protocol)
def get_device_list():
    """
    Returns a list of devices; constantly changes.

    """
    # Maps device_id -> {device_id, device_vendor, netdisco_name}
    output_dict = {}

    host_state = get_host_state()
    if host_state is None:
        return json.dumps(output_dict)

    # Get device vendor
    with host_state.lock:
        for (ip, mac) in host_state.ip_mac_dict.items():

            # Never include the gateway
            if ip == host_state.gateway_ip:
                continue

            device_id = utils.get_device_id(mac, host_state)
            device_vendor = oui_parser.get_vendor(utils.get_oui(mac))

            output_dict.setdefault(
                device_id, {
                    'device_id': device_id,
                    'device_ip': ip,
                    'device_vendor': device_vendor,
                    'netdisco_name': '',
                    'dhcp_name': '',
                    'is_inspected': device_id in host_state.device_whitelist
                })

    # Fill out netdisco_name

    with host_state.lock:
        for (device_id,
             device_info_list) in host_state.pending_netdisco_dict.items():
            if device_id in output_dict:
                output_dict[device_id]['netdisco_name'] = device_info_list

        # Reset pending dict
        host_state.pending_netdisco_dict = {}

    # Fill out dhcp_name

    with host_state.lock:
        for (device_id, dhcp_name) in host_state.pending_dhcp_dict.items():
            if device_id in output_dict:
                output_dict[device_id]['dhcp_name'] = dhcp_name

        # Reset pending dict
        host_state.pending_dhcp_dict = {}

    return json.dumps(output_dict, indent=2)
Beispiel #3
0
    def _process_packet_helper(self, pkt):

        if sc.ARP in pkt:
            return self._process_arp(pkt)

        if sc.DHCP in pkt:
            return self._process_dhcp(pkt)

        # Must have Ether frame and IP frame.
        if not (sc.Ether in pkt and sc.IP in pkt):
            return

        src_mac = pkt[sc.Ether].src
        dst_mac = pkt[sc.Ether].dst

        src_oui = utils.get_oui(src_mac)
        dst_oui = utils.get_oui(dst_mac)

        # Include only devices for internal testing (if set)
        if utils.TEST_OUI_LIST:
            if not (src_oui in utils.TEST_OUI_LIST or
                    dst_oui in utils.TEST_OUI_LIST):
                return

        # Ignore traffic to and from this host's IP
        if self._host_state.host_ip in (pkt[sc.IP].src, pkt[sc.IP].dst):
            return

        # DNS
        if sc.DNS in pkt:
            self._process_dns(pkt)

        # Ignore traffic to and from the gateway's IP
        if self._host_state.gateway_ip in (pkt[sc.IP].src, pkt[sc.IP].dst):
            return

        # Get gateway's MAC
        try:
            with self._host_state.lock:
                gateway_mac = self._host_state.ip_mac_dict[
                    self._host_state.gateway_ip
                ]
        except KeyError:
            return

        # Communication must be between this host's MAC (acting as a gateway)
        # and a non-gateway device
        host_mac = self._host_state.host_mac
        this_host_as_gateway = (
            (src_mac == host_mac and dst_mac != gateway_mac) or
            (dst_mac == host_mac and src_mac != gateway_mac)
        )
        if not this_host_as_gateway:
            return

        # TCP/UDP
        if sc.TCP in pkt:
            protocol = 'tcp'
        elif sc.UDP in pkt:
            protocol = 'udp'
        else:
            return

        return self._process_tcp_udp_flow(pkt, protocol)
Beispiel #4
0
    def _arp_spoof_loop(self):

        prev_ip_mac_dict = None

        while True:

            if not self._host_state.is_inspecting():
                time.sleep(2)
                continue

            time.sleep(1)

            with self._lock:
                if not self._active:
                    return

            with self._host_state.lock:
                if not self._host_state.has_consent:
                    utils.log('[ARP Spoof] No consent; no spoofing.')
                    continue

            # Get ARP cache
            ip_mac_dict = self._host_state.get_ip_mac_dict_copy()
            gateway_ip = self._host_state.gateway_ip

            if str(ip_mac_dict) != str(prev_ip_mac_dict):

                prev_ip_mac_dict = ip_mac_dict

                utils.log('[ARP Spoof] Cache:', ip_mac_dict)
                utils.log('[ARP Spoof] Whitelist:',
                          self._host_state.device_whitelist)

            # Get gateway MAC addr
            try:
                gateway_mac = ip_mac_dict[gateway_ip]
            except KeyError:
                continue

            whitelist_ip_mac = []
            # Add gateway
            whitelist_ip_mac.append((gateway_ip, gateway_mac))

            # Build device-to-device whitelist
            for ip, mac in ip_mac_dict.items():
                device_id = utils.get_device_id(mac, self._host_state)
                if device_id not in self._host_state.device_whitelist:
                    utils.log('[ARP Spoof] Ignore:', ip, mac)
                    continue
                whitelist_ip_mac.append((ip, mac))

            # Spoof individual devices on the network.
            for (victim_ip, victim_mac) in ip_mac_dict.items():

                if victim_ip == gateway_ip:
                    continue

                # Check against whitelist.
                victim_device_id = \
                    utils.get_device_id(victim_mac, self._host_state)
                if victim_device_id not in self._host_state.device_whitelist:
                    utils.log('[ARP Spoof] Ignore:', victim_ip, victim_mac)
                    continue

                if utils.TEST_OUI_LIST:
                    victim_mac_oui = utils.get_oui(victim_mac)
                    if victim_mac_oui not in utils.TEST_OUI_LIST:
                        continue

                utils.safe_run(self._arp_spoof,
                               args=(victim_mac, victim_ip, whitelist_ip_mac))

                with self._lock:
                    if not self._active:
                        return

                time.sleep(max(MIN_ARP_SPOOF_INTERVAL, 2.0 / len(ip_mac_dict)))
Beispiel #5
0
    def _prepare_upload_data(self):
        """Returns (window_duration, a dictionary of data to post)."""

        window_duration = time.time() - self._last_upload_ts

        # Remove all pending tasks
        with self._host_state.lock:

            dns_dict = self._host_state.pending_dns_dict
            dhcp_dict = self._host_state.pending_dhcp_dict
            resolver_dict = self._host_state.pending_resolver_dict
            flow_dict = self._host_state.pending_flow_dict
            ua_dict = self._host_state.pending_ua_dict
            ip_mac_dict = self._host_state.ip_mac_dict
            tls_dict_list = self._host_state.pending_tls_dict_list
            netdisco_dict = self._host_state.pending_netdisco_dict

            self._clear_host_state_pending_data()

            self._last_upload_ts = time.time()

        # Turn IP -> MAC dict into device_id -> (ip, device_oui) dict, ignoring
        # gateway's IP.
        device_dict = {}
        for (ip, mac) in ip_mac_dict.iteritems():
            # Never include the gateway
            if ip == self._host_state.gateway_ip:
                continue
            device_id = utils.get_device_id(mac, self._host_state)
            oui = utils.get_oui(mac)
            device_dict[device_id] = (ip, oui)

        # Process flow_stats
        for flow_key in flow_dict:

            flow_stats = flow_dict[flow_key]

            # Compute unique byte count during this window using seq number
            for direction in ('inbound', 'outbound'):
                flow_stats[direction + '_tcp_seq_range'] = get_seq_diff(
                    flow_stats[direction + '_tcp_seq_min_max']
                )
                flow_stats[direction + '_tcp_ack_range'] = get_seq_diff(
                    flow_stats[direction + '_tcp_ack_min_max']
                )

                # We use the original byte count or the sequence number as the
                # final byte count (whichever is larger), although we should
                # note the caveats of using TCP seq numbers to estimate flow
                # size in packet_processor.py.
                flow_stats[direction + '_byte_count'] = max(
                    flow_stats[direction + '_byte_count'],
                    flow_stats[direction + '_tcp_seq_range']
                )

            # Fill in missing byte count (e.g., due to failure of ARP spoofing)
            if flow_stats['inbound_byte_count'] == 0:
                outbound_seq_diff = flow_stats['outbound_tcp_ack_range']
                if outbound_seq_diff:
                    flow_stats['inbound_byte_count'] = outbound_seq_diff
            if flow_stats['outbound_byte_count'] == 0:
                inbound_seq_diff = flow_stats['inbound_tcp_ack_range']
                if inbound_seq_diff:
                    flow_stats['outbound_byte_count'] = inbound_seq_diff

            # Keep only the byte count fields
            flow_dict[flow_key] = {
                'inbound_byte_count': flow_stats['inbound_byte_count'],
                'outbound_byte_count': flow_stats['outbound_byte_count'],
                'syn_originator': flow_stats['syn_originator']
            }

        return (window_duration, {
            'dns_dict': jsonify_dict(dns_dict),
            'flow_dict': jsonify_dict(flow_dict),
            'device_dict': jsonify_dict(device_dict),
            'ua_dict': jsonify_dict(ua_dict),
            'dhcp_dict': jsonify_dict(dhcp_dict),
            'resolver_dict': jsonify_dict(resolver_dict),
            'client_version': self._host_state.client_version,
            'tls_dict_list': json.dumps(tls_dict_list),
            'netdisco_dict': jsonify_dict(netdisco_dict),
            'duration': str(window_duration),
            'client_ts': str(int(time.time()))
        })