Skip to content

Commit

Permalink
Simplify search for iptables executable (#382)
Browse files Browse the repository at this point in the history
* fix safe exec

* fix black format

* iptables simplify

* iptables search

* Remove unused import
  • Loading branch information
thinkst-az authored Oct 18, 2024
1 parent 2509734 commit fd3c748
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 60 deletions.
4 changes: 1 addition & 3 deletions bin/opencanary.tac
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion docs/starting/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------------------
Expand Down
31 changes: 1 addition & 30 deletions opencanary/__init__.py
Original file line number Diff line number Diff line change
@@ -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"])
10 changes: 0 additions & 10 deletions opencanary/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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}$",
}
Expand Down Expand Up @@ -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:
Expand Down
33 changes: 17 additions & 16 deletions opencanary/modules/portscan.py
Original file line number Diff line number Diff line change
@@ -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


Expand Down Expand Up @@ -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"

Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit fd3c748

Please sign in to comment.