Ejemplo n.º 1
0
    def _setup(cls):
        Configuration.setup(cls)
        IPSResponse.setup(cls, Log)

        cls.set_proxy_callback(
            func=Inspect.portscan
        )  # this will get called after parsing is complete.

        Log.notice(f'{cls.__name__} initialization complete.')
Ejemplo n.º 2
0
    def _pre_check(self, nfqueue):
        if (not self.ddos_engine_enabled
                and nfqueue.get_mark() == IP_PROXY_DROP):
            Log.debug(
                'packet fast dropped from ip proxy | ddos engine disabled')
            nfqueue.drop()

        elif (not self.inspection_enabled):
            self.forward_packet(nfqueue)
        else:
            return True  # marking for inspection
Ejemplo n.º 3
0
    def _threshhold_exceeded(self, initial, count):
        protocol_src_limit = self._IPS.connection_limits[self._packet.protocol]
        elapsed_time = self._packet.timestamp - initial
        if (elapsed_time < 2): return False

        connections_per_second = count / elapsed_time
        if (connections_per_second < protocol_src_limit): return False

        # host is now considered active DDOS
        Log.debug(f'CPS: {connections_per_second}')
        return True
Ejemplo n.º 4
0
    def _threshhold_exceeded(self, tracked_ip, packet):
        protocol_src_limit = self._IPS.connection_limits[packet.protocol]
        elapsed_time = packet.timestamp - tracked_ip['initial']
        if (elapsed_time < 2): return False

        if (tracked_ip['count'] / elapsed_time < protocol_src_limit):
            return False

        # host is now considered active DDOS
        Log.debug('CPS: {}'.format(tracked_ip['count'] / elapsed_time))

        return True
Ejemplo n.º 5
0
    def _threshhold_exceeded(self, tracked_ip, packet):
        elapsed_time = packet.timestamp - tracked_ip['initial']
        if (elapsed_time < 2): return False

        protocol_src_limit = self._IPS.connection_limits[packet.protocol]
        if (tracked_ip['count'] / elapsed_time < protocol_src_limit):
            return False

        # host is now marked as engaging in active d/dos attack.
        Log.debug('CPS: {}'.format(tracked_ip['count'] / elapsed_time))

        return True
Ejemplo n.º 6
0
    def _ddos_inspect(self, packet):
        ddos = self.ddos_tracker[packet.protocol]
        with ddos.lock:
            if not self._ddos_detected(ddos.tracker, packet): return

        if (self._IPS.ids_mode):
            Log.log(packet, IPS.LOGGED, engine=IPS.DDOS)

        elif (self._IPS.ddos_prevention):
            IPTableManager.proxy_add_rule(packet.conn.tracked_ip,
                                          table='mangle',
                                          chain='IPS')

            Log.log(packet, IPS.FILTERED, engine=IPS.DDOS)
Ejemplo n.º 7
0
    def _ddos_timeout(self, tracked_ip, ddos_tracker):
        # if marked as an active ddos host, will timeout the conn
        # since we will be dropping all subsequent conn attempts at the kernel level
        if self.active_ddos_hosts.pop(tracked_ip, None): return 'break'

        # if tracked ip hasnt been seen for 10 seconds, it will be removed from the ddos tracker and thread will close
        tracked_connection = ddos_tracker.get(tracked_ip, None)
        last_seen = tracked_connection.get('last_seen')
        if (time.time() - last_seen >= 10):
            ddos_tracker.pop(tracked_ip)
            Log.debug(f'DDOS TIMED OUT CONN: {tracked_ip}')

            return 'break'

        return 5.1
Ejemplo n.º 8
0
    def _ddos_inspect(self):
        ddos = self.ddos_tracker.get(self._packet.protocol)
        with ddos['lock']:
            if not self._ddos_detected(ddos['tracker']): return

        # this is to supress log entries for ddos hosts that are being detected by the engine, but not blocked
        # this behavior would only happen in informational logging mode without block enabled.
        if self._recently_detected(self._packet.conn.tracked_ip): return

        if (self._IPS.ddos_prevention):
            IPTableManager.proxy_add_rule(self._packet.conn.tracked_ip,
                                          table='mangle',
                                          chain='IPS')

        # TODO: add entry for ids mode

        Log.log(self._packet, engine=IPS.DDOS)
