Skip to content

Commit

Permalink
Prevent Local Privilege Escalation via Config & Untrusted Aliases
Browse files Browse the repository at this point in the history
* Mitigated local config exploitability
* Re-ordered precedence to sys locations
* Added warning if local location is used
* Mitigated untrusted alias execution
  • Loading branch information
DavidBakerEffendi authored and thinkst-az committed Oct 14, 2024
1 parent d3956bc commit 2c11575
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
33 changes: 33 additions & 0 deletions opencanary/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
import os
import subprocess

__version__ = "0.9.3"

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)):

This comment was marked as outdated.

Copy link
@prabhu

prabhu Oct 24, 2024

Consider handling relative paths in binary_name.

Eg: ../../../tmp/foo

This comment has been minimized.

Copy link
@thinkst-az

thinkst-az Oct 30, 2024

Contributor

Thanks for looking over @prabhu. This is older code that has since been removed. If you'd like to suggests changes to code - please review latest code on master and submit PRs.

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)

This comment was marked as outdated.

Copy link
@prabhu

prabhu Oct 24, 2024

shell=True is unnecessary here.

This comment has been minimized.

Copy link
@thinkst-az

thinkst-az Oct 29, 2024

Contributor

Thanks for the check @prabhu . This is an old version of the code you're looking at - it has been removed already.

15 changes: 9 additions & 6 deletions opencanary/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import json
import itertools
import string
import subprocess
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 @@ -54,9 +54,9 @@ def __init__(self, configfile=SETTINGS):
self.__configfile = configfile

files = [
configfile,
"%s/.%s" % (expanduser("~"), configfile),
"/etc/opencanaryd/%s" % configfile,
"%s/.%s" % (expanduser("~"), configfile),
configfile,
]
print(
"** We hope you enjoy using OpenCanary. For more open source Canary goodness, head over to canarytokens.org. **"
Expand All @@ -67,14 +67,17 @@ def __init__(self, configfile=SETTINGS):
print("[-] Using config file: %s" % fname)
self.__config = json.load(f)
self.__config = expand_vars(self.__config)
if fname is configfile:
print(
"[-] Warning, making use of the configuration file in the immediate directory is not recommended! Suggested locations: %s"
% ", ".join(files[:2])
)
return
except IOError as e:
print("[-] Failed to open %s for reading (%s)" % (fname, e))
except ValueError as e:
print("[-] Failed to decode json from %s (%s)" % (fname, e))
subprocess.call(
"cp -r %s /var/tmp/config-err-$(date +%%s)" % fname, shell=True
)
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
4 changes: 2 additions & 2 deletions opencanary/modules/portscan.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from opencanary.modules import CanaryService
from opencanary.modules import FileSystemWatcher
from opencanary import safe_exec
import os
import shutil
import subprocess


class SynLogWatcher(FileSystemWatcher):
Expand Down Expand Up @@ -68,7 +68,7 @@ def handleLines(self, lines=None): # noqa: C901


def detectNFTables():
return b"nf_tables" in subprocess.check_output(["iptables", "--version"])
return b"nf_tables" in safe_exec("iptables", ["--version"])


class CanaryPortscan(CanaryService):
Expand Down

0 comments on commit 2c11575

Please sign in to comment.