class PingOfDeath(object):
    """PingOfDeath class."""
    def __init__(self, debug=False):
        """
        Initialize PingOfDeath.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = logger.SecureTeaLogger(__name__, debug=debug)

        # Initialize threshold
        self._THRESHOLD = 60000

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect(self, pkt):
        """
        Detect ping of death attack
        by calculating load threshold.

        Args:
            pkt (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if (pkt.haslayer(scapy.IP) and pkt.haslayer(scapy.ICMP)):
            # If packet has load
            if pkt.haslayer(scapy.Raw):

                load_len = len(pkt[scapy.Raw].load)

                if (load_len >= self._THRESHOLD):
                    source_ip = pkt[scapy.IP].src
                    msg = "Possible ping of death attack detected " \
                          "from: {}".format(source_ip)
                    self.logger.log(msg, logtype="warning")
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(source_ip.strip(" "))
                    # Write malicious IP to file
                    write_mal_ip(str(source_ip).strip(" "))
Exemplo n.º 2
0
class SSHLogin(object):
    """SSHLogin Class."""

    def __init__(self, debug=False):
        """
        Initialize SSHLogin.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = logger.SecureTeaLogger(
                __name__,
                debug=debug
        )

        # OS name to SSH-log path map
        self.system_log_map = {
            "debian": "/var/log/auth.log"
        }

        os_name = utils.categorize_os()
        self.log_file = None

        if os_name:
            try:
                self.log_file = self.system_log_map[os_name]
            except KeyError:
                self.logger.log(
                    "Could not find path for the SSH-log file",
                    logtype="error"
                )
                return
        else:
            return

        # Salt to generate hashed username
        self.SALT = "<!@?>"

        # Regex to extract invalid SSH login details
        self.INVALID_USER = r'^([a-zA-Z]+\s[0-9]+)\s([0-9]+:[0-9]+:[0-9]+).*' \
                            r'Invalid\suser\s([a-zA-Z0-9_-]+)\sfrom\s([0-9]+\.' \
                            r'[0-9]+\.[0-9]+\.[0-9]+)'

        # Initialize username to IP dict
        self.username_dict = dict()

        # Set threshold to 5 attempts per second to detect brute-force
        self.THRESHOLD = 5  # inter = 0.2

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def parse_log_file(self):
        """
        Parse log file to extract invalid SSH user /
        their authentication failure / login attempts.

        Args:
            None

        Raises:
            None

        Returns:
            None
        """
        # Open the log file
        log_file_data = utils.open_file(self.log_file)
        for line in log_file_data:
            found = re.findall(self.INVALID_USER, line)
            if (found is not None and found != []):
                date = found[0][0]
                month = date.split(" ")[0]
                day = date.split(" ")[1]
                last_time = found[0][1]
                username = found[0][2]
                ip = found[0][3]

                # convert date, time to epoch time
                epoch_time = utils.get_epoch_time(month, day, last_time)
                self.update_username_dict(username, ip, date, epoch_time)

    def update_username_dict(self, username, ip, date, epoch_time):
        """
        Update username to IP dict with the
        new set of IP & failure attempts on a
        given day for a particular user.

        Args:
            username (str): Name of the account being tried to access
            ip (str): IP address of the source
            date (str): Date of action (eg. Jun 1)
            epoch_time (int): Time during the attempt in epoch format

        Raises:
            None

        Returns:
            None
        """
        # Generate a hashed username using salt
        hashed_username = username + self.SALT + date
        if self.username_dict.get(hashed_username) is None:
            # if user not in dict, add to dict
            self.username_dict[hashed_username] = {
                "ip": [ip],
                "last_time": epoch_time,
                "count": 1
            }
        else:
            # if user in dict, update user IP address & count
            if ip not in self.username_dict[hashed_username]["ip"]:
                self.username_dict[hashed_username]["ip"].append(ip)
            prev_count = self.username_dict[hashed_username]["count"]
            new_count = prev_count + 1
            self.username_dict[hashed_username]["count"] = new_count

    def check_ssh_bruteforce(self):
        """
        Check for SSH brute-force by comparing
        the calculated ratio with the set threshold.

        Args:
            None

        Raises:
            None

        Returns:
            None
        """
        for user in self.username_dict.keys():
            no_of_ip = len(self.username_dict[user]["ip"])
            count = self.username_dict[user]["count"]
            last_time = self.username_dict[user]["last_time"]
            current_time = time.time()

            try:
                delta_time = int(current_time - last_time)
                calc_threshold_ip = no_of_ip / delta_time
                calc_threshold_count = count / delta_time
            except ZeroDivisionError:
                calc_threshold_ip = int(no_of_ip)
                calc_threshold_count = int(count)

            if (calc_threshold_ip > self.THRESHOLD or
                calc_threshold_count > self.THRESHOLD):
                if no_of_ip == 1:  # if a single IP in user list
                    msg = "Possible SSH brute force detected for the user: "******" from: " + \
                           self.username_dict[user]["ip"][0] + " on: " + \
                           user.split(self.SALT)[1]
                    self.logger.log(
                        msg,
                        logtype="warning"
                    )
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(self.username_dict[user]["ip"][0].strip(" "))
                else:
                    for ip in self.username_dict[user]["ip"]:
                        msg = "Possible SSH brute force detected for the user: "******" from: " + ip + " on: " + \
                               user.split(self.SALT)[1]
                        self.logger.log(
                            msg,
                            logtype="warning"
                        )
                        # Generate CSV report using OSINT tools
                        self.osint_obj.perform_osint_scan(ip.strip(" "))

    def run(self):
        """
        Start monitoring the SSH log file for
        login attempts & possible password brute-force.

        Args:
            None

        Raises:
            None

        Returns:
            None
        """
        if self.log_file:  # if path of SSH-log file is valid
            # Rotate & parse the log file
            self.parse_log_file()
            # Analyze the log for brute-force
            self.check_ssh_bruteforce()
            # Empty the dict to rotate the log-file
            self.username_dict.clear()
Exemplo n.º 3
0
class WebShell(object):
    """WebShell Class."""
    def __init__(self, debug=False, test=False):
        """
        Initialize WebShell.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = ServerLogger(__name__, debug=debug)

        if test:
            # Path of file containing web_shell payloads
            self.PAYLOAD_FILE = "securetea/lib/log_monitor/server_log/rules/payloads/web_shell.txt"
        else:
            # Path of file containing web_shell payloads
            self.PAYLOAD_FILE = "/etc/securetea/log_monitor/server_log/payloads/web_shell.txt"

        # Load web_shell payloads
        self.payloads = utils.open_file(self.PAYLOAD_FILE)

        # Logged IP list
        self.logged_IP = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_web_shell(self, data):
        """
        Detect possible Web Shell attacks.
        Use string comparison to scan GET request with the
        list of possible web shell payloads.

        Args:
            data (dict): Parsed log file data

        Raises:
            None

        Returns:
            None
        """
        for ip in data.keys():
            get_req = data[ip]["get"]
            if (self.payload_match(get_req)):
                if ip not in self.logged_IP:  # if not logged earlier
                    self.logged_IP.append(ip)
                    last_time = data[ip]["ep_time"][0]
                    msg = "Possible web shell detected from: " + str(ip) + \
                          " on: " + str(utils.epoch_to_date(last_time))
                    self.logger.log(msg, logtype="warning")
                    utils.write_ip(str(ip))
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(ip.strip(" "))
                    # Write malicious IP to file, to teach Firewall about the IP
                    write_mal_ip(ip.strip(" "))

    def payload_match(self, get_req):
        """
        Match parsed GET request for a
        possible web shell payload.

        Args:
            get_req (str): GET request on which to perform
                           payload string matching

        Raises:
            None

        Returns:
            TYPE: bool
        """
        for req in get_req:
            for payload in self.payloads:
                payload = payload.strip(" ").strip("\n")
                if (payload in req or utils.uri_encode(payload) in req):
                    return True
Exemplo n.º 4
0
class DDoS(object):
    """DDoS Class."""
    def __init__(self, debug=False):
        """
        Initialize DDoS.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = ServerLogger(__name__, debug=debug)

        # Initialize threshold to 1000 packets per second
        self._SISP_THRESHOLD = 1000  # inter = 0.001
        self._SIMP_THRESHOLD = 100  # 100 different IPs that trigger SISP DoS

        # List of IPs
        self.SISP_LIST = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_ddos(self, data):
        """
        Detect DoS attack. Classify DoS attack into two categories:
        - Single IP Single Port DoS Attack
        - Single IP Multiple Port DoS Attack
        Look for IP addresses having high number of GET request and
        a small time difference to predict SISP DoS attack.
        High number of alarms triggered for SISP DoS attack indicates
        MISP DoS attack.

        Args:
            data (dict): Parsed log file data

        Raises:
            None

        Returns:
            None
        """
        for ip in data.keys():
            count = data[ip]["count"]
            last_time = data[ip]["ep_time"][0]
            initial_time = data[ip]["ep_time"][int(
                len(data[ip]["ep_time"]) - 1)]
            delta = abs(int(last_time - initial_time))

            try:
                calc_count_thresh = int(count / delta)
            except ZeroDivisionError:
                calc_count_thresh = int(count)

            if calc_count_thresh > self._SISP_THRESHOLD:  # if crosses threshold, trigger alarm
                msg = "Possible Single IP DoS Attack Detected from: " + \
                       str(ip) + " on: " + utils.epoch_to_date(last_time)
                self.logger.log(msg, logtype="warning")
                if ip not in self.SISP_LIST:
                    self.SISP_LIST.append(ip)
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(ip.strip(" "))
                    # Write malicious IP to file, to teach Firewall about the IP
                    write_mal_ip(ip.strip(" "))

            if len(self.SISP_LIST
                   ) > self._SIMP_THRESHOLD:  # if no. of SISP is huge
                for ip in self.SISP_LIST:
                    self.logger.log(
                        "Possible Multiple IP DoS Attack Detected from: " +
                        str(ip),
                        logtype="warning")
Exemplo n.º 5
0
class PortScan(object):
    """PortScan Class."""
    def __init__(self, debug=False, test=False):
        """
        Initialize PortScan.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = ServerLogger(__name__, debug=debug)

        if test:
            # Path of file containing port_scan payloads
            self.PAYLOAD_FILE = "securetea/lib/log_monitor/server_log/rules/payloads/port_scan_ua.txt"
        else:
            # Path of file containing port_scan payloads
            self.PAYLOAD_FILE = "/etc/securetea/log_monitor/server_log/payloads/port_scan_ua.txt"

        # Load port_scan payloads
        self.payloads = utils.open_file(self.PAYLOAD_FILE)

        # List of IPs
        self.logged_IP = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_port_scan(self, data):
        """
        Detect possible Port Scan recon attacks.
        Look for a possible port scan user agent payload
        in the user agent field.

        Args:
            data (dict): Parsed log file data

        Raises:
            None

        Returns:
            None
        """
        for ip in data.keys():
            user_agent = data[ip]["ua"]
            if (self.payload_match(user_agent)):
                if ip not in self.logged_IP:
                    self.logged_IP.append(ip)
                    last_time = data[ip]["ep_time"][0]
                    msg = "Possible port scan detected from: " + str(ip) + \
                          " on: " + utils.epoch_to_date(last_time)
                    self.logger.log(msg, logtype="warning")
                    utils.write_ip(str(ip))
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(ip.strip(" "))
                    # Write malicious IP to file, to teach Firewall about the IP
                    write_mal_ip(ip.strip(" "))

    def payload_match(self, user_agent):
        """
        Match parsed user agent for a
        possible port scan user agent payload.

        Args:
            user_agent (str): User agent on which to perform
                              payload string matching

        Raises:
            None

        Returns:
            TYPE: bool
        """
        for agent in user_agent:
            for payload in self.payloads:
                payload = payload.strip(" ").strip("\n")
                if payload in agent:
                    return True
Exemplo n.º 6
0
class DetectRecon(object):
    """Class for DetectRecon."""
    def __init__(self, threshold=None, debug=False):
        """Initialize DetectRecon class.

        Args:
            threshold (integer): Threshold ratio limit
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None

        Working:
            Detect the following possible probe (reconnaissance) attacks
            (performed for information gathering):

            - TCP ACK / Window Scan
            - UDP Scan
            - ICMP Scan
            - FIN Scan
            - NULL Scan
            - XMAS Scan
            - OS fingerprinting Scan
        """

        # Initialize logger
        self.logger = logger.SecureTeaLogger(__name__, debug)

        # Set threshold
        if not threshold:
            self._THRESHOLD = 100
        else:
            try:
                self._THRESHOLD = int(threshold)
            except ValueError:
                self.logger.log("Incorrent threshold, need an integer value.",
                                logtype="error")
                sys.exit(0)

        # Set count threshold
        self._COUNT = self._THRESHOLD * 1000

        # Initialize empty dicts to store IPs
        self.tcp_ack = dict()
        self.icmp_scan = dict()
        self.udp_scan = dict()
        self.fin_scan = dict()
        self.xmas_scan = dict()
        self.null_scan = dict()
        self.os_scan = dict()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_tcp_ack(self, packet=None):
        """
        Detect possible TCP ACK / Window scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if packet.haslayer(scapy.TCP):
                flag = str(packet[scapy.TCP].flags)
                if (flag == "A"):
                    packet_ip = None
                    try:
                        packet_ip = str(packet[scapy.IP].src)
                    except Exception as e:
                        # If IP layer is missing
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
                    if packet_ip:
                        try:
                            # Check if the IP exists in the dict or not
                            count = self.tcp_ack[packet_ip]["count"]
                            new_port = int(packet[scapy.TCP].dport)
                            if (new_port
                                    not in self.tcp_ack[packet_ip]["ports"]):
                                self.tcp_ack[packet_ip]["ports"].append(
                                    new_port)
                            self.tcp_ack[packet_ip]["count"] = count + 1
                        except KeyError:
                            # Packet from a new IP address
                            self.tcp_ack[packet_ip] = {
                                "start_time": time.time(),
                                "count": 1,
                                "ports": [int(packet[scapy.TCP].dport)]
                            }
                        except Exception as e:
                            self.logger.log("Error occurred: " + str(e),
                                            logtype="error")
            # Check if there has been an intrusion attack
            self.calc_intrusion(scan_dict=self.tcp_ack,
                                msg="TCP ACK / Window Scan detected")

    def detect_udp(self, packet=None):
        """
        Detect possible UDP scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if packet.haslayer(scapy.UDP):
                packet_ip = None
                try:
                    packet_ip = str(packet[scapy.IP].src)
                except Exception as e:
                    # If IP layer is missing
                    self.logger.log("Error occurred: " + str(e),
                                    logtype="error")
                if packet_ip:
                    try:
                        # Check if the IP exists in the dict or not
                        count = self.udp_scan[packet_ip]["count"]
                        new_port = int(packet[scapy.UDP].dport)
                        if (new_port not in self.udp_scan[packet_ip]["ports"]):
                            self.udp_scan[packet_ip]["ports"].append(new_port)
                        self.udp_scan[packet_ip]["count"] = count + 1
                    except KeyError:
                        # Packet from a new IP address
                        self.udp_scan[packet_ip] = {
                            "start_time": time.time(),
                            "count": 1,
                            "ports": [int(packet[scapy.UDP].dport)]
                        }
                    except Exception as e:
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
        # Check if there has been an intrusion attack
        self.calc_intrusion(scan_dict=self.udp_scan, msg="UDP Scan detected")

    def detect_icmp(self, packet=None):
        """
        Detect possible ICMP scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if (packet.haslayer(scapy.ICMP) and packet.haslayer(scapy.Ether)):

                dst = str(packet[scapy.Ether].dst)
                if (dst == "ff:ff:ff:ff:ff:ff"
                        and (int(packet[scapy.ICMP].type) == 8)):
                    packet_ip = None
                    try:
                        packet_ip = str(packet[scapy.IP].src)
                    except Exception as e:
                        # If IP layer is missing
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
                    if packet_ip:
                        try:
                            # Check if the IP exists in the dict ot not
                            count = self.icmp_scan[packet_ip]["count"]
                            sellf.icmp_scan[packet_ip]["count"] = count + 1
                        except KeyError:
                            # Packet from a new IP address
                            self.icmp_scan[packet_ip] = {
                                "start_time": time.time(),
                                "count": 1
                            }
                        except Exception as e:
                            self.logger.log("Error occurred: " + str(e),
                                            logtype="error")
            # Check if there has been an intrusion attack
            for key in self.icmp_scan.keys():
                current_time = time.time()
                start_time = self.icmp_scan[key]["start_time"]
                delta_time = int(current_time - start_time)
                count = int(self.icmp_scan[key]["count"])

                try:
                    calc_threshold = int(count / delta_time)
                except ZeroDivisionError:
                    calc_threshold = int(count)

                if (calc_threshold > self._THRESHOLD):
                    self.logger.log("ICMP Scan detected from: " + str(key),
                                    logtype="warning")

    def detect_os_scan(self, packet):
        """
        Detect possible OS fingerprinting scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if packet.haslayer(scapy.TCP):
                flag = str(packet[scapy.TCP].flags)
                if ("SF" in flag or "FS" in flag):
                    packet_ip = None
                    try:
                        packet_ip = str(packet[scapy.IP].src)
                    except Exception as e:
                        # If IP layer is missing
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
                    if packet_ip:
                        try:
                            # Check if the IP exists in the dict or not
                            count = self.os_scan[packet_ip]["count"]
                            new_port = int(packet[scapy.TCP].dport)
                            if (new_port
                                    not in self.os_scan[packet_ip]["ports"]):
                                self.os_scan[packet_ip]["ports"].append(
                                    new_port)
                            self.os_scan[packet_ip]["count"] = count + 1
                        except KeyError:
                            # Packet from a new IP address
                            self.os_scan[packet_ip] = {
                                "start_time": time.time(),
                                "count": 1,
                                "ports": [int(packet[scapy.TCP].dport)]
                            }
                        except Exception as e:
                            self.logger.log("Error occurred: " + str(e),
                                            logtype="error")
            # Check if there has been an intrusion attack
            self.calc_intrusion(scan_dict=self.os_scan,
                                msg="OS Fingerprinting Scan detected")

    def detect_fin_scan(self, packet):
        """
        Detect possible FIN scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if packet.haslayer(scapy.TCP):
                flag = str(packet[scapy.TCP].flags)
                if (flag == "F"):
                    packet_ip = None
                    try:
                        packet_ip = str(packet[scapy.IP].src)
                    except Exception as e:
                        # If IP layer is missing
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
                    if packet_ip:
                        try:
                            # Check if the IP exists in the dict or not
                            count = self.fin_scan[packet_ip]["count"]
                            new_port = int(packet[scapy.TCP].dport)
                            if (new_port
                                    not in self.fin_scan[packet_ip]["ports"]):
                                self.fin_scan[packet_ip]["ports"].append(
                                    new_port)
                            self.fin_scan[packet_ip]["count"] = count + 1
                        except KeyError:
                            # Packet from a new IP address
                            self.fin_scan[packet_ip] = {
                                "start_time": time.time(),
                                "count": 1,
                                "ports": [int(packet[scapy.TCP].dport)]
                            }
                        except Exception as e:
                            self.logger.log("Error occurred: " + str(e),
                                            logtype="error")
            # Check if there has been an intrusion attack
            self.calc_intrusion(scan_dict=self.fin_scan,
                                msg="FIN Scan detected")

    def detect_xmas_scan(self, packet=None):
        """
        Detect possible XMAS scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if packet.haslayer(scapy.TCP):
                flag = str(packet[scapy.TCP].flags)
                if (flag == "FPU"):
                    packet_ip = None
                    try:
                        packet_ip = str(packet[scapy.IP].src)
                    except Exception as e:
                        # If IP layer is missing
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
                    if packet_ip:
                        try:
                            # Check if the IP exists in the dict or not
                            count = self.xmas_scan[packet_ip]["count"]
                            new_port = int(packet[scapy.TCP].dport)
                            if (new_port
                                    not in self.xmas_scan[packet_ip]["ports"]):
                                self.xmas_scan[packet_ip]["ports"].append(
                                    new_port)
                            self.xmas_scan[packet_ip]["count"] = count + 1
                        except KeyError:
                            # Packet from a new IP address
                            self.xmas_scan[packet_ip] = {
                                "start_time": time.time(),
                                "count": 1,
                                "ports": [int(packet[scapy.TCP].dport)]
                            }
                        except Exception as e:
                            self.logger.log("Error occurred: " + str(e),
                                            logtype="error")
            # Check if there has been an intrusion attack
            self.calc_intrusion(scan_dict=self.xmas_scan,
                                msg="XMAS Scan detected")

    def detect_null_scan(self, packet):
        """
        Detect possible NULL scan.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        if packet is not None:
            if packet.haslayer(scapy.TCP):
                flag = packet[scapy.TCP].flags
                if flag is None:
                    packet_ip = None
                    try:
                        packet_ip = str(packet[scapy.IP].src)
                    except Exception as e:
                        # If IP layer is missing
                        self.logger.log("Error occurred: " + str(e),
                                        logtype="error")
                    if packet_ip:
                        try:
                            # Check if the IP exists in the dict or not
                            count = self.null_scan[packet_ip]["count"]
                            new_port = int(packet[scapy.TCP].dport)
                            if (new_port
                                    not in self.null_scan[packet_ip]["ports"]):
                                self.null_scan[packet_ip]["ports"].append(
                                    new_port)
                            self.null_scan[packet_ip]["count"] = count + 1
                        except KeyError:
                            # Packet from a new IP address
                            self.null_scan[packet_ip] = {
                                "start_time": time.time(),
                                "count": 1,
                                "ports": [int(packet[scapy.TCP].dport)]
                            }
                        except Exception as e:
                            self.logger.log("Error occurred: " + str(e),
                                            logtype="error")
            # Check if there has been an intrusion attack
            self.calc_intrusion(scan_dict=self.null_scan,
                                msg="NULL Scan detected")

    def calc_intrusion(self, scan_dict, msg):
        """
        Detect intrusion by comparing observed and expected
        threshold ratio.

        Args:
            scan_dict (dict): IP dictionary
            msg (str): Message to display when intrusion is detected

        Raises:
            None

        Returns:
            None
        """
        for key in scan_dict.keys():
            current_time = time.time()
            start_time = scan_dict[key]["start_time"]
            port_len = len(scan_dict[key]["ports"])
            count = scan_dict[key]["count"]
            delta_time = int(current_time - start_time)

            try:
                calc_threshold = int(port_len / delta_time)
            except ZeroDivisionError:
                calc_threshold = int(port_len)

            if (calc_threshold >= self._THRESHOLD or count >= self._COUNT):
                # Intrusion detected
                new_msg = msg + " from IP: " + str(key)
                self.logger.log(new_msg, logtype="warning")
                # Generate CSV report using OSINT tools
                self.osint_obj.perform_osint_scan(str(key).strip(" "))
                # Write malicious IP to file
                write_mal_ip(str(key).strip(" "))

    def run(self, packet):
        """
        Start to detect reconnaissance attacks.

        Args:
            packet (scapy_object): Packet to dissect and observe

        Raises:
            None

        Returns:
            None
        """
        # Detect general scans
        self.detect_tcp_ack(packet)
        self.detect_udp(packet)
        self.detect_icmp(packet)

        # Detect stealth scans
        self.detect_fin_scan(packet)
        self.detect_xmas_scan(packet)
        self.detect_null_scan(packet)

        # Detect OS fingerprinting scans
        self.detect_os_scan(packet)
Exemplo n.º 7
0
class PacketFilter(object):
    """Class for PacketFilter."""
    def __init__(self,
                 interface=None,
                 debug=False,
                 ip_inbound=None,
                 ip_outbound=None,
                 protocols=None,
                 dns=None,
                 dports=None,
                 sports=None,
                 extensions=None,
                 action_inbound_IPRule=0,
                 action_outbound_IPRule=0,
                 action_DNSRule=0,
                 action_source_portRule=0,
                 action_dest_portRule=0,
                 action_HTTPResponse=1,
                 action_HTTPRequest=1,
                 action_protocolRule=0,
                 action_scanLoad=0,
                 test=False):
        """Initilize PacketFilter class."""

        self.logger = logger.SecureTeaLogger(__name__, debug)

        # Initialize with empty list
        if ip_inbound is None:
            ip_inbound = []
        if ip_outbound is None:
            ip_outbound = []
        if protocols is None:
            protocols = []
        if dns is None:
            dns = []
        if sports is None:
            sports = []
        if dports is None:
            dports = []
        if extensions is None:
            extensions = []

        self._action_inbound_IPRule = action_inbound_IPRule
        self._action_outbound_IPRule = action_outbound_IPRule
        self._action_protocolRule = action_protocolRule
        self._action_DNSRule = action_DNSRule
        self._action_source_portRule = action_source_portRule
        self._action_dest_portRule = action_dest_portRule
        self._action_HTTPRequest = action_HTTPRequest
        self._action_HTTPResponse = action_HTTPResponse
        self._action_scanLoad = action_scanLoad

        self._IP_INBOUND = ip_inbound
        self._IP_OUTBOUND = ip_outbound
        self._PROTCOLS = protocols
        self._DNS = dns
        self._DPORTS = dports
        self._SPORTS = sports
        self._EXTENSIONS = extensions

        if not test:  # Avoid generating PCAP file during test run
            # Initialize PcapWriter for PCAP dumping
            self.pktdump = PcapWriter("blocked.pcap", append=True, sync=True)
        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

        # Malicious IP file path
        self._MAL_IP_PATH = "/etc/securetea/mal_ip.txt"

    @utils.xnor
    def inbound_IPRule(self, scapy_pkt):
        """
        Filter packet based on the specified
        inbound IP rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.IP):
            if (str(scapy_pkt[scapy.IP].src) in self._IP_INBOUND):
                return {'action': self._action_inbound_IPRule, 'result': 1}
            else:
                return {'action': self._action_inbound_IPRule, 'result': 0}
        else:
            return {'action': self._action_inbound_IPRule, 'result': 0}

    @utils.xnor
    def outbound_IPRule(self, scapy_pkt):
        """
        Filter packet based on the specified
        outbound IP rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.IP):
            if (str(scapy_pkt[scapy.IP].dst) in self._IP_OUTBOUND):
                return {'action': self._action_outbound_IPRule, 'result': 1}
            else:
                return {'action': self._action_outbound_IPRule, 'result': 0}
        else:
            return {'action': self._action_outbound_IPRule, 'result': 0}

    @utils.xnor
    def protocolRule(self, scapy_pkt):
        """
        Filter packet based on the specified
        protocols.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.IP):
            if (str(scapy_pkt[scapy.IP].proto) in self._PROTCOLS):
                return {'action': self._action_protocolRule, 'result': 1}
            else:
                return {'action': self._action_protocolRule, 'result': 0}
        else:
            return {'action': self._action_protocolRule, 'result': 0}

    @utils.xnor
    def DNSRule(self, scapy_pkt):
        """
        Filter packet based on the specified
        DNS rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.DNSRR):
            qname = scapy_pkt[scapy.DNSQR].qname.decode('utf-8')
            if len(self._DNS):
                for dns in self._DNS:
                    if dns in str(qname.strip()):
                        return {'action': self._action_DNSRule, 'result': 1}
                    else:
                        return {'action': self._action_DNSRule, 'result': 0}
            else:
                return {'action': self._action_DNSRule, 'result': 0}
        else:
            return {'action': self._action_DNSRule, 'result': 0}

    @utils.xnor
    def source_portRule(self, scapy_pkt):
        """
        Filter packet based on the specified
        source port rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.Raw):
            if str(scapy_pkt[scapy.TCP].sport) in self._SPORTS:
                return {'action': self._action_source_portRule, 'result': 1}
            else:
                return {'action': self._action_source_portRule, 'result': 0}
        else:
            return {'action': self._action_source_portRule, 'result': 0}

    @utils.xnor
    def dest_portRule(self, scapy_pkt):
        """
        Filter packet based on the specified
        destination port rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.Raw):
            if str(scapy_pkt[scapy.TCP].dport) in self._DPORTS:
                return {'action': self._action_dest_portRule, 'result': 1}
            else:
                return {'action': self._action_dest_portRule, 'result': 0}
        else:
            return {'action': self._action_dest_portRule, 'result': 0}

    def HTTPRequest(self, scapy_pkt):
        """
        Filter packet based on the specified
        HTTPRequest rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        try:
            if scapy_pkt.haslayer(scapy.Raw):
                if scapy_pkt[scapy.TCP].dport == 80:
                    # User defined action
                    return self._action_HTTPRequest
                else:
                    # Allow if not found
                    return 1
            else:
                # Allow if not found
                return 1
        except Exception as e:
            self.logger.log(str(e), logtype="error")
            return 1

    def HTTPResponse(self, scapy_pkt):
        """
        Filter packet based on the specified
        HTTP Response rules.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        try:
            if scapy_pkt.haslayer(scapy.Raw):
                if scapy_pkt[scapy.TCP].sport == 80:
                    # User defined action
                    return self._action_HTTPResponse
                else:
                    # Allow if not found
                    return 1
            else:
                # Allow if not found
                return 1
        except Exception as e:
            self.logger.log(str(e), logtype="error")
            return 1

    @utils.xnor
    def scanLoad(self, scapy_pkt):
        """
        Filter packet based on the specified
        scan load rules i.e. scan for the extensions.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            dict:
                'action': User specified action
                'result': Rule matched or not
        """
        if scapy_pkt.haslayer(scapy.Raw):
            if scapy_pkt[scapy.TCP].dport == 80:
                for extension in self.extensions:
                    if extension in scapy_pkt[scapy.Raw].load:
                        return {'action': self._action_scanLoad, 'result': 1}
                    else:
                        return {'action': self._action_scanLoad, 'result': 0}
            else:
                return {'action': self._action_scanLoad, 'result': 0}
        else:
            return {'action': self._action_scanLoad, 'result': 0}

    @staticmethod
    def check_first_fragment(pkt):
        """
        Check first fragment. Drop a packet if
        flag is "MF", offset value = 0 & total
        length < 120.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP)):
            if ((str(pkt[scapy.IP].flags) == "MF")
                    and int(pkt[scapy.IP].frag) == 0
                    and int(pkt[scapy.IP].len) < 120):
                return 0
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_ip_version(pkt):
        """
        Check for unknown IP version

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP)):
            version = int(pkt[scapy.IP].version)
            if (version == 4 or version == 6):
                return 1
            else:
                return 0
        else:
            return 1

    @staticmethod
    def check_ip_fragment_boundary(pkt):
        """
        Check IP fragment boundary. Drop a packet if
        packet length + fragmentation offset > 65355

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP)):
            if ((int(pkt[scapy.IP].len) + int(pkt[scapy.IP].frag)) > 65355):
                return 0
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_ip_fragment_offset(pkt):
        """
        Check IP fragment small offset. Drop a packet if
        0 < fragmentation offset < 60

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP)):
            frag = int(pkt[scapy.IP].frag)
            if (frag < 60 and frag > 0):
                return 0
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_invalid_ip(pkt):
        """
        Check invalid IP. Drop a packet if IP
        is invalid or is 0.0.0.0.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP)):
            source_ip = pkt[scapy.IP].src
            if (utils.check_ip(source_ip) and str(source_ip) != "0.0.0.0"):
                return 1
            else:
                return 0
        else:
            return 1

    @staticmethod
    def check_ip_header_length(pkt):
        """
        Check invalid IP header length. Drop a
        packet if length < 20 bytes.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP)):
            hlen = pkt[scapy.IP].len
            if int(hlen) < 20:
                return 0
            else:
                return 1
        else:
            return 1

    @staticmethod
    def icmp_fragmentation_attack(pkt):
        """
        Check for ICMP fragmentation. Drop a packet if
        protocol is set to ICMP, and IP flag is set to "MF" or
        fragment offset > 0.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if pkt.haslayer(scapy.IP):
            proto = int(pkt[scapy.IP].proto)
            if proto == 1:
                flags = str(pkt[scapy.IP].flags)
                frag = int(pkt[scapy.IP].frag)
                if (flags == "MF" or frag > 0):
                    return 0
                else:
                    return 1
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_large_icmp(pkt):
        """
        Check for large ICMP. Drop a packet if
        protocol is set to ICMP, and length > 1024 bytes.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if pkt.haslayer(scapy.IP):
            proto = int(pkt[scapy.IP].proto)
            if proto == 1:
                hlen = int(pkt[scapy.IP].len)
                if (hlen > 1024):
                    return 0
                else:
                    return 1
            else:
                return 1
        else:
            return 1

    @staticmethod
    def syn_fragmentation_attack(pkt):
        """
        Check for SYN fragmentation. Drop a packet if
        SYN flag is set, and IP flag is set to "MF" or
        fragment offset > 0.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if (pkt.haslayer(scapy.IP) and pkt.haslayer(scapy.TCP)):
            tcp_flag = pkt[scapy.TCP].flags
            if tcp_flag == "S":
                flags = str(pkt[scapy.IP].flags)
                frag = int(pkt[scapy.IP].frag)
                if (flags == "MF" or frag > 0):
                    return 0
                else:
                    return 1
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_fin_ack(pkt):
        """
        Check whether “FIN” flag is set but not “ACK”.
        TCP segments with the FIN flag set also have the ACK
        flag set to acknowledge the previous packet received.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if pkt.haslayer(scapy.TCP):
            flag = str(pkt[scapy.TCP].flags)
            if "F" in flag:
                if (flag == "FA" or flag == "AF"):
                    return 1
                else:
                    return 0
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_tcp_flag(pkt):
        """
        Check TCP flag. Drop a
        packet if TCP flag is None.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if pkt.haslayer(scapy.TCP):
            flag = pkt[scapy.TCP].flags
            if flag is None:
                return 0
            else:
                return 1
        else:
            return 1

    @staticmethod
    def check_network_congestion(pkt):
        """
        Enable network congestion detection by
        observing “ECE” flag at the TCP
        layer to reject packets.

        Args:
            scapy_pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        if pkt.haslayer(scapy.TCP):
            flag = str(pkt[scapy.TCP].flags)
            if (flag == "EC" or flag == "ECE"):
                return 0
            else:
                return 1
        else:
            return 1

    def check_mal_ip(self, pkt):
        """
        Check whether the source IP of the packet
        arriving is in the malicious IP list.

        Args:
            pkt (scapy_object): Packet to filter

        Raises:
            None

        Returns:
            bool (int): Allow or drop
        """
        ip_list = utils.open_file(self._MAL_IP_PATH)
        source_ip = pkt[scapy.IP].src
        source_ip = source_ip.strip(" ")

        for ip in ip_list:
            ip = ip.strip(" ").strip("\n")
            if source_ip == ip:
                return 0
        return 1

    def process(self, pkt):
        """
        Check whether the packet passed matches
        all the rules or not.

        Args:
            pkt: Packet

        Raises:
            None

        Returns:
            int: 1 if to allow, 0 to block
        """
        scapy_pkt = scapy.IP(pkt.get_payload())

        if (self.inbound_IPRule(scapy_pkt) and self.outbound_IPRule(scapy_pkt)
                and self.protocolRule(scapy_pkt) and self.DNSRule(scapy_pkt)
                and self.source_portRule(scapy_pkt)
                and self.dest_portRule(scapy_pkt)
                and self.HTTPResponse(scapy_pkt)
                and self.HTTPRequest(scapy_pkt)
                and self.check_first_fragment(scapy_pkt)
                and self.check_ip_version(scapy_pkt)
                and self.check_ip_fragment_boundary(scapy_pkt)
                and self.check_ip_fragment_offset(scapy_pkt)
                and self.check_invalid_ip(scapy_pkt)
                and self.check_ip_header_length(scapy_pkt)
                and self.icmp_fragmentation_attack(scapy_pkt)
                and self.check_large_icmp(scapy_pkt)
                and self.syn_fragmentation_attack(scapy_pkt)
                and self.check_fin_ack(scapy_pkt)
                and self.check_tcp_flag(scapy_pkt)
                and self.check_network_congestion(scapy_pkt)
                and self.check_mal_ip(scapy_pkt)):
            return 1
        else:
            self.logger.log("Packet blocked.", logtype="info")
            # PCAP dumping of rejected packets
            self.pktdump.write(scapy_pkt)
            # Generate report using OSINT tools
            src_ip = scapy_pkt[scapy.IP].src
            src_ip = src_ip.strip(" ")
            self.osint_obj.perform_osint_scan(src_ip)
            return 0
Exemplo n.º 8
0
class SpiderDetect(object):
    """SpiderDetect Class."""
    def __init__(self, debug=False):
        """
        Initialize SpiderDetect.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = ServerLogger(__name__, debug=debug)

        # Path of file containing spider user agents payloads
        self._PAYLOAD_FILE = "securetea/lib/log_monitor/server_log/rules/payloads/bad_ua.txt"

        # Load spider user agents payloads
        self.payloads = utils.open_file(self._PAYLOAD_FILE)

        # Initialize threshold to 50 request / second
        self._THRESHOLD = 50  # inter = 0.02

        # List of IPs
        self.logged_IP = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_spider(self, data):
        """
        Detect possible Web Crawler / Spider / Bad user agents.
        High amount of unique GET request from an IP within a
        small period of time are likely to indicate a web crawler /
        spider.

        Look for bad user agents payload to guess a bad user agent.

        Args:
            data (dict): Parsed log file data

        Raises:
            None

        Returns:
            None
        """
        for ip in data.keys():
            count = data[ip]["count"]
            last_time = data[ip]["ep_time"][0]
            initial_time = data[ip]["ep_time"][int(
                len(data[ip]["ep_time"]) - 1)]
            delta = abs(int(last_time - initial_time))

            try:
                calc_count_thresh = count / delta
                calc_get_thresh = len(data[ip]["unique_get"]) / delta
            except ZeroDivisionError:
                calc_count_thresh = count
                calc_get_thresh = len(data[ip]["unique_get"])

            if (calc_count_thresh > self._THRESHOLD
                    or calc_get_thresh > self._THRESHOLD
                    or self.payload_match(data[ip]["ua"])):
                if ip not in self.logged_IP:
                    self.logged_IP.append(ip)
                    self.logger.log(
                        "Possible web crawler / spider / bad user agent detected from: "
                        + str(ip),
                        logtype="warning")
                    utils.write_ip(str(ip))
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(ip.strip(" "))
                    # Write malicious IP to file, to teach Firewall about the IP
                    write_mal_ip(ip.strip(" "))

    def payload_match(self, user_agent):
        """
        Match parsed user agent for a
        possible bad user agent payload.

        Args:
            user_agent (str): User agent on which to perform
                              payload string matching

        Raises:
            None

        Returns:
            TYPE: bool
        """
        for agent in user_agent:
            for payload in self.payloads:
                payload = payload.strip(" ").strip("\n")
                if payload in agent:
                    return True