Ejemplo n.º 9
0
    def _ddos_detected(self, ddos_tracker, packet):
        tracked_ip = ddos_tracker.get(packet.conn.tracked_ip, None)
        if (not tracked_ip or fast_time() - tracked_ip['last_seen'] > 15):
            self._add_to_tracker(ddos_tracker, packet, engine=IPS.DDOS)

        else:
            tracked_ip['count'] += 1
            tracked_ip['last_seen'] = packet.timestamp

            # if conn limit exceeded and host is not already marked, returns active ddos and add ip to tracker
            if self._threshhold_exceeded(tracked_ip, packet):
                Log.debug(f'ACTIVE BLOCK: {packet.conn.tracked_ip}')

                # this is to supress log entries for ddos hosts that are being detected by the engine since there is a delay
                # between detection and kernel offload or some packets are already in queue
                if (packet.conn.tracked_ip not in self._IPS.fw_rules):
                    self._IPS.fw_rules[
                        packet.conn.tracked_ip] = packet.timestamp

                    return True

        return False
Ejemplo n.º 10
0
    def _portscan_inspect(self, IPS_IDS, packet):
        pscan = self.pscan_tracker[packet.protocol]
        with pscan.lock:
            initial_block, active_scanner, pre_detection_logging = self._portscan_detect(
                pscan.tracker, packet)

        if (not active_scanner):
            Log.debug(
                f'PROXY ACCEPT | {packet.src_ip}:{packet.src_port} > {packet.dst_ip}:{packet.dst_port}.'
            )
            IPS_IDS.forward_packet(packet.nfqueue)

            return

        if (IPS_IDS.ids_mode):
            IPS_IDS.forward_packet(packet.nfqueue)
            block_status = IPS.LOGGED

        elif (IPS_IDS.portscan_prevention):
            packet.nfqueue.drop()

            # if rejection is enabled on top of prevention port uncreachable packets will be sent back to the scanner.
            if (IPS_IDS.portscan_reject):
                self._portscan_reject(pre_detection_logging, packet,
                                      initial_block)

            # if initial block is not set then the current host has already been effectively blocked and does not need
            # to do anything beyond this point.
            if (not initial_block): return

            block_status = self._get_block_status(pre_detection_logging,
                                                  packet.protocol)

        Log.debug(
            f'PROXY INITIAL SCANNER | {block_status.name} | {packet.src_ip}:{packet.src_port} > {packet.dst_ip}:{packet.dst_port}.'
        )

        # NOTE: i think this is stupid. this would effectivly block all portscan logging while passive blocking is
        # active, right???? if that is the case, we need to figure out a different way to deal with this. i think this
        # was to ensure ddos wasnt logged as portscan first, but this doesnt soudn liek a good way to do this anymore.
        if (not IPS_IDS.fw_rules):
            scan_info = IPS_SCAN_RESULTS(initial_block, active_scanner,
                                         block_status)
            Log.log(packet, scan_info, engine=IPS.PORTSCAN)

        else:  # NOTE: for testing purposes only
            Log.debug(
                'ACTIVE DDOS WHEN ATTEMPTING TO LOG PORTSCAN, LOG HAULTED.')
Ejemplo n.º 11
0
    def _portscan_inspect(self, packet):
        # TODO: optimize _IPS reference please! :)
        pscan = self.pscan_tracker[packet.protocol]
        with pscan.lock:
            initial_block, active_scanner, pre_detection_logging = self._portscan_detect(
                pscan.tracker, packet)

        if (not active_scanner):
            Log.debug(
                f'PROXY ACCEPT | {packet.src_ip}:{packet.src_port} > {packet.dst_ip}:{packet.dst_port}.'
            )
            self._IPS.forward_packet(packet.nfqueue)

            return

        if (self._IPS.ids_mode):
            self._IPS.forward_packet(packet.nfqueue)
            block_status = IPS.LOGGED

        elif (self._IPS.portscan_prevention):
            packet.nfqueue.drop()

            # if rejection is enabled on top of prevention port uncreachable packets will be sent back to the scanner.
            if (self._IPS.portscan_reject):
                self._portscan_reject(pre_detection_logging, packet,
                                      initial_block)

            # if initial block is not set then the current host has already been effectively blocked and does not need
            # to do anything beyond this point.
            if (not initial_block): return

            block_status = self._get_block_status(pre_detection_logging,
                                                  packet.protocol)

        Log.debug(
            f'PROXY INITIAL SCANNER | {block_status.name} | {packet.src_ip}:{packet.src_port} > {packet.dst_ip}:{packet.dst_port}.'
        )

        if (not self._IPS.fw_rules):
            scan_info = IPS_SCAN_RESULTS(initial_block, active_scanner,
                                         block_status)
            Log.log(packet, scan_info, engine=IPS.PORTSCAN)

        else:  # NOTE: for testing purposes only
            Log.debug(
                'ACTIVE DDOS WHEN ATTEMPTING TO LOG PORTSCAN, LOG HAULTED.')
