Beispiel #1
0
    def _l7_analysis(self, packet):
        """Analyzes application level of pcap.

        :param packet: Single packet.
        """
        if packet.dns:
            if packet.dns.qr == 0:
                # dns question
                for question in packet.dns.questions:
                    self._dns_questions.add(question)

            # report anomaly
            if (packet.dns.question_count > 499
                    or packet.dns.answer_count > 499
                    or packet.dns.authority_count > 499
                    or packet.dns.additional_count > 499):
                name = 'dns_header_many_records'
                description = ('Sample sends DNS header with either big '
                               'number of questions, answers, authorities '
                               'or additionals.')
                data = {
                    'question_count': packet.dns.question_count,
                    'answer_count': packet.dns.answer_count,
                    'authority_count': packet.dns.authority_count,
                    'additional_count': packet.dns.additional_count
                }

                anomaly = Anomaly(name, description, data)
                self._anomalies.append(anomaly.to_dict())

        if packet.http:
            if packet.http.is_request:
                # http request
                request = {
                    'method': packet.http.request_method,
                    'uri': packet.http.request_uri,
                    'version': packet.http.version,
                    'headers': {}
                }
                # headers
                for key in packet.http.headers:
                    request['headers'][key] = packet.http.headers[key]

                self._http_requests.append(request)

        if packet.irc:
            for message in packet.irc.messages:
                # irc messages
                str_message = message.command
                for param in message.params:
                    str_message += ' ' + param
                str_message += ' ' + message.trailing
                str_message = str_message.strip()
                if str_message != '':
                    self._irc_messages.append(str_message)

        if packet.telnet:
            if len(packet.telnet.data.strip()) != 0:
                self._telnet_data.append(packet.telnet.data)
Beispiel #2
0
def test_anomaly_empty():
    anomaly = Anomaly(None, None, None)

    assert anomaly.to_dict() == {
        'name': None,
        'description': None,
        'data': None
    }
Beispiel #3
0
def test_anomaly_standard():
    anomaly = Anomaly('test_anomaly', 'Test description.',
                      {'anomaly_data': 42})

    assert anomaly.to_dict() == {
        'name': 'test_anomaly',
        'description': 'Test description.',
        'data': {
            'anomaly_data': 42
        }
    }
Beispiel #4
0
    def _analyze_endpoint(self, ip):
        """Returns information about endpoint (IP address)

        :param ip: String representation of IP address.
        :param port: Port number.
        :returns: Dictionary with endpoint information.
        """
        if self._maxmind:
            # get maxmind geolite2 info
            try:
                rc = self._reader_city.city(ip)
                ra = self._reader_asn.asn(ip)
                endpoint = {
                    'ip': ip,
                    'ports': [],
                    'country': rc.country.name,
                    'city': rc.city.name,
                    'asn': ra.autonomous_system_number,
                    'organization': ra.autonomous_system_organization,
                    'blacklisted': is_ip_blacklisted(ip),
                    'data_in': 0,
                    'data_out': 0
                }
            except geoip2.errors.AddressNotFoundError as e:
                endpoint = {
                    'ip': ip,
                    'ports': [],
                    'blacklisted': is_ip_blacklisted(ip),
                    'data_in': 0,
                    'data_out': 0
                }
        else:
            endpoint = {
                'ip': ip,
                'ports': [],
                'blacklisted': is_ip_blacklisted(ip),
                'data_in': 0,
                'data_out': 0
            }

        # report anomaly
        if endpoint['blacklisted']:
            name = 'blacklisted_ip_access'
            description = ('Sample contacted endpoint with IP '
                           'address present on blacklist.')
            data = {
                'ip_address': ip
            }

            anomaly = Anomaly(name, description, data)
            self._anomalies.append(anomaly.to_dict())

        return endpoint
Beispiel #5
0
def test_anomaly_nested():
    anomaly = Anomaly(
        'nested_anomaly',
        'Random description.',
        {
            'anomaly_data': {
                'nested_anomaly_data': {
                    'ip_address': '192.168.0.1'
                }
            }
        }
    )

    assert anomaly.to_dict() == {
        'name': 'nested_anomaly',
        'description': 'Random description.',
        'data': {
            'anomaly_data': {
                'nested_anomaly_data': {
                    'ip_address': '192.168.0.1'
                }
            }
        }
    }