Exemplo n.º 9
0
class PortScan(object):
    """PortScan Class."""
    def __init__(self, debug=False):
        """
        Initialize PortScan.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = logger.SecureTeaLogger(__name__, debug=debug)

        # OS name to auth-log path map
        self.system_log_map = {"debian": "/var/log/auth.log"}

        os_name = utils.categorize_os()
        self.log_file = None

        if os_name:
            try:
                self.log_file = self.system_log_map[os_name]
            except KeyError:
                self.logger.log("Could not find path for the auth-log file",
                                logtype="error")
                return
        else:
            return

        # Salt to generate hashed username
        self.SALT = "<!@?>"

        # Regex to extract Received disconnect
        self.RECIEVED_DISCONNECT = r'^([a-zA-Z]+\s[0-9]+)\s([0-9]+:[0-9]+:[0-9]+).' \
                                   r'*Received\sdisconnect\sfrom\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'

        # Initialize IP to count dict
        self.ip_dict = dict()

        # Set threshold to 5 attempts per second to detect port scan
        self.THRESHOLD = 5  # inter = 0.2

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def parse_log_file(self):
        """
        Parse the log file to extract IP address
        showing quick Recieved Disconnect.

        Args:
            None

        Raises:
            None

        Returns:
            None
        """
        # Open the log file
        log_file_data = utils.open_file(self.log_file)
        for line in log_file_data:
            found = re.findall(self.RECIEVED_DISCONNECT, line)
            if (found is not None and found != []):
                date = found[0][0]
                month = date.split(" ")[0]
                day = date.split(" ")[1]
                last_time = found[0][1]
                ip = found[0][2]

                # convert date, time to epoch time
                epoch_time = utils.get_epoch_time(month, day, last_time)
                self.update_ip_dict(ip, date, epoch_time)

    def update_ip_dict(self, ip, date, epoch_time):
        """
        Update IP address to count dict.

        Args:
            ip (str): IP address of the source
            date (str): Date of action (eg. Jun 1)
            epoch_time (int): Time during the attempt in epoch format

        Raises:
            None

        Returns:
            None
        """
        # Generate a hashed IP using salt
        hashed_ip = ip + self.SALT + date
        if self.ip_dict.get(hashed_ip) is None:
            # if IP not in dict
            self.ip_dict[hashed_ip] = {"count": 1, "last_time": epoch_time}
        else:
            # update IP count & last time
            prev_count = self.ip_dict[hashed_ip]["count"]
            new_count = prev_count + 1
            self.ip_dict[hashed_ip]["count"] = new_count
            self.ip_dict[hashed_ip]["last_time"] = epoch_time

    def detect_port_scan(self):
        """
        Detect port scan by comparing the
        calculated ratio with the set threshold.

        Args:
            None

        Raises:
            None

        Returns:
            None
        """
        for ip in self.ip_dict.keys():
            count = self.ip_dict[ip]["count"]
            last_time = self.ip_dict[ip]["last_time"]
            current_time = time.time()

            try:
                delta_time = int(current_time - last_time)
                calc_threshold = count / delta_time
            except ZeroDivisionError:
                calc_threshold = int(count)

            if calc_threshold > self.THRESHOLD:
                msg = "Possible port scan detected from: " \
                      + ip.split(self.SALT)[0] + " on " \
                      + ip.split(self.SALT)[1]
                self.logger.log(msg, logtype="warning")
                # Generate CSV report using OSINT tools
                self.osint_obj.perform_osint_scan(
                    ip.split(self.SALT)[0].strip(" "))
                # Write malicious IP to file, to teach Firewall about the IP
                write_mal_ip(ip.split(self.SALT)[0].strip(" "))

    def run(self):
        """
        Start monitoring the log file for
        possible port scans.

        Args:
            None

        Raises:
            None

        Returns:
            None
        """
        if self.log_file:  # if path of log file is valid
            # Rotate & parse the log file
            self.parse_log_file()
            # Analyze the log for port scan
            self.detect_port_scan()
            # Empty the dict to rotate the log-file
            self.ip_dict.clear()
Exemplo n.º 10
0
class SQLi(object):
    """SQLi Class."""
    def __init__(self, debug=False):
        """
        Initialize SQLi.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = ServerLogger(__name__, debug=debug)

        # Path of file containing sqli payloads
        self.PAYLOAD_FILE = "securetea/lib/log_monitor/server_log/rules/payloads/sqli.txt"
        # Path of file containing sqli regex rules
        self.REGEX_FILE = "securetea/lib/log_monitor/server_log/rules/regex/sqli.txt"

        # Load sqli payloads
        self.payloads = utils.open_file(self.PAYLOAD_FILE)
        # Load sqli regex rules
        self.regex = utils.open_file(self.REGEX_FILE)

        # Logged IP list
        self.logged_IP = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_sqli(self, data):
        """
        Detect possible SQL Injection (sqli) attacks.
        Use regex rules and string matching to detect
        SQLi attacks.
        4 Level rules:
            - Simple regex
            - Hex regex
            - Payload string matching
            - URI encoded string matching

        Args:
            data (dict): Parsed log file data

        Raises:
            None

        Returns:
            None
        """
        for ip in data.keys():
            get_req = data[ip]["get"]
            last_time = data[ip]["ep_time"][0]
            if (self.payload_match(get_req) or self.regex_check(get_req)):
                if ip not in self.logged_IP:  # if not logged earlier
                    self.logged_IP.append(ip)
                    msg = "Possible SQL injection (sqli) detected from: " + str(ip) + \
                          " on: " + str(utils.epoch_to_date(last_time))
                    self.logger.log(msg, logtype="warning")
                    utils.write_ip(str(ip))
                    # Generate CSV report using OSINT tools
                    self.osint_obj.perform_osint_scan(ip.strip(" "))
                    # Write malicious IP to file, to teach Firewall about the IP
                    write_mal_ip(ip.strip(" "))

    def payload_match(self, get_req):
        """
        Match parsed GET request for a
        possible sqli payload.

        Args:
            get_req (str): GET request on which to perform
                           payload string matching

        Raises:
            None

        Returns:
            TYPE: bool
        """
        for req in get_req:
            for payload in self.payloads:
                payload = payload.strip(" ").strip("\n")
                if (payload in req or utils.uri_encode(payload) in req):
                    return True

    def regex_check(self, get_req):
        """
        Match parsed GET request with
        a sqli regex rules.

        Args:
            get_req (str): GET request on which to perform
                           regex matching

        Raises:
            None

        Returns:
            TYPE: bool
        """
        for req in get_req:
            for reg in self.regex:
                reg = reg.strip(" ").strip("\n")
                if re.findall(reg, req) != []:
                    return True