Ejemplo n.º 12
0
    def _portscan_inspect(self):
        pscan = self.pscan_tracker.get(self._packet.protocol)
        with pscan['lock']:
            initial_block, active_scanner, pre_detection_logging = self._portscan_detect(
                pscan['tracker'])
        if (not active_scanner):
            Log.informational(
                f'PROXY ACCEPT | {self._packet.src_ip}:{self._packet.src_port} > {self._packet.dst_ip}:{self._packet.dst_port}.'
            )
            self._IPS.forward_packet(self._packet.nfqueue)

            return

        if (self._IPS.portscan_prevention):
            if (self._IPS.ids_mode):
                self._IPS.forward_packet(self._packet.nfqueue)
                block_status = IPS.LOGGED
            else:
                self._packet.nfqueue.drop()

            if (self._IPS.portscan_reject):
                self._portscan_reject(pre_detection_logging)

            if (pre_detection_logging):
                block_status = self._get_block_status(pre_detection_logging)

                Log.informational(
                    f'PROXY ACTIVE SCANNER DROP {self._packet.src_ip}:{self._packet.src_port} > {self._packet.dst_ip}:{self._packet.dst_port}.'
                )
                if (not self.active_ddos):
                    scan_info = IPS_SCAN_RESULTS(initial_block, active_scanner,
                                                 block_status)
                    Log.log(self._packet, scan_info, engine=IPS.PORTSCAN)

                else:  # NOTE: for testing purposes only
                    Log.informational(
                        'ACTIVE DDOS WHEN ATTEMPTING TO LOG PORTSCAN, LOG HAULTED.'
                    )
Ejemplo n.º 13
0
    # to the reject message actually sent
    def _portscan_reject(self, pre_detection_logging, packet, initial_block):
        if (not initial_block):
            self._IPSResponse.prepare_and_send(packet)

        else:
            IPSResponse = self._IPSResponse
            if (packet.protocol is PROTO.TCP):
                for port, seq_num in pre_detection_logging.items():
                    IPSResponse.prepare_and_send(
                        copy(packet).tcp_override(port, seq_num))

            elif (packet.protocol is PROTO.UDP):
                for port, icmp_payload in pre_detection_logging.items():
                    IPSResponse.prepare_and_send(
                        copy(packet).udp_override(icmp_payload))

    def _get_block_status(self, pre_detection_logging, protocol):
        open_ports = self._IPS.open_ports

        for port in pre_detection_logging:
            if port in open_ports[protocol]:
                return IPS.MISSED

        return IPS.BLOCKED


if __name__ == '__main__':
    Log.run(name=LOG_NAME)
    IPS_IDS.run(Log, q_num=2)
Ejemplo n.º 14
0
    # to the reject message actually sent
    def _portscan_reject(self, pre_detection_logging, packet, initial_block):
        if (not initial_block):
            self._IPSResponse.prepare_and_send(packet)

        else:
            IPSResponse = self._IPSResponse
            if (packet.protocol is PROTO.TCP):
                for port, seq_num in pre_detection_logging.items():
                    IPSResponse.prepare_and_send(
                        copy(packet).tcp_override(port, seq_num))

            elif (packet.protocol is PROTO.UDP):
                for port, icmp_payload in pre_detection_logging.items():
                    IPSResponse.prepare_and_send(
                        copy(packet).udp_override(icmp_payload))

    def _get_block_status(self, pre_detection_logging, protocol):
        open_ports = self._IPS.open_ports

        for port in pre_detection_logging:
            if port in open_ports[protocol]:
                return IPS.MISSED

        return IPS.BLOCKED


if __name__ == '__main__':
    Log.run(name=LOG_NAME, verbose=VERBOSE, root=ROOT)
    IPS_IDS.run(Log, q_num=2)