Beispiel #6
0
    def analyze_pcap(self):
        """Analyzes captured pcap file. Fills self._endpoints,
        self._port_statistics, self._syn_count, self._fin_count and others.
        """

        endpoints = {}

        if self._local_ip is None:
            self._local_ip = disspcap.most_common_ip(self._pcap_path)

        pcap = disspcap.Pcap(self._pcap_path)

        while True:

            packet = pcap.next_packet()
            if packet is None:
                break

            if packet.ipv4:
                packet_ip = packet.ipv4
            elif packet.ipv6:
                packet_ip = packet.ipv6
            else:
                continue

            # TCP communication
            if packet.tcp:

                if packet_ip.source == self._local_ip:
                    # outgoing packet
                    ip = packet_ip.destination
                    port = str(packet.tcp.destination_port)
                    length = packet.tcp.payload_length

                    if packet.tcp.syn:
                        # search for syn scan
                        self._syn_count += 1
                        if is_ip_local(ip):
                            self._syn_count_local += 1
                    elif packet.tcp.fin and not packet.tcp.ack:
                        # search for fin scan
                        self._fin_count += 1
                        if is_ip_local(ip):
                            self._fin_count_local += 1

                    if length != 0:
                        # analyze endpoint
                        if ip not in endpoints:
                            endpoint = self._analyze_endpoint(ip)
                            endpoints[ip] = endpoint

                        endpoints[ip]['data_out'] += length

                        if port not in endpoints[ip]['ports']:
                            endpoints[ip]['ports'].append(port)

                    self._port_statistics['TCP'][port] += 1

                else:
                    # incomming packet
                    ip = packet_ip.source
                    port = str(packet.tcp.source_port)
                    length = packet.tcp.payload_length

                    if length != 0:
                        if ip not in endpoints:
                            endpoint = self._analyze_endpoint(ip)
                            endpoints[ip] = endpoint

                        endpoints[ip]['data_in'] += length

                        if port not in endpoints[ip]['ports']:
                            endpoints[ip]['ports'].append(port)

                    self._port_statistics['TCP'][port] += 1

            # UDP communication
            if packet.udp:

                if packet_ip.source == self._local_ip:
                    # outgoing packet
                    ip = packet_ip.destination
                    port = str(packet.udp.destination_port)
                    length = packet.udp.payload_length

                    if length != 0:
                        # analyze endpoints
                        if ip not in endpoints:
                            endpoint = self._analyze_endpoint(ip)
                            endpoints[ip] = endpoint

                        endpoints[ip]['data_out'] += length

                        if port not in endpoints[ip]['ports']:
                            endpoints[ip]['ports'].append(port)

                    self._port_statistics['UDP'][port] += 1
                else:
                    # incommming packet
                    ip = packet_ip.source
                    port = str(packet.udp.source_port)
                    length = packet.udp.payload_length

                    if length != 0:
                        # analyze endpoint
                        if ip not in endpoints:
                            endpoint = self._analyze_endpoint(ip)
                            endpoints[ip] = endpoint

                        endpoints[ip]['data_in'] += length

                        if port not in endpoints[ip]['ports']:
                            endpoints[ip]['ports'].append(port)

                    self._port_statistics['UDP'][port] += 1

            self._l7_analysis(packet)

        self._endpoints = list(endpoints.values())

        # report anomaly
        if self._syn_count > 100:
            name = 'syn_scan'
            description = 'Sample send more than 100 TCP SYN packets.'
            data = {
                'syn_count': {
                    'total': self._syn_count,
                    'local': self._syn_count_local,
                    'internet': self._syn_count - self._syn_count_local
                }
            }

            anomaly = Anomaly(name, description, data)
            self._anomalies.append(anomaly.to_dict())

        # report anomaly
        if self._fin_count > 100:
            name = 'fin_scan'
            description = 'Sample send more than 100 TCP FIN packets.'
            data = {
                'fin_count': {
                    'total': self._fin_count,
                    'local': self._fin_count_local,
                    'internet': self._fin_count - self._fin_count_local
                }
            }

            anomaly = Anomaly(name, description, data)
            self._anomalies.append(anomaly.to_dict())

        # save pcap analysis output
        self._output['anomalies'] = self._anomalies

        self._output['irc_messages'] = self._irc_messages

        self._output['dns_questions'] = []

        # question structure
        for question in self._dns_questions:
            qname, qtype = question.split()
            self._output['dns_questions'].append({
                'name': qname,
                'type': qtype
            })

        self._output['http_requests'] = self._http_requests

        self._output['telnet_data'] = self._telnet_data

        most_common_tcp = self._port_statistics['TCP'].most_common()
        most_common_udp = self._port_statistics['UDP'].most_common()

        ports_tcp_count = len(most_common_tcp)
        ports_udp_count = len(most_common_udp)

        # report anomaly
        if ports_tcp_count + ports_udp_count > 100:
            name = 'port_scan'
            description = 'Sample communicated on more than 100 ports.'
            data = {
                'tcp_ports_count': ports_tcp_count,
                'udp_ports_count': ports_udp_count
            }

            anomaly = Anomaly(name, description, data)
            self._anomalies.append(anomaly.to_dict())

        self._output['port_statistics'] = {
            'TCP': collections.OrderedDict(most_common_tcp),
            'UDP': collections.OrderedDict(most_common_udp)
        }

        self._output['endpoints'] = self._endpoints