Exemplo n.º 11
0
class FuzzerDetect(object):
    """FuzzerDetect Class."""
    def __init__(self, debug=False):
        """
        Initialize FuzzerDetect.

        Args:
            debug (bool): Log on terminal or not

        Raises:
            None

        Returns:
            None
        """
        # Initialize logger
        self.logger = ServerLogger(__name__, debug=debug)

        # Set threshold to 25 failure attempts / second
        self._THRESHOLD = 25  # inter = 0.04

        # List of IPs
        self.logged_IP = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    @staticmethod
    def count_failure(status_code):
        """
        Counts the number of failure status code.

        Args:
            status_code (list): List of status codes

        Raises:
            None

        Returns:
            failure_count (int): Count of failure code
        """
        failure_count = 0
        for code in status_code:
            if (400 <= code < 500):  # if failure code
                failure_count = failure_count + 1
        return failure_count

    def detect_fuzzer(self, data):
        """
        Detect possible URL fuzzing attacks.
        High number of failure codes (400-500) range from an IP
        within a small period of time indicates a possible
        fuzzing attack.

        Args:
            data (dict): Parsed log file data

        Raises:
            None

        Returns:
            None
        """
        for ip in data.keys():
            status_code = data[ip]["status_code"]
            # Count failure attempts for that IP
            failure_count = self.count_failure(status_code)
            last_time = data[ip]["ep_time"][0]
            initial_time = data[ip]["ep_time"][int(
                len(data[ip]["ep_time"]) - 1)]
            delta = abs(int(last_time - initial_time))

            try:
                calc_count_thresh = failure_count / delta
                calc_get_thresh = len(data[ip]["get"]) / delta
            except ZeroDivisionError:
                calc_count_thresh = failure_count
                calc_get_thresh = len(data[ip]["get"])

            if (calc_count_thresh > self._THRESHOLD
                    or calc_get_thresh > self._THRESHOLD):
                if ip not in self.logged_IP:
                    self.logged_IP.append(ip)
                    msg = "Possible URL fuzzing detected from: " + str(ip) + \
                          " on: " + utils.epoch_to_date(data[ip]["ep_time"][0])
                    self.logger.log(msg, logtype="warning")
                utils.write_ip(str(ip))
                # Generate CSV report using OSINT tools
                self.osint_obj.perform_osint_scan(ip.strip(" "))
                # Write malicious IP to file, to teach Firewall about the IP
                write_mal_ip(ip.strip(" "))
