def allow_ssh_temporarily(_config: SectionProxy) -> None: """ Allows ssh temporarily :param _config: the config to use """ number_of_required_chains = len(_config.getlist("ports")) for i in range(1, number_of_required_chains): self.execute("-N SSH-KNOCKING-{}".format(i)) command = "-A INPUT -m state --state NEW -m tcp -p tcp" if _config.get("interface", None): command += " -i " + _config.get("interface") command += " --dport " + _config.get("ssh_port", "22") command += " -m recent --rcheck --seconds " + _config.get("timeout", 30) command += " --name SSH{}".format(len(_config.getlist("ports")) - 1) command += \ ' -m comment --comment "Allow port {} for ssh for {} if the connecting ip is in the list SSH{}"'.format( _config.get("ssh_port", "22"), _config.get("timeout", 30), len(_config.getlist("ports")) - 1 ) self.execute(command)
def allow_ssh_temporarily(_config: SectionProxy) -> None: """ Allows ssh temporarily :param _config: the config to use """ number_of_required_chains = len(_config.getlist("ports")) for i in range(1, number_of_required_chains): self.execute("-N SSH-KNOCKING-{}".format(i)) command = "-A INPUT -m state --state NEW -m tcp -p tcp" if _config.get("interface", None): command += " -i " + _config.get("interface") command += " --dport " + _config.get("ssh_port", "22") command += " -m recent --rcheck --seconds " + _config.get( "timeout", 30) command += " --name SSH{}".format( len(_config.getlist("ports")) - 1) command += \ ' -m comment --comment "Allow port {} for ssh for {} if the connecting ip is in the list SSH{}"'.format( _config.get("ssh_port", "22"), _config.get("timeout", 30), len(_config.getlist("ports")) - 1 ) self.execute(command)
def handle_service(config: SectionProxy) -> None: """ Sets a rule or a service :param config: the configuration for the rule """ for src in config.getlist("source", [None]): for dst in config.getlist("destination", [None]): source = None destination = None if src is not None: source = get_ip_address(src) if source is None: print( "[ERROR] Could not determine ip address for {} : skipping" .format(src)) continue if dst is not None: destination = get_ip_address(dst) if destination is None: print( "[ERROR] Could not determine ip address for {} : skipping" .format(dst)) continue rule = IptablesRule(name=config.name, interface=config.get("interface"), chain=config.get("chain"), protocol=config.get("protocol"), action=config.get("action"), source=source, destination=destination, sport=config.get("sport"), dport=config.get("dport"), remote=config.get("remote", None)) if config.getboolean("ipv4", False) and (rule.source is None or rule.source.version == 4) and \ (rule.destination is None or rule.source.version == 4): ipv4_handler.add_rule(rule) if config.getboolean("ipv6") and (rule.source is None or rule.source.version == 6) and \ (rule.destination is None or rule.source.version == 6): ipv6_handler.add_rule(rule) if (rule.source is not None and rule.destination is not None) and \ rule.destination.version != rule.source.version: print( "[ERROR] Could not add rule with ip versions no matching: {} and {}" .format(str(rule.source, rule.destination)))
def setup(handler: Iptables, _config: SectionProxy) -> None: """ Sets up the tables to accept new rules : resets all rules, set defaults and allow global traffic :param handler: the Iptables instance on which to operate :param _config: the configuration used """ handler.reset() for chain in _config.getlist("closed_chains", []): handler.set_default(chain, "DROP") if _config.getboolean("allow_established_traffic", False): handler.allow_existing_traffic() for interface in _config.getlist("allow_traffic_on_interface", []): handler.allow_traffic_on_interface(interface) if _config.getboolean("drop_invalid_traffic", False): handler.drop_invalid_traffic()
def enable_ssh_knocking(self, config: SectionProxy) -> None: """ enables iptables-only ssh knocking :param config: the configuration to use for the knocking """ def allow_ssh_temporarily(_config: SectionProxy) -> None: """ Allows ssh temporarily :param _config: the config to use """ number_of_required_chains = len(_config.getlist("ports")) for i in range(1, number_of_required_chains): self.execute("-N SSH-KNOCKING-{}".format(i)) command = "-A INPUT -m state --state NEW -m tcp -p tcp" if _config.get("interface", None): command += " -i " + _config.get("interface") command += " --dport " + _config.get("ssh_port", "22") command += " -m recent --rcheck --seconds " + _config.get("timeout", 30) command += " --name SSH{}".format(len(_config.getlist("ports")) - 1) command += \ ' -m comment --comment "Allow port {} for ssh for {} if the connecting ip is in the list SSH{}"'.format( _config.get("ssh_port", "22"), _config.get("timeout", 30), len(_config.getlist("ports")) - 1 ) self.execute(command) def remove_from_list(entry_number: int) -> None: """ Removes the ip from the list given by the number :param entry_number: the number for which to remove the list """ command = "-A INPUT -m state --state NEW -m tcp -p tcp -m recent --name SSH{} --remove".format(entry_number) command += ' -j DROP -m comment --comment "Remove connecting ip from the SSH{} list"'.format(entry_number) self.execute(command) def enable_jump(_port: int, entry_number: int) -> None: """ Enables jumping to the given chain :param _port: the port on which to enable the jump :param entry_number: the number of the entry to which to jump """ command = "-A INPUT -m state --state NEW -m tcp -p tcp --dport {} -m recent --rcheck --name SSH{}".format( _port, entry_number - 1 ) command += ' -j SSH-KNOCKING-{} -m comment --comment "Checks for the sequence and jumps if correct"'.format( entry_number ) self.execute(command) def initiate_knocking(_port: int) -> None: """ Sequence initiation for the port knocking :param _port: the port on which to knock """ command = "-A INPUT -m state --state NEW -m tcp -p tcp --dport {} -m recent --name SSH0 --set".format(_port) command += ' -j DROP -m comment --comment "Sequence initiation for port knocking"' self.execute(command) def hide_port(number: int) -> None: """ Hides the port given by the number by dropping it :param number: the number of the chain on which to drop """ command = "-A INPUT -m recent --name SSH{} --set -j DROP -m comment".format(number) command += '--comment "Disguise successful knock as a closed port for obfuscation"' self.execute(command) # noinspection PyTypeChecker allow_ssh_temporarily(config) # noinspection PyUnresolvedReferences ports = config.getlist("ports") for port in reversed(ports): remove_from_list(ports.index(port)) if ports.index(port) != 0: enable_jump(port, ports.index(port)) else: initiate_knocking(port) for entry in range(len(ports) - 1): hide_port(entry)
def enable_ssh_knocking(self, config: SectionProxy) -> None: """ enables iptables-only ssh knocking :param config: the configuration to use for the knocking """ def allow_ssh_temporarily(_config: SectionProxy) -> None: """ Allows ssh temporarily :param _config: the config to use """ number_of_required_chains = len(_config.getlist("ports")) for i in range(1, number_of_required_chains): self.execute("-N SSH-KNOCKING-{}".format(i)) command = "-A INPUT -m state --state NEW -m tcp -p tcp" if _config.get("interface", None): command += " -i " + _config.get("interface") command += " --dport " + _config.get("ssh_port", "22") command += " -m recent --rcheck --seconds " + _config.get( "timeout", 30) command += " --name SSH{}".format( len(_config.getlist("ports")) - 1) command += \ ' -m comment --comment "Allow port {} for ssh for {} if the connecting ip is in the list SSH{}"'.format( _config.get("ssh_port", "22"), _config.get("timeout", 30), len(_config.getlist("ports")) - 1 ) self.execute(command) def remove_from_list(entry_number: int) -> None: """ Removes the ip from the list given by the number :param entry_number: the number for which to remove the list """ command = "-A INPUT -m state --state NEW -m tcp -p tcp -m recent --name SSH{} --remove".format( entry_number) command += ' -j DROP -m comment --comment "Remove connecting ip from the SSH{} list"'.format( entry_number) self.execute(command) def enable_jump(_port: int, entry_number: int) -> None: """ Enables jumping to the given chain :param _port: the port on which to enable the jump :param entry_number: the number of the entry to which to jump """ command = "-A INPUT -m state --state NEW -m tcp -p tcp --dport {} -m recent --rcheck --name SSH{}".format( _port, entry_number - 1) command += ' -j SSH-KNOCKING-{} -m comment --comment "Checks for the sequence and jumps if correct"'.format( entry_number) self.execute(command) def initiate_knocking(_port: int) -> None: """ Sequence initiation for the port knocking :param _port: the port on which to knock """ command = "-A INPUT -m state --state NEW -m tcp -p tcp --dport {} -m recent --name SSH0 --set".format( _port) command += ' -j DROP -m comment --comment "Sequence initiation for port knocking"' self.execute(command) def hide_port(number: int) -> None: """ Hides the port given by the number by dropping it :param number: the number of the chain on which to drop """ command = "-A INPUT -m recent --name SSH{} --set -j DROP -m comment".format( number) command += '--comment "Disguise successful knock as a closed port for obfuscation"' self.execute(command) # noinspection PyTypeChecker allow_ssh_temporarily(config) # noinspection PyUnresolvedReferences ports = config.getlist("ports") for port in reversed(ports): remove_from_list(ports.index(port)) if ports.index(port) != 0: enable_jump(port, ports.index(port)) else: initiate_knocking(port) for entry in range(len(ports) - 1): hide_port(entry)