From fd3c748a8f5842a56593b3ac0bc86d94ea01e9a0 Mon Sep 17 00:00:00 2001 From: thinkst-az <156116192+thinkst-az@users.noreply.github.com> Date: Fri, 18 Oct 2024 07:23:13 +0200 Subject: [PATCH] Simplify search for iptables executable (#382) * fix safe exec * fix black format * iptables simplify * iptables search * Remove unused import --- bin/opencanary.tac | 4 +--- docs/starting/configuration.rst | 1 - opencanary/__init__.py | 31 +------------------------------ opencanary/config.py | 10 ---------- opencanary/modules/portscan.py | 33 +++++++++++++++++---------------- 5 files changed, 19 insertions(+), 60 deletions(-) diff --git a/bin/opencanary.tac b/bin/opencanary.tac index 44f933d..bc5523f 100644 --- a/bin/opencanary.tac +++ b/bin/opencanary.tac @@ -4,7 +4,7 @@ import sys from twisted.application import service from pkg_resources import iter_entry_points -from opencanary.config import config, is_docker, detectIPTables +from opencanary.config import config, is_docker from opencanary.logger import getLogger from opencanary.modules.http import CanaryHTTP from opencanary.modules.https import CanaryHTTPS @@ -84,8 +84,6 @@ if sys.platform.startswith("linux"): if config.moduleEnabled("portscan") and is_docker(): # Remove portscan if running in DOCKER (specified in Dockerfile) print("Can't use portscan in Docker. Portscan module disabled.") - elif config.moduleEnabled("portscan") and not detectIPTables(): - print("Can't use portscan without iptables. Please install iptables.") else: from opencanary.modules.portscan import CanaryPortscan diff --git a/docs/starting/configuration.rst b/docs/starting/configuration.rst index 69d5e83..56aabce 100644 --- a/docs/starting/configuration.rst +++ b/docs/starting/configuration.rst @@ -41,7 +41,6 @@ For this configuration, you will need to set up your own Windows File Share. Ple `portscan` - a log watcher that works with iptables to monitor when your Opencanary is being scanned. At this stage, the portscan module supports the detection of Nmap OS, Nmap FIN, Nmap OS, Nmap NULL, and normal port scans. -`portscan.iptables_path` is available for you to specify the path to your `iptables` binary. Logger Configuration -------------------- diff --git a/opencanary/__init__.py b/opencanary/__init__.py index 8489f17..8e6093e 100644 --- a/opencanary/__init__.py +++ b/opencanary/__init__.py @@ -1,34 +1,5 @@ import os -import subprocess __version__ = "0.9.5" -from os import PathLike -from typing import Union - -BIN_LOCATIONS = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"] - - -def _check_file_exists_and_executable(path: Union[PathLike, str]) -> bool: - if not os.path.isfile(path): - return False - else: - return os.access(path, os.X_OK) - - -def safe_exec(binary_name: str, args: list) -> bytes: - """ - Executes the given binary with the given arguments as a subprocess. What makes this safe is that the binary name - is not executed as an alias, and only binaries that live in trusted system locations are executed. This means that - only system-wide binaries are executable. - """ - exec_path = None - for prefix in BIN_LOCATIONS: - bin_path = os.path.join(prefix, binary_name) - if _check_file_exists_and_executable(os.path.join(prefix, binary_name)): - exec_path = bin_path - break - if exec_path is None: - raise Exception(f"Could not find executable ${binary_name}") - else: - return subprocess.check_output(args, shell=True, executable=exec_path) +STDPATH = os.pathsep.join(["/usr/bin", "/bin", "/usr/sbin", "/sbin"]) diff --git a/opencanary/config.py b/opencanary/config.py index 5a621f2..a7440dd 100644 --- a/opencanary/config.py +++ b/opencanary/config.py @@ -3,12 +3,10 @@ import json import itertools import string -import shutil import re from os.path import expanduser from pkg_resources import resource_filename from pathlib import Path -from . import safe_exec SAMPLE_SETTINGS = resource_filename(__name__, "data/settings.json") SETTINGS = "opencanary.conf" @@ -36,13 +34,6 @@ def is_docker(): ) -def detectIPTables(): - if shutil.which("iptables"): - return True - else: - return False - - SERVICE_REGEXES = { "ssh.version": r"(SSH-(2.0|1.5|1.99|1.0)-([!-,\-./0-~]+(:?$|\s))(?:[ -~]*)){1,253}$", } @@ -77,7 +68,6 @@ def __init__(self, configfile=SETTINGS): print("[-] Failed to open %s for reading (%s)" % (fname, e)) except ValueError as e: print("[-] Failed to decode json from %s (%s)" % (fname, e)) - safe_exec("cp", ["-r", fname, "/var/tmp/config-err-$(date +%%s)"]) except Exception as e: print("[-] An error occurred loading %s (%s)" % (fname, e)) if self.__config is None: diff --git a/opencanary/modules/portscan.py b/opencanary/modules/portscan.py index cb6cb71..145ecda 100644 --- a/opencanary/modules/portscan.py +++ b/opencanary/modules/portscan.py @@ -1,7 +1,8 @@ from opencanary.modules import CanaryService from opencanary.modules import FileSystemWatcher -from opencanary import safe_exec +from opencanary import STDPATH import os +import subprocess import shutil @@ -67,10 +68,6 @@ def handleLines(self, lines=None): # noqa: C901 self.logger.log(data) -def detectNFTables(): - return b"nf_tables" in safe_exec("iptables", ["--version"]) - - class CanaryPortscan(CanaryService): NAME = "portscan" @@ -85,18 +82,8 @@ def __init__(self, config=None, logger=None): "portscan.ignore_localhost", default=False ) self.ignore_ports = config.getVal("portscan.ignore_ports", default=[]) - self.iptables_path = self.config.getVal("portscan.iptables_path", False) self.config = config - def getIptablesPath(self): - if self.iptables_path: - return self.iptables_path - - if detectNFTables(): - return shutil.which("iptables-legacy") - - return shutil.which("iptables") or "/sbin/iptables" - def startYourEngines(self, reactor=None): # Logging rules for loopback interface. # This is separate from the canaryfw rule as the canary watchdog was @@ -117,7 +104,21 @@ def configUpdated( pass def set_iptables_rules(self): - iptables_path = self.getIptablesPath() + iptables_path = shutil.which("iptables-legacy", path=STDPATH) + + if not iptables_path: + iptables_path = shutil.which("iptables", path=STDPATH) + + if not iptables_path: + err = "Portscan module failed to start as iptables cannot be found. Please install iptables." + print(err) + raise Exception(err) + + if b"nf_tables" in subprocess.check_output([iptables_path, "--version"]): + err = "Portscan module failed to start as iptables-legacy cannot be found. Please install iptables-legacy" + print(err) + raise Exception(err) + os.system( 'sudo {0} -t mangle -D PREROUTING -p tcp -i lo -j LOG --log-level=warning --log-prefix="canaryfw: " -m limit --limit="{1}/hour"'.format( iptables_path, self.lorate