Exemplo n.º 12
0
class Ssrf (object):


    def __init__(self,test=False,debug=False):
        """
                    Initialize Ssrf

                    Args:
                        debug (bool): Log on terminal or not

                    Raises:
                        None

                    Returns:
                        None
                    """
        # Initialize logger
        self.logger = ServerLogger(
            __name__,
            debug=debug
        )

        if test:
            # Path of file containing SSRF payloads
            self.PAYLOAD_FILE = "securetea/lib/log_monitor/server_log/rules/payloads/ssrf.txt"
            # Path of file containing SSRF regex rules
            self.REGEX_FILE = "securetea/lib/log_monitor/server_log/rules/regex/ssrf.txt"
            # Path of the IP Rules
            self.IP_FILE = "securetea/lib/log_monitor/server_log/rules/payloads/ips.txt"

        else:
            # Path of file containing SSRF payloads
            self.PAYLOAD_FILE = "/etc/securetea/log_monitor/server_log/payloads/ssrf.txt"
            # Path of file containing SSRF regex rules
            self.REGEX_FILE = "/etc/securetea/log_monitor/server_log/regex/ssrf.txt"
            # Path of the IP Rules
            self.IP_FILE = "/etc/securetea/log_monitor/server_log/payloads/ips.txt"



        # Load  SSRF payloads
        self.payloads = utils.open_file(self.PAYLOAD_FILE)
        # Load SSRF regex rules
        self.regex = utils.open_file(self.REGEX_FILE)
        # IPs
        self.ips = utils.open_file(self.IP_FILE)

        # Logged IP list
        self.logged_IP = list()

        # Initialize OSINT object
        self.osint_obj = OSINT(debug=debug)

    def detect_ssrf(self , data):
        """
                    Detects  SSRF
                    Args:
                        data (dict): Parsed Log File

                    Raises:
                        None

                    Returns:
                        None
                    """
        for ip in data.keys():
            get_req = data[ip]["get"]
            last_time = data[ip]["ep_time"][0]
            # extracting all the urls in path
            urls=re.findall(r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+", get_req[0])
            for url in urls:
                resolved_ip=utils.resolver(url)
                if resolved_ip:
                    if (self.rmatch(resolved_ip)):
                        if ip not in self.logged_IP:  # if not logged earlier
                            self.logged_IP.append(ip)
                            msg = "Possible SSRF detected From: " + str(ip) + \
                                  " on: " + str(utils.epoch_to_date(last_time))
                            self.logger.log(
                                msg,
                                logtype="warning"
                            )
                            utils.write_ip(str(ip))
                            # Generate CSV report using OSINT tools
                            self.osint_obj.perform_osint_scan(ip.strip(" "))
                            # Write malicious IP to file, to teach Firewall about the IP
                            write_mal_ip(ip.strip(" "))

                if(self.payload_match(url) or self.regex_match(get_req)):
                        if ip not in self.logged_IP:
                            self.logged_IP.append(ip)
                            msg = "Possible SSRF detected From  " + str(ip) + \
                                  " on: " + str(utils.epoch_to_date(last_time))
                            self.logger.log(msg,logtype="warning")
                            utils.write_ip(str(ip))
                            # Generate CSV report using OSINT tools
                            self.osint_obj.perform_osint_scan(ip.strip(" "))
                            # Write malicious IP to file, to teach Firewall about the IP
                            write_mal_ip(ip.strip(" "))


    def payload_match(self,url):
        """
               Match parsed URL from a GET Request to
               possible SSRF payload.

               Args:
                   url (str): url on which to perform
                                  payload string matching

               Raises:
                   None

               Returns:
                   TYPE: bool
               """
        for payloads in self.payloads:
            payload=payloads.strip(" ").strip("\n")
            if (payload in url
                    or utils.uri_encode(payload) in url):
                return True


    def regex_match(self,req):
        """
               Match parsed GET request for a
               possible SSRF regex

               Args:
                   get_req (str): GET request on which to perform
                                  regex string matching

               Raises:
                   None

               Returns:
                   TYPE: bool
               """
        for req in get_req:
            for reg in self.regex:
                reg = reg.strip(" ").strip("\n")
                if re.findall(reg, req) != []:
                    return True


    def rmatch(self,ip):
        """
               Match resolved  IP  for a
               possible SSRF  in IP List.

               Args:
                   ip (str): IP  on which to perform
                                  payload string matching

               Raises:
                   None

               Returns:
                   TYPE: bool
               """
        for payload_ip in self.ips:
            payload_ip=payload_ip.strip(" ").strip("\n")
            if payload_ip in ip:
                return True