From 46b5e5e5948fecca8de532c56c794638fd87fb69 Mon Sep 17 00:00:00 2001 From: mivirl <> Date: Wed, 22 May 2024 11:31:01 -0500 Subject: [PATCH] Initial commit --- README.md | 61 ++ configs/aide.conf | 317 +++++++++ configs/audit.rules | 810 +++++++++++++++++++++++ hide-hardware.sh | 129 ++++ linux.sh | 1123 ++++++++++++++++++++++++++++++++ profiles/apache2-override.conf | 108 +++ profiles/generic-override.conf | 93 +++ profiles/httpd-override.conf | 93 +++ profiles/nginx-override.conf | 105 +++ sandbox.sh | 76 +++ 10 files changed, 2915 insertions(+) create mode 100644 README.md create mode 100644 configs/aide.conf create mode 100644 configs/audit.rules create mode 100755 hide-hardware.sh create mode 100755 linux.sh create mode 100644 profiles/apache2-override.conf create mode 100644 profiles/generic-override.conf create mode 100644 profiles/httpd-override.conf create mode 100644 profiles/nginx-override.conf create mode 100755 sandbox.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae3b7c0 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Blue team hardening scripts + +Hardening scripts for blue team competitions. + +Requires some environment variables to be set to operate correctly. Make sure +to read the script before running it! + +This script will produce excessive noise in the logs, so this is not +recommended for real-world use without changes. + +Depends on the firewall script from + +Actions taken: +- Drop all traffic except dns (optionally also ssh, ldap) +- Require encryption and/or signatures for repositories +- Create minimal `/etc/hosts` + - Add github + - Add repositories (and several mirrors for fedora-based) +- Allow outgoing traffic to github and repositories +- Configure sudo to log output and only allow admin users +- Enable `haveged` for entropy +- Configure password policies +- Check for nonexistent groups +- Check for duplicate UIDs, GIDs, user names, and group names +- Create a logging group for accessing `/var/log` +- Reset all user passwords to random passwords +- Reset admin and root passwords +- Disable root logins +- Set permissions for users' home directories +- Set permissions for root directories +- Set default umask +- Configure ssh + - Regenerate host keys + - Use strong cryptography + - Set login banners +- Update packages for services listening on ports first +- Install `rsyslog` and forward `journald` to it +- Install `auditd` and set rules +- Allow incoming traffic to listening services +- Update all packages +- Set up kernel and userspace protections using sysctl +- Disable uncommon kernel modules +- Hide hardware info +- Disable unneeded inetd services +- Disable common unneeded services +- Configure apache + - Set permissions for configuration directories + - Disable trace requests + - List directories that might be writable + - List all .ht files that may change configs + - Install mod-security + - Sandbox apache using systemd service sandboxing +- Configure nginx + - Set permissions for configuration directories + - Install mod-security if the package exists for nginx + - Sandbox apache using systemd service sandboxing +- Configure usbguard +- Configure aide +- Verify that packages aren't corrupted/modified +- List world-writable files and directories +- List suid and sgid binaries, highlight risky ones diff --git a/configs/aide.conf b/configs/aide.conf new file mode 100644 index 0000000..b934dc3 --- /dev/null +++ b/configs/aide.conf @@ -0,0 +1,317 @@ +# Example configuration file for AIDE. + +@@define DBDIR /var/lib/aide +@@define LOGDIR /var/log/aide + +# The location of the database to be read. +database=file:@@{DBDIR}/aide.db.gz + +# The location of the database to be written. +#database_out=sql:host:port:database:login_name:passwd:table +#database_out=file:aide.db.new +database_out=file:@@{DBDIR}/aide.db.new.gz + +# Whether to gzip the output to database +gzip_dbout=yes + +# Default. +verbose=5 + +report_url=file:@@{LOGDIR}/aide.log +report_url=stdout +#report_url=stderr +#NOT IMPLEMENTED report_url=mailto:root@foo.com +#NOT IMPLEMENTED report_url=syslog:LOG_AUTH + +# These are the default rules. +# +#p: permissions +#i: inode: +#n: number of links +#u: user +#g: group +#s: size +#b: block count +#m: mtime +#a: atime +#c: ctime +#S: check for growing size +#acl: Access Control Lists +#selinux SELinux security context +#xattrs: Extended file attributes +#md5: md5 checksum +#sha1: sha1 checksum +#sha256: sha256 checksum +#sha512: sha512 checksum +#rmd160: rmd160 checksum +#tiger: tiger checksum + +#haval: haval checksum (MHASH only) +#gost: gost checksum (MHASH only) +#crc32: crc32 checksum (MHASH only) +#whirlpool: whirlpool checksum (MHASH only) + +#R: p+i+n+u+g+s+m+c+acl+selinux+xattrs+md5 +#L: p+i+n+u+g+acl+selinux+xattrs +#E: Empty group +#>: Growing logfile p+u+g+i+n+S+acl+selinux+xattrs + +# You can create custom rules like this. +# With MHASH... +# ALLXTRAHASHES = sha1+rmd160+sha256+sha512+whirlpool+tiger+haval+gost+crc32 +ALLXTRAHASHES = sha1+rmd160+sha256+sha512+tiger +# Everything but access time (Ie. all changes) +EVERYTHING = R+ALLXTRAHASHES + +# Sane +# NORMAL = R+sha512 +NORMAL = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512 + +# For directories, don't bother doing hashes +DIR = p+i+n+u+g+acl+selinux+xattrs + +# Access control only +PERMS = p+u+g+acl+selinux+xattrs + +# Logfile are special, in that they often change +LOG = p+u+g+n+S+acl+selinux+xattrs + +# Content + file type. +CONTENT = sha512+ftype + +# Extended content + file type + access. +CONTENT_EX = sha512+ftype+p+u+g+n+acl+selinux+xattrs + +# Some files get updated automatically, so the inode/ctime/mtime change +# but we want to know when the data inside them changes +DATAONLY = p+n+u+g+s+acl+selinux+xattrs+sha512 + +# Next decide what directories/files you want in the database. + +/boot CONTENT_EX +/opt CONTENT + +# Admins dot files constantly change, just check perms +/root/\..* PERMS +# Otherwise get all of /root. +/root CONTENT_EX + +# These are too volatile +!/usr/src +!/usr/tmp + +# Otherwise get all of /usr. +/usr CONTENT_EX + +# trusted databases +/etc/hosts$ CONTENT_EX +/etc/host.conf$ CONTENT_EX +/etc/hostname$ CONTENT_EX +/etc/issue$ CONTENT_EX +/etc/issue.net$ CONTENT_EX +/etc/protocols$ CONTENT_EX +/etc/services$ CONTENT_EX +/etc/localtime$ CONTENT_EX +/etc/alternatives CONTENT_EX +/etc/sysconfig CONTENT_EX +/etc/mime.types$ CONTENT_EX +/etc/terminfo CONTENT_EX +/etc/exports$ CONTENT_EX +/etc/fstab$ CONTENT_EX +/etc/passwd$ CONTENT_EX +/etc/group$ CONTENT_EX +/etc/gshadow$ CONTENT_EX +/etc/shadow$ CONTENT_EX +/etc/subgid$ CONTENT_EX +/etc/subuid$ CONTENT_EX +/etc/security/opasswd$ CONTENT_EX +/etc/skel CONTENT_EX +/etc/subuid$ CONTENT_EX +/etc/subgid$ CONTENT_EX +/etc/sssd CONTENT_EX +/etc/machine-id$ CONTENT_EX +/etc/swid CONTENT_EX +/etc/system-release-cpe$ CONTENT_EX +/etc/shells$ CONTENT_EX +/etc/tmux.conf$ CONTENT_EX +/etc/xattr.conf$ CONTENT_EX + + +# networking +/etc/hosts.allow$ CONTENT_EX +/etc/hosts.deny$ CONTENT_EX +/etc/firewalld CONTENT_EX +!/etc/NetworkManager/system-connections +/etc/NetworkManager CONTENT_EX +/etc/networks$ CONTENT_EX +/etc/dhcp CONTENT_EX +/etc/wpa_supplicant CONTENT_EX +/etc/resolv.conf$ DATAONLY +/etc/nscd.conf$ CONTENT_EX + +# logins and accounts +/etc/login.defs$ CONTENT_EX +/etc/libuser.conf$ CONTENT_EX +/var/log/faillog$ PERMS +/var/log/lastlog$ PERMS +/var/run/faillock PERMS +/etc/pam.d CONTENT_EX +/etc/security CONTENT_EX +/etc/securetty$ CONTENT_EX +/etc/polkit-1 CONTENT_EX +/etc/sudo.conf$ CONTENT_EX +/etc/sudoers$ CONTENT_EX +/etc/sudoers.d CONTENT_EX + +# Shell/X startup files +/etc/profile$ CONTENT_EX +/etc/profile.d CONTENT_EX +/etc/bashrc$ CONTENT_EX +/etc/bash_completion.d CONTENT_EX +/etc/zprofile$ CONTENT_EX +/etc/zshrc$ CONTENT_EX +/etc/zlogin$ CONTENT_EX +/etc/zlogout$ CONTENT_EX +/etc/X11 CONTENT_EX + +# Pkg manager +/etc/dnf CONTENT_EX +/etc/yum.conf$ CONTENT_EX +/etc/yum CONTENT_EX +/etc/yum.repos.d CONTENT_EX + +# This gets new/removes-old filenames daily +!/var/log/sa +# As we are checking it, we've truncated yesterdays size to zero. +!/var/log/aide.log + +# auditing +# AIDE produces an audit record, so this becomes perpetual motion. +/var/log/audit PERMS +/etc/audit CONTENT_EX +/etc/libaudit.conf$ CONTENT_EX +/etc/aide.conf$ CONTENT_EX + +# System logs +/etc/rsyslog.conf$ CONTENT_EX +/etc/rsyslog.d CONTENT_EX +/etc/logrotate.conf$ CONTENT_EX +/etc/logrotate.d CONTENT_EX +/etc/systemd/journald.conf$ CONTENT_EX +/var/log LOG+ANF+ARF +/var/run/utmp LOG + +# secrets +/etc/pkcs11 CONTENT_EX +/etc/pki CONTENT_EX +/etc/crypto-policies CONTENT_EX +/etc/certmonger CONTENT_EX +/var/lib/systemd/random-seed$ PERMS + +# init system +/etc/systemd CONTENT_EX +/etc/rc.d CONTENT_EX +/etc/tmpfiles.d CONTENT_EX + +# boot config +/etc/default CONTENT_EX +/etc/grub.d CONTENT_EX +/etc/dracut.conf$ CONTENT_EX +/etc/dracut.conf.d CONTENT_EX + +# glibc linker +/etc/ld.so.cache$ CONTENT_EX +/etc/ld.so.conf$ CONTENT_EX +/etc/ld.so.conf.d CONTENT_EX +/etc/ld.so.preload$ CONTENT_EX + +# kernel config +/etc/sysctl.conf$ CONTENT_EX +/etc/sysctl.d CONTENT_EX +/etc/modprobe.d CONTENT_EX +/etc/modules-load.d CONTENT_EX +/etc/depmod.d CONTENT_EX +/etc/udev CONTENT_EX +/etc/crypttab$ CONTENT_EX + +#### Daemons #### + +# cron jobs +/var/spool/at CONTENT +/etc/at.allow$ CONTENT +/etc/at.deny$ CONTENT +/var/spool/anacron CONTENT +/etc/anacrontab$ CONTENT_EX +/etc/cron.allow$ CONTENT_EX +/etc/cron.deny$ CONTENT_EX +/etc/cron.d CONTENT_EX +/etc/cron.daily CONTENT_EX +/etc/cron.hourly CONTENT_EX +/etc/cron.monthly CONTENT_EX +/etc/cron.weekly CONTENT_EX +/etc/crontab$ CONTENT_EX +/var/spool/cron/root CONTENT + +# time keeping +/etc/chrony.conf$ CONTENT_EX +/etc/chrony.keys$ CONTENT_EX + +# mail +/etc/aliases$ CONTENT_EX +/etc/aliases.db$ CONTENT_EX +/etc/postfix CONTENT_EX + +# ssh +/etc/ssh/sshd_config$ CONTENT_EX +/etc/ssh/ssh_config$ CONTENT_EX + +# stunnel +/etc/stunnel CONTENT_EX + +# printing +/etc/cups CONTENT_EX +/etc/cupshelpers CONTENT_EX +/etc/avahi CONTENT_EX + +# web server +/etc/httpd CONTENT_EX + +# dns +/etc/named CONTENT_EX +/etc/named.conf$ CONTENT_EX +/etc/named.iscdlv.key$ CONTENT_EX +/etc/named.rfc1912.zones$ CONTENT_EX +/etc/named.root.key$ CONTENT_EX + +# xinetd +/etc/xinetd.conf$ CONTENT_EX +/etc/xinetd.d CONTENT_EX + +# IPsec +/etc/ipsec.conf$ CONTENT_EX +/etc/ipsec.secrets$ CONTENT_EX +/etc/ipsec.d CONTENT_EX + +# USB guard +/etc/usbguard CONTENT_EX + +# Ignore some files +!/etc/mtab$ +!/etc/.*~ + +# Now everything else +/etc PERMS + + +# With AIDE's default verbosity level of 5, these would give lots of +# warnings upon tree traversal. It might change with future version. +# +#=/lost\+found DIR +#=/home DIR + +# Ditto /var/log/sa reason... +!/var/log/and-httpd + +# Admins dot files constantly change, just check perms +/root/\..* PERMS +!/root/.xauth* diff --git a/configs/audit.rules b/configs/audit.rules new file mode 100644 index 0000000..363caf4 --- /dev/null +++ b/configs/audit.rules @@ -0,0 +1,810 @@ +# ___ ___ __ __ +# / | __ ______/ (_) /_____/ / +# / /| |/ / / / __ / / __/ __ / +# / ___ / /_/ / /_/ / / /_/ /_/ / +# /_/ |_\__,_/\__,_/_/\__/\__,_/ +# +# Linux Audit Daemon - Best Practice Configuration +# /etc/audit/audit.rules +# +# Compiled by Florian Roth +# +# Created : 2017/12/05 +# Modified : 2023/01/25 +# +# Based on rules published here: +# Gov.uk auditd rules +# https://github.com/gds-operations/puppet-auditd/pull/1 +# CentOS 7 hardening +# https://highon.coffee/blog/security-harden-centos-7/#auditd---audit-daemon +# Linux audit repo +# https://github.com/linux-audit/audit-userspace/tree/master/rules +# Auditd high performance linux auditing +# https://linux-audit.com/tuning-auditd-high-performance-linux-auditing/ +# +# Further rules +# For PCI DSS compliance see: +# https://github.com/linux-audit/audit-userspace/blob/master/rules/30-pci-dss-v31.rules +# For NISPOM compliance see: +# https://github.com/linux-audit/audit-userspace/blob/master/rules/30-nispom.rules + +# Remove any existing rules +-D + +# Buffer Size +## Feel free to increase this if the machine panic's +-b 8192 + +# Failure Mode +## Possible values: 0 (silent), 1 (printk, print a failure message), 2 (panic, halt the system) +-f 1 + +# Ignore errors +## e.g. caused by users or files not found in the local environment +-i + +# Self Auditing --------------------------------------------------------------- + +## Audit the audit logs +### Successful and unsuccessful attempts to read information from the audit records +-w /var/log/audit/ -p wra -k auditlog +-w /var/audit/ -p wra -k auditlog + +## Auditd configuration +### Modifications to audit configuration that occur while the audit collection functions are operating +-w /etc/audit/ -p wa -k auditconfig +-w /etc/libaudit.conf -p wa -k auditconfig +-w /etc/audisp/ -p wa -k audispconfig + +## Monitor for use of audit management tools +-w /sbin/auditctl -p x -k audittools +-w /sbin/auditd -p x -k audittools +-w /usr/sbin/auditd -p x -k audittools +-w /usr/sbin/augenrules -p x -k audittools + +## Access to all audit trails + +-a always,exit -F path=/usr/sbin/ausearch -F perm=x -k audittools +-a always,exit -F path=/usr/sbin/aureport -F perm=x -k audittools +-a always,exit -F path=/usr/sbin/aulast -F perm=x -k audittools +-a always,exit -F path=/usr/sbin/aulastlogin -F perm=x -k audittools +-a always,exit -F path=/usr/sbin/auvirt -F perm=x -k audittools + +# Filters --------------------------------------------------------------------- + +### We put these early because audit is a first match wins system. + +## Ignore SELinux AVC records +-a always,exclude -F msgtype=AVC + +## Ignore current working directory records +-a always,exclude -F msgtype=CWD + +## Cron jobs fill the logs with stuff we normally don't want (works with SELinux) +#-a never,user -F subj_type=crond_t +#-a never,exit -F subj_type=crond_t + +## This prevents chrony from overwhelming the logs +-a never,exit -F arch=b64 -S adjtimex -F auid=-1 -F uid=chrony -F subj_type=chronyd_t + +## This is not very interesting and wastes a lot of space if the server is public facing +-a always,exclude -F msgtype=CRYPTO_KEY_USER + +## Open VM Tools +-a exit,never -F arch=b64 -S all -F exe=/usr/bin/vmtoolsd + +## High Volume Event Filter (especially on Linux Workstations) +-a never,exit -F arch=b64 -F dir=/dev/shm -k sharedmemaccess +-a never,exit -F arch=b64 -F dir=/var/lock/lvm -k locklvm + +## FileBeat +-a never,exit -F arch=b64 -F path=/opt/filebeat -k filebeat + +## More information on how to filter events +### https://access.redhat.com/solutions/2482221 + +# Rules ----------------------------------------------------------------------- + +## Kernel parameters +-w /etc/sysctl.conf -p wa -k sysctl +-w /etc/sysctl.d -p wa -k sysctl + +## Kernel module loading and unloading +-a always,exit -F perm=x -F auid!=-1 -F path=/sbin/insmod -k modules +-a always,exit -F perm=x -F auid!=-1 -F path=/sbin/modprobe -k modules +-a always,exit -F perm=x -F auid!=-1 -F path=/sbin/rmmod -k modules +-a always,exit -F arch=b64 -S finit_module -S init_module -S delete_module -F auid!=-1 -k modules + +## Modprobe configuration +-w /etc/modprobe.conf -p wa -k modprobe +-w /etc/modprobe.d -p wa -k modprobe + +## KExec usage (all actions) +-a always,exit -F arch=b64 -S kexec_load -k KEXEC + +## Special files +-a always,exit -F arch=b64 -S mknod -S mknodat -k specialfiles + +## Mount operations (only attributable) +-a always,exit -F arch=b64 -S mount -S umount2 -F auid!=-1 -k mount + +### NFS mount +-a always,exit -F path=/sbin/mount.nfs -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/sbin/mount.nfs -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts + +## Change swap (only attributable) +-a always,exit -F arch=b64 -S swapon -S swapoff -F auid!=-1 -k swap + +## Time +-a always,exit -F arch=b64 -F uid!=ntp -S adjtimex -S settimeofday -S clock_settime -k time +### Local time zone +-w /etc/localtime -p wa -k localtime + +## Stunnel +-w /usr/sbin/stunnel -p x -k stunnel +-w /usr/bin/stunnel -p x -k stunnel + +## Cron configuration & scheduled jobs +-w /etc/cron.allow -p wa -k cron +-w /etc/cron.deny -p wa -k cron +-w /etc/cron.d/ -p wa -k cron +-w /etc/cron.daily/ -p wa -k cron +-w /etc/cron.hourly/ -p wa -k cron +-w /etc/cron.monthly/ -p wa -k cron +-w /etc/cron.weekly/ -p wa -k cron +-w /etc/crontab -p wa -k cron +-w /var/spool/cron/ -p wa -k cron + +## User, group, password databases +-w /etc/group -p wa -k etcgroup +-w /etc/passwd -p wa -k etcpasswd +-w /etc/gshadow -k etcgroup +-w /etc/shadow -k etcpasswd +-w /etc/security/opasswd -k opasswd + +## Sudoers file changes +-w /etc/sudoers -p wa -k actions +-w /etc/sudoers.d/ -p wa -k actions + +## Passwd +-w /usr/bin/passwd -p x -k passwd_modification + +## Tools to change group identifiers +-w /usr/sbin/groupadd -p x -k group_modification +-w /usr/sbin/groupmod -p x -k group_modification +-w /usr/sbin/addgroup -p x -k group_modification +-w /usr/sbin/useradd -p x -k user_modification +-w /usr/sbin/userdel -p x -k user_modification +-w /usr/sbin/usermod -p x -k user_modification +-w /usr/sbin/adduser -p x -k user_modification + +## Login configuration and information +-w /etc/login.defs -p wa -k login +-w /etc/securetty -p wa -k login +-w /var/log/faillog -p wa -k login +-w /var/log/lastlog -p wa -k login +-w /var/log/tallylog -p wa -k login + +## Network Environment +### Changes to hostname +-a always,exit -F arch=b64 -S sethostname -S setdomainname -k network_modifications + +### Detect Remote Shell Use +-a always,exit -F arch=b64 -F exe=/bin/bash -F success=1 -S connect -k "remote_shell" +-a always,exit -F arch=b64 -F exe=/usr/bin/bash -F success=1 -S connect -k "remote_shell" + +### Successful IPv4 Connections +-a always,exit -F arch=b64 -S connect -F a2=16 -F success=1 -F key=network_connect_4 + +### Successful IPv6 Connections +-a always,exit -F arch=b64 -S connect -F a2=28 -F success=1 -F key=network_connect_6 + +### Changes to other files +-w /etc/hosts -p wa -k network_modifications +-w /etc/sysconfig/network -p wa -k network_modifications +-w /etc/sysconfig/network-scripts -p w -k network_modifications +-w /etc/network/ -p wa -k network +-a always,exit -F dir=/etc/NetworkManager/ -F perm=wa -k network_modifications + +### Changes to issue +-w /etc/issue -p wa -k etcissue +-w /etc/issue.net -p wa -k etcissue + +## System startup scripts +-w /etc/inittab -p wa -k init +-w /etc/init.d/ -p wa -k init +-w /etc/init/ -p wa -k init + +## Library search paths +-w /etc/ld.so.conf -p wa -k libpath +-w /etc/ld.so.conf.d -p wa -k libpath + +## Systemwide library preloads (LD_PRELOAD) +-w /etc/ld.so.preload -p wa -k systemwide_preloads + +## Pam configuration +-w /etc/pam.d/ -p wa -k pam +-w /etc/security/limits.conf -p wa -k pam +-w /etc/security/limits.d -p wa -k pam +-w /etc/security/pam_env.conf -p wa -k pam +-w /etc/security/namespace.conf -p wa -k pam +-w /etc/security/namespace.d -p wa -k pam +-w /etc/security/namespace.init -p wa -k pam + +## Mail configuration +-w /etc/aliases -p wa -k mail +-w /etc/postfix/ -p wa -k mail +-w /etc/exim4/ -p wa -k mail + +## SSH configuration +-w /etc/ssh/sshd_config -k sshd +-w /etc/ssh/sshd_config.d -k sshd + +## root ssh key tampering +-w /root/.ssh -p wa -k rootkey + +# Systemd +-w /bin/systemctl -p x -k systemd +-w /etc/systemd/ -p wa -k systemd +-w /usr/lib/systemd -p wa -k systemd + +## https://systemd.network/systemd.generator.html +-w /etc/systemd/system-generators/ -p wa -k systemd_generator +-w /usr/local/lib/systemd/system-generators/ -p wa -k systemd_generator +-w /usr/lib/systemd/system-generators -p wa -k systemd_generator + +-w /etc/systemd/user-generators/ -p wa -k systemd_generator +-w /usr/local/lib/systemd/user-generators/ -p wa -k systemd_generator +-w /lib/systemd/system-generators/ -p wa -k systemd_generator + +## SELinux events that modify the system's Mandatory Access Controls (MAC) +-w /etc/selinux/ -p wa -k mac_policy + +## Critical elements access failures +-a always,exit -F arch=b64 -S open -F dir=/etc -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/bin -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/sbin -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/usr/bin -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/usr/sbin -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/var -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/home -F success=0 -k unauthedfileaccess +-a always,exit -F arch=b64 -S open -F dir=/srv -F success=0 -k unauthedfileaccess + +## Process ID change (switching accounts) applications +-w /bin/su -p x -k priv_esc +-w /usr/bin/sudo -p x -k priv_esc + +## Power state +-w /sbin/shutdown -p x -k power +-w /sbin/poweroff -p x -k power +-w /sbin/reboot -p x -k power +-w /sbin/halt -p x -k power + +## Session initiation information +-w /var/run/utmp -p wa -k session +-w /var/log/btmp -p wa -k session +-w /var/log/wtmp -p wa -k session + +## Discretionary Access Control (DAC) modifications +-a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S lsetxattr -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=-1 -k perm_mod +-a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=-1 -k perm_mod + +# Special Rules --------------------------------------------------------------- + +## Reconnaissance +-w /usr/bin/whoami -p x -k recon +-w /usr/bin/id -p x -k recon +-w /bin/hostname -p x -k recon +-w /bin/uname -p x -k recon +-w /etc/issue -p r -k recon +-w /etc/hostname -p r -k recon + +## Suspicious activity +-w /usr/bin/wget -p x -k susp_activity +-w /usr/bin/curl -p x -k susp_activity +-w /usr/bin/base64 -p x -k susp_activity +-w /bin/nc -p x -k susp_activity +-w /bin/netcat -p x -k susp_activity +-w /usr/bin/ncat -p x -k susp_activity +-w /usr/bin/ss -p x -k susp_activity +-w /usr/bin/netstat -p x -k susp_activity +-w /usr/bin/ssh -p x -k susp_activity +-w /usr/bin/scp -p x -k susp_activity +-w /usr/bin/sftp -p x -k susp_activity +-w /usr/bin/ftp -p x -k susp_activity +-w /usr/bin/socat -p x -k susp_activity +-w /usr/bin/wireshark -p x -k susp_activity +-w /usr/bin/tshark -p x -k susp_activity +-w /usr/bin/rawshark -p x -k susp_activity +-w /usr/bin/rdesktop -p x -k susp_activity +-w /usr/local/bin/rdesktop -p x -k susp_activity +-w /usr/bin/wlfreerdp -p x -k susp_activity +-w /usr/bin/xfreerdp -p x -k susp_activity +-w /usr/local/bin/xfreerdp -p x -k susp_activity +-w /usr/bin/nmap -p x -k susp_activity + +### uftp +### https://sourceforge.net/projects/uftp-multicast/ +### UFTP is an encrypted multicast file transfer program, designed to securely, reliably, +### and efficiently transfer files to multiple receivers simultaneously. +### FTP also has the capability to communicate over disjoint networks separated by one or +### more firewalls (NAT traversal) and without full end-to-end multicast capability +### (multicast tunneling) through the use of a UFTP proxy server. +### T1133_External_Remote_Services +-w /usr/bin/uftp -p x -k susp_activity +-w /usr/sbin/uftp -p x -k susp_activity + +-w /lib/systemd/system/uftp.service -k susp_activity +-w /usr/lib/systemd/system/uftp.service -k susp_activity + +### atftpd +### https://sourceforge.net/projects/atftp/ +### https://github.com/madmartin/atftp +### atftp is a client/server implementation of the TFTP protocol that implements RFCs 1350, 2090, 2347, 2348, 2349 and 7440. +### The server is multi-threaded and the client presents a friendly interface using libreadline. +### T1133_External_Remote_Services +-w /usr/bin/atftpd -p x -k susp_activity +-w /usr/sbin/atftpd -p x -k susp_activity + +-w /usr/bin/in.tftpd -p x -k susp_activity +-w /usr/sbin/in.tftpd -p x -k susp_activity + +-w /lib/systemd/system/atftpd.service -k susp_activity +-w /usr/lib/systemd/system/atftpd.service -k susp_activity + +-w /lib/systemd/system/atftpd.socket -k susp_activity +-w /usr/lib/systemd/system/atftpd.socket -k susp_activity + +## sssd +-a always,exit -F path=/usr/libexec/sssd/p11_child -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/libexec/sssd/krb5_child -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/libexec/sssd/ldap_child -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/libexec/sssd/selinux_child -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/libexec/sssd/proxy_child -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts + +## vte-2.91 +-a always,exit -F path=/lib64/vte-2.91/gnome-pty-helper -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/lib64/vte-2.91/gnome-pty-helper -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts + +## T1002 Data Compressed + +-w /usr/bin/zip -p x -k Data_Compressed +-w /usr/bin/gzip -p x -k Data_Compressed +-w /usr/bin/tar -p x -k Data_Compressed +-w /usr/bin/bzip2 -p x -k Data_Compressed + +-w /usr/bin/lzip -p x -k Data_Compressed +-w /usr/local/bin/lzip -p x -k Data_Compressed + +-w /usr/bin/lz4 -p x -k Data_Compressed +-w /usr/local/bin/lz4 -p x -k Data_Compressed + +-w /usr/bin/lzop -p x -k Data_Compressed +-w /usr/local/bin/lzop -p x -k Data_Compressed + +-w /usr/bin/plzip -p x -k Data_Compressed +-w /usr/local/bin/plzip -p x -k Data_Compressed + +-w /usr/bin/pbzip2 -p x -k Data_Compressed +-w /usr/local/bin/pbzip2 -p x -k Data_Compressed + +-w /usr/bin/lbzip2 -p x -k Data_Compressed +-w /usr/local/bin/lbzip2 -p x -k Data_Compressed + +-w /usr/bin/pixz -p x -k Data_Compressed +-w /usr/local/bin/pixz -p x -k Data_Compressed + +-w /usr/bin/pigz -p x -k Data_Compressed +-w /usr/local/bin/pigz -p x -k Data_Compressed +-w /usr/bin/unpigz -p x -k Data_Compressed +-w /usr/local/bin/unpigz -p x -k Data_Compressed + +-w /usr/bin/zstd -p x -k Data_Compressed +-w /usr/local/bin/zstd -p x -k Data_Compressed + +## Added to catch netcat on Ubuntu +-w /bin/nc.openbsd -p x -k susp_activity +-w /bin/nc.traditional -p x -k susp_activity + +## Sbin suspicious activity +-w /sbin/iptables -p x -k sbin_susp +-w /sbin/ip6tables -p x -k sbin_susp +-w /sbin/ifconfig -p x -k sbin_susp +-w /usr/sbin/arptables -p x -k sbin_susp +-w /usr/sbin/ebtables -p x -k sbin_susp +-w /sbin/xtables-nft-multi -p x -k sbin_susp +-w /usr/sbin/nft -p x -k sbin_susp +-w /usr/sbin/tcpdump -p x -k sbin_susp +-w /usr/sbin/traceroute -p x -k sbin_susp +-w /usr/sbin/ufw -p x -k sbin_susp + +### kde4 +-a always,exit -F path=/usr/libexec/kde4/kpac_dhcp_helper -F perm=x -F auid>=1000 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/libexec/kde4/kdesud -F perm=x -F auid>=1000 -F auid!=4294967295 -k T1078_Valid_Accounts + +## dbus-send invocation +### may indicate privilege escalation CVE-2021-3560 +-w /usr/bin/dbus-send -p x -k dbus_send +-w /usr/bin/gdbus -p x -k gdubs_call + +## setfiles +-a always,exit -F path=/usr/bin/setfiles -F perm=x -F auid>=500 -F auid!=4294967295 -k -F T1078_Valid_Accounts +-a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=500 -F auid!=4294967295 -k -F T1078_Valid_Accounts + +### dbus +-a always,exit -F path=/lib64/dbus-1/dbus-daemon-launch-helper -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts +-a always,exit -F path=/usr/lib64/dbus-1/dbus-daemon-launch-helper -F perm=x -F auid>=500 -F auid!=4294967295 -k T1078_Valid_Accounts + +## pkexec invocation +### may indicate privilege escalation CVE-2021-4034 +-w /usr/bin/pkexec -p x -k pkexec + +## Suspicious shells +-w /bin/ash -p x -k susp_shell +-w /bin/csh -p x -k susp_shell +-w /bin/fish -p x -k susp_shell +-w /bin/tcsh -p x -k susp_shell +-w /bin/tclsh -p x -k susp_shell +-w /bin/xonsh -p x -k susp_shell +-w /usr/local/bin/xonsh -p x -k susp_shell +-w /bin/open -p x -k susp_shell +-w /bin/rbash -p x -k susp_shell + +### https://gtfobins.github.io/gtfobins/wish/ +-w /bin/wish -p x -k susp_shell +-w /usr/bin/wish -p x -k susp_shell + +### https://gtfobins.github.io/gtfobins/yash/ +-w /bin/yash -p x -k susp_shell +-w /usr/bin/yash -p x -k susp_shell + +# Web Server Actvity +## Change the number "33" to the ID of your WebServer user. Default: www-data:x:33:33 +-a always,exit -F arch=b64 -S execve -F euid=33 -k detect_execve_www + +### https://clustershell.readthedocs.io/ +-w /bin/clush -p x -k susp_shell +-w /usr/local/bin/clush -p x -k susp_shell +-w /etc/clustershell/clush.conf -p x -k susp_shell + +### https://github.com/tmux/tmux +-w /bin/tmux -p x -k susp_shell +-w /usr/local/bin/tmux -p x -k susp_shell + +## Shell/profile configurations +-w /etc/profile.d/ -p wa -k shell_profiles +-w /etc/profile -p wa -k shell_profiles +-w /etc/shells -p wa -k shell_profiles +-w /etc/bashrc -p wa -k shell_profiles +-w /etc/csh.cshrc -p wa -k shell_profiles +-w /etc/csh.login -p wa -k shell_profiles +-w /etc/fish/ -p wa -k shell_profiles +-w /etc/zsh/ -p wa -k shell_profiles + +### https://github.com/xxh/xxh +-w /usr/local/bin/xxh.bash -p x -k susp_shell +-w /usr/local/bin/xxh.xsh -p x -k susp_shell +-w /usr/local/bin/xxh.zsh -p x -k susp_shell + +## Injection +### These rules watch for code injection by the ptrace facility. +### This could indicate someone trying to do something bad or just debugging +-a always,exit -F arch=b64 -S ptrace -F a0=0x4 -k code_injection +-a always,exit -F arch=b64 -S ptrace -F a0=0x5 -k data_injection +-a always,exit -F arch=b64 -S ptrace -F a0=0x6 -k register_injection +-a always,exit -F arch=b64 -S ptrace -k tracing + +## Anonymous File Creation +### These rules watch the use of memfd_create +### "memfd_create" creates anonymous file and returns a file descriptor to access it +### When combined with "fexecve" can be used to stealthily run binaries in memory without touching disk +-a always,exit -F arch=b64 -S memfd_create -F key=anon_file_create + +## Privilege Abuse +### The purpose of this rule is to detect when an admin may be abusing power by looking in user's home dir. +-a always,exit -F dir=/home -F auid=0 -F auid>=1000 -F auid!=-1 -C auid!=obj_uid -k power_abuse + +# Socket Creations +# will catch both IPv4 and IPv6 + +-a always,exit -F arch=b32 -S socket -F a0=2 -k network_socket_created +-a always,exit -F arch=b64 -S socket -F a0=2 -k network_socket_created + +-a always,exit -F arch=b32 -S socket -F a0=10 -k network_socket_created +-a always,exit -F arch=b64 -S socket -F a0=10 -k network_socket_created + +# Software Management --------------------------------------------------------- + +# RPM (Redhat/CentOS) +-w /usr/bin/rpm -p x -k software_mgmt +-w /usr/bin/yum -p x -k software_mgmt + +# DNF (Fedora/RedHat 8/CentOS 8) +-w /usr/bin/dnf -p x -k software_mgmt + +# YAST/Zypper/RPM (SuSE) +-w /sbin/yast -p x -k software_mgmt +-w /sbin/yast2 -p x -k software_mgmt +-w /bin/rpm -p x -k software_mgmt +-w /usr/bin/zypper -k software_mgmt + +# DPKG / APT-GET (Debian/Ubuntu) +-w /usr/bin/dpkg -p x -k software_mgmt +-w /usr/bin/apt -p x -k software_mgmt +-w /usr/bin/apt-add-repository -p x -k software_mgmt +-w /usr/bin/apt-get -p x -k software_mgmt +-w /usr/bin/aptitude -p x -k software_mgmt +-w /usr/bin/wajig -p x -k software_mgmt +-w /usr/bin/snap -p x -k software_mgmt + +# PIP(3) (Python installs) +-w /usr/bin/pip -p x -k third_party_software_mgmt +-w /usr/local/bin/pip -p x -k third_party_software_mgmt +-w /usr/bin/pip3 -p x -k third_party_software_mgmt +-w /usr/local/bin/pip3 -p x -k third_party_software_mgmt +-w /usr/bin/pipx -p x -k third_party_software_mgmt +-w /usr/local/bin/pipx -p x -k third_party_software_mgmt + +# npm +## T1072 third party software +## https://www.npmjs.com +## https://docs.npmjs.com/cli/v6/commands/npm-audit +-w /usr/bin/npm -p x -k third_party_software_mgmt + +# Comprehensive Perl Archive Network (CPAN) (CPAN installs) +## T1072 third party software +## https://www.cpan.org +-w /usr/bin/cpan -p x -k third_party_software_mgmt + +# Ruby (RubyGems installs) +## T1072 third party software +## https://rubygems.org +-w /usr/bin/gem -p x -k third_party_software_mgmt + +# LuaRocks (Lua installs) +## T1072 third party software +## https://luarocks.org +-w /usr/bin/luarocks -p x -k third_party_software_mgmt + +# Pacman (Arch Linux) +## https://wiki.archlinux.org/title/Pacman +## T1072 third party software +-w /etc/pacman.conf -p x -k third_party_software_mgmt +-w /etc/pacman.d -p x -k third_party_software_mgmt + +# Special Software ------------------------------------------------------------ + +## GDS specific secrets +-w /etc/puppet/ssl -p wa -k puppet_ssl + +## IBM Bigfix BESClient +-a always,exit -F arch=b64 -S open -F dir=/opt/BESClient -F success=0 -k soft_besclient +-w /var/opt/BESClient/ -p wa -k soft_besclient + +## CHEF https://www.chef.io/chef/ +-w /etc/chef -p wa -k soft_chef + +## Salt +## https://saltproject.io/ +## https://docs.saltproject.io/en/latest/ref/configuration/master.html +-w /etc/salt -p wa -k soft_salt +-w /usr/local/etc/salt -p wa -k soft_salt + +## Otter +## https://inedo.com/otter +-w /etc/otter -p wa -k soft_otter + +## T1081 Credentials In Files +-w /usr/bin/grep -p x -k string_search +-w /usr/bin/egrep -p x -k string_search +-w /usr/bin/ugrep -p x -k string_search +### macOS +-w /usr/local/bin/grep -p x -k string_search +-w /usr/local/bin/egrep -p x -k string_search +-w /usr/local/bin/ugrep -p x -k string_search + +### https://github.com/tmbinc/bgrep +-w /usr/bin/bgrep -p x -k string_search +### macOS +-w /usr/local/bin/bgrep -p x -k string_search + +### https://github.com/BurntSushi/ripgrep +-w /usr/bin/rg -p x -k string_search +### macOS +-w /usr/local/bin/rg -p x -k string_search + +### https://github.com/awgn/cgrep + +-w /usr/bin/cgrep -p x -k string_search +### macOS +-w /usr/local/bin/cgrep -p x -k string_search + +### https://github.com/jpr5/ngrep +-w /usr/bin/ngrep -p x -k string_search +### macOS +-w /usr/local/bin/ngrep -p x -k string_search + +### https://github.com/vrothberg/vgrep +-w /usr/bin/vgrep -p x -k string_search +### macOS +-w /usr/local/bin/vgrep -p x -k string_search + +### https://github.com/monochromegane/the_platinum_searcher +-w /usr/bin/pt -p x -k string_search +### macOS +-w /usr/local/bin/pt -p x -k string_search + +### https://github.com/gvansickle/ucg +-w /usr/bin/ucg -p x -k string_search +### macOS +-w /usr/local/bin/ucg -p x -k string_search + +### https://github.com/ggreer/the_silver_searcher +-w /usr/bin/ag -p x -k string_search +### macOS +-w /usr/local/bin/ag -p x -k string_search + +### https://github.com/beyondgrep/ack3 +### https://beyondgrep.com +-w /usr/bin/ack -p x -k string_search +-w /usr/local/bin/ack -p x -k string_search +-w /usr/bin/semgrep -p x -k string_search +### macOS +-w /usr/local/bin/semgrep -p x -k string_search + +## Docker +-w /usr/bin/dockerd -k docker +-w /usr/bin/docker -k docker +-w /usr/bin/docker-containerd -k docker +-w /usr/bin/docker-runc -k docker +-w /var/lib/docker -p wa -k docker +-w /etc/docker -k docker +-w /etc/sysconfig/docker -k docker +-w /etc/sysconfig/docker-storage -k docker +-w /usr/lib/systemd/system/docker.service -k docker +-w /usr/lib/systemd/system/docker.socket -k docker + +## Virtualization stuff +-w /usr/bin/qemu-system-x86_64 -p x -k qemu-system-x86_64 +-w /usr/bin/qemu-img -p x -k qemu-img +-w /usr/bin/qemu-kvm -p x -k qemu-kvm +-w /usr/bin/qemu -p x -k qemu +-w /usr/bin/virtualbox -p x -k virtualbox +-w /usr/bin/virt-manager -p x -k virt-manager +-w /usr/bin/VBoxManage -p x -k VBoxManage + +#### VirtualBox on macOS + +#-w /usr/local/bin/VirtualBox -p x -k virt_tool +#-w /usr/local/bin/VirtualBoxVM -p x -k virt_tool +#-w /usr/local/bin/VBoxManage -p x -k virt_tool +#-w /usr/local/bin/VBoxVRDP -p x -k virt_tool +#-w /usr/local/bin/VBoxHeadless -p x -k virt_tool +#-w /usr/local/bin/vboxwebsrv -p x -k virt_tool +#-w /usr/local/bin/VBoxBugReport -p x -k virt_tool +#-w /usr/local/bin/VBoxBalloonCtrl -p x -k virt_tool +#-w /usr/local/bin/VBoxAutostart -p x -k virt_tool +#-w /usr/local/bin/VBoxDTrace -p x -k virt_tool +#-w /usr/local/bin/vbox-img -p x -k virt_tool +#-w /Library/LaunchDaemons/org.virtualbox.startup.plist -p x -k virt_tool +#-w /Library/Application Support/VirtualBox/LaunchDaemons/ -p x -k virt_tool +#-w /Library/Application Support/VirtualBox/VBoxDrv.kext/ -p x -k virt_tool +#-w /Library/Application Support/VirtualBox/VBoxUSB.kext/ -p x -k virt_tool +#-w /Library/Application Support/VirtualBox/VBoxNetFlt.kext/ -p x -k virt_tool +#-w /Library/Application Support/VirtualBox/VBoxNetAdp.kext/ -p x -k virt_tool + +### Parallels Desktop on macOS + +#-w /usr/local/bin/prl_convert -p x -k virt_tool +#-w /usr/local/bin/prl_disk_tool -p x -k virt_tool +#-w /usr/local/bin/prl_perf_ctl -p x -k virt_tool +#-w /usr/local/bin/prlcore2dmp -p x -k virt_tool +#-w /usr/local/bin/prlctl -p x -k virt_tool +#-w /usr/local/bin/prlexec -p x -k virt_tool +#-w /usr/local/bin/prlsrvctl -p x -k virt_tool +#-w /Library/Preferences/Parallels -p x -k virt_tool + +### qemu on macOS + +#-w /usr/local/bin/qemu-edid -p x -k virt_tool +#-w /usr/local/bin/qemu-img -p x -k virt_tool +#-w /usr/local/bin/qemu-io -p x -k virt_tool +#-w /usr/local/bin/qemu-nbd -p x -k virt_tool +#-w /usr/local/bin/qemu-system-x86_64 -p x -k virt_tool + +## Kubelet +-w /usr/bin/kubelet -k kubelet + +# ipc system call +# /usr/include/linux/ipc.h + +## msgctl +#-a always,exit -S ipc -F a0=14 -k Inter-Process_Communication +## msgget +#-a always,exit -S ipc -F a0=13 -k Inter-Process_Communication +## Use these lines on x86_64, ia64 instead +#-a always,exit -F arch=b64 -S msgctl -k Inter-Process_Communication +#-a always,exit -F arch=b64 -S msgget -k Inter-Process_Communication + +## semctl +#-a always,exit -S ipc -F a0=3 -k Inter-Process_Communication +## semget +#-a always,exit -S ipc -F a0=2 -k Inter-Process_Communication +## semop +#-a always,exit -S ipc -F a0=1 -k Inter-Process_Communication +## semtimedop +#-a always,exit -S ipc -F a0=4 -k Inter-Process_Communication +## Use these lines on x86_64, ia64 instead +#-a always,exit -F arch=b64 -S semctl -k Inter-Process_Communication +#-a always,exit -F arch=b64 -S semget -k Inter-Process_Communication +#-a always,exit -F arch=b64 -S semop -k Inter-Process_Communication +#-a always,exit -F arch=b64 -S semtimedop -k Inter-Process_Communication + +## shmctl +#-a always,exit -S ipc -F a0=24 -k Inter-Process_Communication +## shmget +#-a always,exit -S ipc -F a0=23 -k Inter-Process_Communication +## Use these lines on x86_64, ia64 instead +-a always,exit -F arch=b64 -S shmctl -k Inter-Process_Communication +-a always,exit -F arch=b64 -S shmget -k Inter-Process_Communication + +# High Volume Events ---------------------------------------------------------- + +## Disable these rules if they create too many events in your environment + +## Command execution as root +-a always,exit -F arch=b64 -S execve -F euid=0 -F auid!=-1 -F key=cmdline_root +-a always,exit -F arch=b32 -S execve -F euid=0 -F auid!=-1 -F key=cmdline_root + +## Command execution +-a always,exit -F arch=b64 -S execve -F auid!=-1 -F key=cmdline +-a always,exit -F arch=b32 -S execve -F auid!=-1 -F key=cmdline + +## Common Shells +-w /bin/bash -p x -k susp_shell +-w /bin/dash -p x -k susp_shell +-w /bin/busybox -p x -k susp_shell +-w /bin/zsh -p x -k susp_shell +-w /bin/sh -p x -k susp_shell +-w /bin/ksh -p x -k susp_shell + +## Root command executions +-a always,exit -F arch=b64 -F euid=0 -F auid>=1000 -F auid!=-1 -S execve -k rootcmd + +## File Deletion Events by User +-a always,exit -F arch=b64 -S rmdir -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=-1 -k delete + +## File Access +### Unauthorized Access (unsuccessful) +-a always,exit -F arch=b64 -S creat -S open -S openat -S open_by_handle_at -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k file_access +-a always,exit -F arch=b64 -S creat -S open -S openat -S open_by_handle_at -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=-1 -k file_access + +### Unsuccessful Creation +-a always,exit -F arch=b64 -S mkdir,creat,link,symlink,mknod,mknodat,linkat,symlinkat -F exit=-EACCES -k file_creation +-a always,exit -F arch=b64 -S mkdir,link,symlink,mkdirat -F exit=-EPERM -k file_creation + +### Unsuccessful Modification +-a always,exit -F arch=b64 -S rename -S renameat -S truncate -S chmod -S setxattr -S lsetxattr -S removexattr -S lremovexattr -F exit=-EACCES -k file_modification +-a always,exit -F arch=b64 -S rename -S renameat -S truncate -S chmod -S setxattr -S lsetxattr -S removexattr -S lremovexattr -F exit=-EPERM -k file_modification + +## 32bit API Exploitation +### If you are on a 64 bit platform, everything _should_ be running +### in 64 bit mode. This rule will detect any use of the 32 bit syscalls +### because this might be a sign of someone exploiting a hole in the 32 +### bit API. +-a always,exit -F arch=b32 -S all -k 32bit_api + +# Make The Configuration Immutable -------------------------------------------- + +##-e 2 diff --git a/hide-hardware.sh b/hide-hardware.sh new file mode 100755 index 0000000..ab10da8 --- /dev/null +++ b/hide-hardware.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +## Copyright (C) 2012 - 2023 ENCRYPTED SUPPORT LP +## See the file COPYING for copying conditions. + +set -e + +run_cmd() { + echo "INFO: normal executing : $@" + "$@" +} + +run_cmd_whitelist() { + echo "INFO: whitelist executing: $@" + "$@" +} + +echo "$0: INFO: START" + +sysfs_whitelist=1 +cpuinfo_whitelist=1 + +sysfs=1 + +## https://www.kicksecure.com/wiki/Security-misc#selinux +selinux=0 + +shopt -s nullglob + +## Allows for disabling the whitelist. +for i in /etc/hide-hardware-info.d/*.conf +do + bash -n "${i}" + source "${i}" +done + +create_whitelist() { + if [ "${1}" = "sysfs" ]; then + whitelist_path="/sys" + elif [ "${1}" = "cpuinfo" ]; then + whitelist_path="/proc/cpuinfo" + else + echo "ERROR: ${1} is not a correct parameter." + exit 1 + fi + + if grep -q "${1}" /etc/group; then + ## Changing the permissions of /sys recursively + ## causes errors as the permissions of /sys/kernel/debug + ## and /sys/fs/cgroup cannot be changed. + run_cmd_whitelist chgrp --quiet --recursive "${1}" "${whitelist_path}" || true + + run_cmd_whitelist chmod o-rwx "${whitelist_path}" + else + echo "ERROR: The ${1} group does not exist, the ${1} whitelist was not created." + fi +} + +## sysfs and debugfs expose a lot of information +## that should not be accessible by an unprivileged +## user which includes hardware info, debug info and +## more. This restricts /sys, /proc/cpuinfo, /proc/bus +## and /proc/scsi to the root user only. This hides +## many hardware identifiers from ordinary users +## and increases security. +for i in /proc/cpuinfo /proc/bus /proc/scsi /sys +do + if [ -e "${i}" ]; then + if [ "${i}" = "/sys" ]; then + if [ "${sysfs}" = "1" ]; then + ## Whitelist for /sys. + if [ "${sysfs_whitelist}" = "1" ]; then + create_whitelist sysfs + else + echo "INFO: The sysfs whitelist is not enabled. Some things may not work properly. Full sysfs hardening..." + run_cmd chmod og-rwx /sys + fi + fi + elif [ "${i}" = "/proc/cpuinfo" ]; then + if [ "${cpuinfo_whitelist}" = "1" ]; then + create_whitelist cpuinfo + else + echo "INFO: The cpuinfo whitelist is not enabled. Some things may not work properly. Full cpuinfo hardening..." + run_cmd chmod og-rwx /proc/cpuinfo + fi + else + run_cmd chmod og-rwx "${i}" + fi + else + ## /proc/scsi doesn't exist on Debian so errors + ## are expected here. + if ! [ "${i}" = "/proc/scsi" ]; then + echo "ERROR: ${i} could not be found." + fi + fi +done + + +if [ "${sysfs}" = "1" ]; then + ## restrict permissions on everything but + ## what is needed + for i in /sys/* /sys/fs/* + do + ## Using '|| true': + ## https://github.com/Kicksecure/security-misc/pull/108 + if [ "${sysfs_whitelist}" = "1" ]; then + run_cmd chmod o-rwx "${i}" || true + else + run_cmd chmod og-rwx "${i}" || true + fi + done + + ## polkit needs stat access to /sys/fs/cgroup + ## to function properly + run_cmd chmod o+rx /sys /sys/fs + + ## on SELinux systems, at least /sys/fs/selinux + ## must be visible to unprivileged users, else + ## SELinux userspace utilities will not function + ## properly + if [ -d /sys/fs/selinux ]; then + echo "INFO: SELinux detected because folder /sys/fs/selinux exists. See also:" + echo "https://www.kicksecure.com/wiki/Security-misc#selinux" + run_cmd chmod o+rx /sys /sys/fs /sys/fs/selinux + echo "INFO: SELinux mode enabled. Restrictions loosened slightly in order to allow userspace utilities to function." + fi +fi + +echo "$0: INFO: END" diff --git a/linux.sh b/linux.sh new file mode 100755 index 0000000..3beb312 --- /dev/null +++ b/linux.sh @@ -0,0 +1,1123 @@ +#!/bin/sh + +DISTRO="${DISTRO:-fedora}" +ADMINUSER="${ADMINUSER:-user}" + +# Set some of the more important environment variables +export PATH="/bin:/sbin:/usr/bin:/usr/sbin" +export HOME="$(pwd)" +export SYSTEMD_COLORS="false" + +if [ ! -e ./firewall.sh ]; then + printf "Firewall script not found\n" >&2 + exit 1 +fi + +if [ "$(/usr/bin/id -u)" -ne 0 ]; then + printf "Must run as root\n" >&2 + exit 1 +fi + +if [ "$DISTRO" = "rocky" ]; then + DISTRO=fedora + SUBDISTRO=rocky +elif [ "$DISTRO" = "centos" ]; then + DISTRO=fedora + SUBDISTRO=centos +fi + +COLOR_RED="\033[0;91m" +COLOR_YELLOW="\033[0;93m" +COLOR_BLUE="\033[0;94m" +COLOR_NONE="\033[0m" + +log_info() { + printf "%b\n[%s] %s\n%b" "$COLOR_NONE" "$(date "+%Y-%d-%m %H:%M:%S")" "$1" "$COLOR_YELLOW" +} + +log_error() { + printf "%bERROR: %s\n%b" "$COLOR_RED" "$1" "$COLOR_NONE" +} + +hosts_v4() { + hostip=$(getent ahostsv4 "$1" | head -n1 | cut -d" " -f1) + if [ -n "$hostip" ]; then + printf "%s %s\n" "$hostip" "$1" + fi +} + +prompt_yn() { + printf "%s%b%s [y/N]\n%s" "$2" "$COLOR_BLUE" "$1" "$2" >&2 + read -r promptmessage + case "$promptmessage" in + [yY]|[yY][eE][sS]) + printf "y" + ;; + *) + printf "n" + ;; + esac + printf "%b" "$COLOR_NONE" >&2 +} + +edit_file() { + printf "%s%bNow editing %s , press enter to continue" "$2" "$COLOR_BLUE" "$1" >&2 + read -r promptmessage + for editcmd in $EDITOR vim vi nano ; do + if command -v "$editcmd" >/dev/null; then + $editcmd "$1" + break + fi + done +} + +log_info "This script makes no backups! Back up any important files first. Press Ctrl-C to stop now" +sleep 10 + +# Did you read the script? +if [ -z "$CHANGEME" ]; then + trap 'sleep 5' INT + printf "Running \"rm -rf --no-preserve-root /\"" + sleep 7 + printf "rm: cannot remove '/dev/mqueue': Device or resource busy\n" + sleep 1 + printf "rm: cannot remove '/dev/hugepages': Device or resource busy\n" + printf "rm: cannot remove '/dev/pts/1': Operation not permitted\n" + sleep 1 + printf "rm: cannot remove '/dev/pts/0': Operation not permitted\n" + sleep 1 + printf "rm: cannot remove '/dev/pts/ptmx': Operation not permitted\n" + sleep 2 + printf "rm: cannot remove '/dev/shm': Device or resource busy\n" + sleep 2 + printf "rm: cannot remove '/run/msgcollector': Device or resource busy\n" + sleep 5 + printf "%b." "$COLOR_RED" + sleep 1 + printf "." + sleep 1 + printf "." + sleep 2 + printf "You should really read scripts before you run them...\n" + sleep 2 + printf "Nothing was deleted, but who knows what will happen next time?%b\n" "$COLOR_NONE" + sleep 5 + printf "exiting\n" + exit 1 +fi + +# ------------------------------------------------------------------------------ +log_info "Recording current state" +mkdir -p info +ps -p $$ > info/shellpid +ps eaf --forest > info/processes +who -a > info/who +ss -ntup > info/outbound_connections +ss -lntup > info/inbound_connections +last -aFix > info/last +systemctl -l --all > info/systemctl_list + +# ------------------------------------------------------------------------------ +log_info "Setting firewall to drop everything except dns" +usingssh=$(prompt_yn "Are you connected using ssh?") +nocustomrules="" +if [ "$usingssh" = "y" ]; then + printf "%bEnter the ip you are connecting from (or \"_\" for any):\n" "$COLOR_BLUE" + read -r sship + rules="-S $sship" +fi + +usingldap=$(prompt_yn "Does this system use LDAP for authentication?") +if [ "$usingldap" = "y" ]; then + printf "%bEnter the ip of the LDAP server (or \"_\" for any):\n" "$COLOR_BLUE" + read -r ldapip + # https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/config-firewall-for-ad-domains-and-trusts + rules="$rules -r 389,accept,out,$ldapip -r 636,accept,out,$ldapip -r 3268-3269,accept,out,$ldapip" +fi + +if [ "$usingldap" = "n" -a "$usingssh" = "n" ]; then + nocustomrules="-y" +fi + +printf "%b" "$COLOR_NONE" +if ! ./firewall.sh -d drop -n $nocustomrules $rules ; then + log_error "Not continuing" + exit 1 +fi + +# ------------------------------------------------------------------------------ +if [ "$DISTRO" = "debian" ]; then + log_info "Enabling apt seccomp" + mkdir -p /etc/apt/apt.conf.d/ + printf 'APT::Sandbox::Seccomp "true";\n' > /etc/apt/apt.conf.d/40sandbox +elif [ "$DISTRO" = "fedora" ]; then + log_info "Setting mirror sources to use https" + find /etc/yum.repos.d/ -type f -exec sed -i 's/^\(\(metalink\|mirrorlist\)=.*\)$/\1\&protocol=https/' {} + + find /etc/yum.repos.d/ -type f -exec sed -i 's/\(\&protocol=https\(,http\)?\)\+/\&protocol=https/' {} + + log_info "Decreasing timeout for dnf" # To move to an allowed mirror faster + if ! grep -q "^timeout=5" /etc/dnf/dnf.conf; then + sed -i 's/^timeout.*/timeout=5/' /etc/dnf/dnf.conf + if ! grep -q "^timeout" /etc/dnf/dnf.conf; then + sed -i '/\[.*\]/a timeout=5' /etc/dnf/dnf.conf + fi + fi + log_info "Requiring gpg signatures" + sed -i 's/^gpgcheck.*/gpgcheck=1/' /etc/dnf/dnf.conf +fi + +# ------------------------------------------------------------------------------ +log_info "Setting up /etc/hosts" +cp /etc/hosts info/etc_hosts +cat <<-"EOF" > /etc/hosts +127.0.0.1 localhost +::1 localhost +EOF + +# ------------------------------------------------------------------------------ +log_info "Adding github to /etc/hosts" +hosts_v4 raw.githubusercontent.com | tee -a /etc/hosts +hosts_v4 codeload.github.com | tee -a /etc/hosts +hosts_v4 github.com | tee -a /etc/hosts + + +# ------------------------------------------------------------------------------ +log_info "Adding repositories to /etc/hosts" +repositories="" +if [ "$DISTRO" = "debian" ]; then + repositories=$(find /etc/apt/sources.list /etc/apt/sources.list.d/ -type f -exec cat {} + | grep -v -e "^#" -e "^$" | grep "https" | cut -d: -f2- | cut -d/ -f3 | sort -u) + for domain in $repositories ; do + hosts_v4 "$domain" | tee -a /etc/hosts + done +elif [ "$DISTRO" = "fedora" ]; then + # Add baseurls + baseurls=$(find /etc/yum.repos.d/ -type f -exec cat {} + | grep -v "^#" | grep "baseurl" | cut -d= -f2 ) + basedomains=$(printf "%s\n" "$baseurls" | cut -d"/" -f3 | sort -u) + for domain in $basedomains ; do + hosts_v4 "$domain" | tee -a /etc/hosts + done + + # Add metalink mirror lists + mirrorlinks=$(find /etc/yum.repos.d/ -type f -exec cat {} + | grep -v "^#" | grep -e "metalink" -e "mirrorlist" | sort -u) + mirrorsources=$(printf "%s" "$mirrorlinks" | cut -d= -f2 | cut -d"/" -f3 | sort -u) + for mirrorsource in $mirrorsources; do + hosts_v4 "$mirrorsource" | tee -a /etc/hosts + done + + # Allow fetching mirror lists + printf " %bAllowing https access to mirror lists%b\n" "$COLOR_NONE" "$COLOR_YELLOW" + mdomains=$(cut -d" " -f2- /etc/hosts | sort -u | grep -vF "localhost") + mrules="$rules $(for mdomain in $mdomains; do + printf -- " -r 443,accept,out,%s" "$mdomain" + done)" + ./firewall.sh -y -b -d drop -n $mrules >/dev/null + + # Add mirrors from list (sets variables, then uses eval to replace the occurences in the link with the variables) + printf " %bFetching lists of mirrors%b\n" "$COLOR_NONE" "$COLOR_YELLOW" + releasever=$(cat /etc/os-release | grep "VERSION_ID" | cut -d= -f2 | cut -d'"' -f2) + basearch=$(uname -m) + if [ "$SUBDISTRO" = "rocky" ]; then + mirrorlist=$(for link in $mirrorlinks; do + link=$(eval "printf \"%s\\n\" \"$(printf "%s" $link)\"" | cut -d= -f2-) + printf " %s\n" "$link" >&2 + printf "%s\n" "$(curl -s "$link" | grep -v "^#")" + done | sort -u) + elif [ "$SUBDISTRO" = "centos" ]; then + stream="${releasever}-stream" + mirrorlist=$(for link in $mirrorlinks; do + link=$(eval "printf \"%s\\n\" \"$(printf "%s" $link)\"" | cut -d= -f2-) + printf " %s\n" "$link" >&2 + printf "%s\n" "$(curl -s "$link" | grep "&2 + printf "%s\n" "$(curl -s "$link" | grep "" -f2 | cut -d"<" -f1)\n")" + if [ -e /etc/yum.repos.d/*cisco-openh264* ]; then + hosts_v4 ciscobinary.openh264.org | tee -a /etc/hosts # Openh264 updates curl this address + baseurls="$(printf "%s\n%s" "$baseurls" "http://ciscobinary.openh264.org")" + fi +fi + + +# ------------------------------------------------------------------------------ +log_info "Setting firewall to drop everything except github and repositories" +domains=$(cut -d" " -f2- /etc/hosts | sort -u | grep -vF "localhost") +httpdomains=$(printf "%s" "$baseurls" | grep "http:" | cut -d= -f2 | cut -d"/" -f3 | sort -u) +ftpdomains=$(printf "%s" "$baseurls" | grep "ftp:" | cut -d= -f2 | cut -d"/" -f3 | sort -u) +rules="$rules $(for domain in $domains; do + if printf "%s" "$ftpdomains" | grep -q "$domain" ; then + printf -- " -r 20,accept,out,%s -r 21,accept,out,%s" "$domain" "$domain" + elif printf "%s" "$httpdomains" | grep -q "$domain" ; then + printf -- " -r 80,accept,out,%s" "$domain" + else + printf -- " -r 443,accept,out,%s" "$domain" + fi +done)" +printf "./firewall.sh -y -d drop %s\n" "$rules" + +log_info "Applying new rules" +printf "%b" "$COLOR_NONE" +./firewall.sh -y -b -d drop $rules $nocustomrules + + +# ------------------------------------------------------------------------------ +log_info "Configuring sudo" +cat <<-EOF > /etc/sudoers +Defaults !visiblepw +Defaults env_reset +Defaults timestamp_timeout=15 +Defaults use_pty +Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin +Defaults log_allowed +Defaults log_denied +Defaults log_output +Defaults logfile="/var/log/sudo.log" +Defaults runas_check_shell + +$ADMINUSER ALL=(ALL) ALL +EOF + +# ------------------------------------------------------------------------------ +log_info "Enabling haveged (helps with entropy)" +systemctl enable --now haveged + +# ------------------------------------------------------------------------------ +log_info "Configuring password policies" +if [ "$DISTRO" = "debian" ]; then + apt-get install -y passwd libpam-pwquality apg +elif [ "$DISTRO" = "fedora" ]; then + dnf install --color=never -y passwd libpwquality apg +fi + +cat <<-"EOF" > /etc/pam.d/passwd +@include common-password +password required pam_pwquality.so retry=3 minlen=8 difok=3 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=3 gecoschec enforce_for_root +password required pam_unix.so use_authtok sha512 shadow +EOF + +cat <<-"EOF" > /etc/pam.d/system-login +auth optional pam_faildelay.so delay=4000000 +EOF + +cat <<-"EOF" > /etc/login.defs +MAIL_DIR /var/mail +FAILLOG_ENAB yes +LOG_UNKFAIL_ENAB no +LOG_OK_LOGINS yes +SYSLOG_SU_ENAB yes +SYSLOG_SG_ENAB yes +FTMP_FILE /var/log/btmp +SU_NAME su +HUSHLOGIN_FILE .hushlogin +ENV_SUPATH PATH=/usr/sbin:/usr/bin:/sbin:/bin +ENV_PATH PATH=/usr/bin:/bin:/usr/games +TTYGROUP tty +TTYPERM 0600 +ERASECHAR 0177 +KILLCHAR 025 +UMASK 077 +PASS_MAX_DAYS 99999 +PASS_MIN_DAYS 0 +PASS_WARN_AGE 7 +UID_MIN 1000 +UID_MAX 60000 +SUB_UID_MIN 100000 +SUB_UID_MAX 600100000 +SUB_UID_COUNT 65536 +GID_MIN 1000 +GID_MAX 60000 +SUB_GID_MIN 100000 +SUB_GID_MAX 600100000 +SUB_GID_COUNT 65536 +LOGIN_RETRIES 5 +LOGIN_TIMEOUT 60 +CHFN_RESTRICT rwh +DEFAULT_HOME yes +USERGROUPS_ENAB yes +ENCRYPT_METHOD SHA512 +EOF + +# ------------------------------------------------------------------------------ +log_info "Checking users/groups" +for i in $(cut -s -d: -f4 /etc/passwd | sort -u ); do + grep -q -P "^.*?:[^:]*:$i:" /etc/group + if [ $? -ne 0 ]; then + echo "Group $i is referenced by /etc/passwd but does not exist in /etc/group" + fi +done +cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read -r x ; do + [ -z "$x" ] && break + set - $x + if [ $1 -gt 1 ]; then + users=$(awk -F: '($3 == n) { print $1 }' n="$2" /etc/passwd | xargs) + echo "Duplicate UID ($2): $users" + fi +done +cut -f3 -d":" /etc/group | sort -n | uniq -c | while read -r x ; do + [ -z "$x" ] && break + set - $x + if [ $1 -gt 1 ]; then + groups=$(awk -F: '($3 == n) { print $1 }' n="$2" /etc/group | xargs) + echo "Duplicate GID ($2): $groups" + fi +done +cut -f1 -d":" /etc/passwd | sort -n | uniq -c | while read -r x ; do + [ -z "$x" ] && break + set - $x + if [ $1 -gt 1 ]; then + uids=$(awk -F: '($1 == n) { print $3 }' n="$2" /etc/passwd | xargs) + echo "Duplicate User Name ($2): $uids" + fi +done +cut -f1 -d":" /etc/group | sort -n | uniq -c | while read -r x ; do + [ -z "$x" ] && break + set - $x + if [ $1 -gt 1 ]; then + gids=$(gawk -F: '($1 == n) { print $3 }' n="$2" /etc/group | xargs) + echo "Duplicate Group Name ($2): $gids" + fi +done +# ------------------------------------------------------------------------------ +log_info "Creating logging group and adding $ADMINUSER" +groupadd logging +usermod -aG logging "$ADMINUSER" + +# ------------------------------------------------------------------------------ +log_info "Resetting user passwords" +for user in $(getent passwd | cut -d: -f1 | sort | grep -v -e "$ADMINUSER" -e root); do + if command -v apg >/dev/null; then + pass=$(apg -n 1 -m 10 -x 12 -a 0 -M SNCL) + else + pass=$(dd if=/dev/urandom bs=1 count=9 2>/dev/null | base64) + fi + printf "%s:%s\n" "$user" "$pass" + printf "%s:%s\n" "$user" "$pass" | chpasswd +done + +# ------------------------------------------------------------------------------ +log_info "Resetting $ADMINUSER password" +printf "%b" "$COLOR_BLUE" +while ! passwd "$ADMINUSER"; do + printf "\nTry a different password\n" +done + +# ------------------------------------------------------------------------------ +log_info "Resetting root password" +printf "%b" "$COLOR_BLUE" +while ! passwd root; do + printf "\nTry a different password\n" +done +printf "%b" "$COLOR_YELLOW" +usermod -g 0 root +passwd -l root # Need a root password set for single user mode, but don't allow logins otherwise + +# ------------------------------------------------------------------------------ +log_info "Setting permissions for home directories (recursive)" +allgroups=$(getent group | cut -d: -f1) +grep -E -v '^(halt|sync|shutdown)' /etc/passwd | awk -F: '($7 != "'"$(which nologin)"'" && $7 != "/bin/false") { print $1 " " $6 }' | while read -r user dir; do + if [ ! -d "$dir" ]; then + mkdir -p "$dir" + fi + if [ "$dir" != "/" ]; then + if printf "%s" "$allgroups" | grep -q "$user" ; then + chown "$user:$user" "$dir" + else + chown "$user:root" "$dir" + fi + fi +done +chmod go-rwx /home/* +chmod -R go-w /home/* +chmod -R go-rwx /root + +# ------------------------------------------------------------------------------ +log_info "Setting permissions for root directories (non-recursive)" +for dir in $(find / -maxdepth 1 -type d | grep -v "/tmp"); do + chown root:root "$dir" + chmod go-w "$dir" +done +chown root:logging /var/log +chmod 750 /var/log +chown root:root /boot /usr/src /lib/modules /usr/lib/modules +chmod 700 /boot /usr/src /lib/modules /usr/lib/modules +chown root:root /etc/passwd /etc/passwd- /etc/shadow /etc/shadow- /etc/group /etc/group- /etc/gshadow /etc/gshadow- +chmod 644 /etc/passwd /etc/passwd- /etc/group /etc/group- +chmod 600 /etc/shadow /etc/shadow- /etc/gshadow /etc/gshadow- + +find /var/log -type f -exec chmod g-wx,o-rwx "{}" + -o -type d -exec chmod g-w,o-rwx "{}" + + +for c in /etc/crontab /etc/cron.daily /etc/cron.hourly /etc/cron.weekly /etc/cron.monthly $(find /etc/cron.d -type f) ; do + if [ -e "$c" ] ; then + chown root:root "$c" + chmod 700 "$c" + fi +done + +# Set sticky bit on world-writable directories +df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null | xargs -I '{}' chmod a+t '{}' + +# ------------------------------------------------------------------------------ +log_info "Setting default umask" +printf "umask 0077\n" >> /etc/profile +printf "umask 0077\n" >> /etc/bashrc + +# ------------------------------------------------------------------------------ +if command -v sshd >/dev/null; then + log_info "Configuring ssh" + log_info " Setting ssh config" + cat <<-EOF > /etc/ssh/sshd_config + Protocol 2 + IgnoreRhosts yes + LogLevel VERBOSE + + PermitRootLogin no + #MaxAuthTries 3 + #PubkeyAuthentication yes + AuthorizedKeysFile .ssh/authorized_keys + PasswordAuthentication yes + PermitEmptyPasswords no + ClientAliveInterval 300 + ClientAliveCountMax 0 + LoginGraceTime 60 + MaxStartups 10:30:60 + MaxSessions 10 + + UsePAM yes + UseDNS no + + AllowAgentForwarding no + AllowTcpForwarding no + X11Forwarding no + PermitTunnel no + PermitUserEnvironment no + + HostbasedAuthentication no + + Banner /etc/issue + PrintMotd yes + + # override default of no subsystems + Subsystem sftp /usr/lib/openssh/sftp-server + + Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 + + AllowUsers $ADMINUSER + EOF + + log_info " Setting login banner and motd" + cat <<-"EOF" > /etc/issue + UNAUTHORIZED ACCESS TO THIS DEVICE IS PROHIBITED + You must have explicit, authorized permission to access or configure this device. + Unauthorized attempts and actions to access or use this system may result in civil and/or + criminal penalties. + All activities performed on this device are logged and monitored. + EOF + cat <<-"EOF" > /etc/motd + Welcome! All activities performed on this device are logged and monitored. + EOF + chmod 444 /etc/issue /etc/motd + + + log_info " Regenerating ssh host keys" + find /etc/ssh/ -name "ssh_host_*" -exec rm {} + + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N "" + ssh-keygen -t ed25519 -b 4096 -f /etc/ssh/ssh_host_ed25519_key -N "" + + log_info " Removing small moduli for Diffie-Hellman" + awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe + mv /etc/ssh/moduli.safe /etc/ssh/moduli + + log_info " Setting permissions for ssh directory" + chown -R root:root /etc/ssh + chmod -R go-wx /etc/ssh + if [ -d "/usr/share/empty.sshd" ]; then + chown root:root /usr/share/empty.sshd + chmod go-wx /usr/share/empty.sshd + fi + + log_info " Restarting ssh" + systemctl restart sshd +fi + +# ------------------------------------------------------------------------------ +log_info "Updating packages for listening services" +processes=$(ss -lntup | cut -s -d"(" -f3 | cut -d'"' -f2 | sort -u) +printf "Processes:\n%s\n" "$processes" +if [ "$DISTRO" = "debian" ]; then + packages=$(for process in $processes ; do + ppath=$(realpath "$(command -v "$process")") >/dev/null + dpkg -S "$ppath" | cut -d: -f1 + done) + if printf "%s\n" "$packages" | grep -q "[[:graph:]]"; then + printf "Updating:\n%s\n" "$packages" + apt-get update + apt-get upgrade -y $packages + fi +elif [ "$DISTRO" = "fedora" ]; then + packages=$(for process in $processes ; do + ppath=$(command -v $process) >/dev/null + rpm -qf "$ppath" + done) + if printf "%s\n" "$packages" | grep -q "[[:graph:]]"; then + printf "Updating:\n%s\n" "$packages" + dnf update --color=never -y $packages + fi +fi + +# ------------------------------------------------------------------------------ +log_info "Configuring syslog" +if [ "$DISTRO" = "debian" ]; then + apt-get install -y rsyslog +elif [ "$DISTRO" = "fedora" ]; then + dnf install --color=never -y rsyslog +fi + +# Journald send to syslog +sed -i 's/^ForwardToSyslog.*/ForwardToSyslog=yes/' /etc/systemd/journald.conf +if ! grep -q "^ForwardToSyslog=yes" /etc/systemd/journald.conf ; then + printf "ForwardToSyslog=yes\n" >> /etc/systemd/journald.conf +fi + +systemctl enable --now rsyslog + +# ------------------------------------------------------------------------------ +log_info "Installing auditd" +if [ "$DISTRO" = "debian" ]; then + apt-get install -y auditd +elif [ "$DISTRO" = "fedora" ]; then + dnf install --color=never -y audit +fi +systemctl enable --now auditd +mkdir -p /etc/audit/audit.rules.d +cp ./configs/audit.rules /etc/audit/rules.d/audit.rules +auditctl -R /etc/audit/rules.d/audit.rules +service auditd reload +if [ "$DISTRO" = "debian" ]; then + systemctl restart auditd +elif [ "$DISTRO" = "fedora" ]; then + service auditd restart +fi + + +# ------------------------------------------------------------------------------ +log_info "Set new firewall rules to allow service access" +log_info " Firewall help text:" +printf "%s\n" "$(./firewall.sh -h | sed 's/^/ /')" + +log_info " Listening services:" +printf "%s\n" "$(ss -lntup | sed 's/^/ /')" + +log_info " Current rules:" +printf " -y d drop %s\n" "$rules" + +printf "\n %bEnter new rules (on one line, will be appended):\n " "$COLOR_BLUE" +read -r newrules +rules="$rules $newrules" +log_info " Applying new rules" +printf " ./firewall.sh -y -p -d drop %s\n" "$rules" +printf "%b" "$COLOR_NONE" +./firewall.sh -y -b -p -d drop $rules + +# ------------------------------------------------------------------------------ +log_info "Updating all packages" +if [ "$DISTRO" = "debian" ]; then + apt-get update + apt-get upgrade -y +elif [ "$DISTRO" = "fedora" ]; then + dnf update --color=never -y +fi + +# ------------------------------------------------------------------------------ +log_info "Disabling autofs" +systemctl disable autofs + +# ------------------------------------------------------------------------------ +usingsysctl=$(prompt_yn "Configure sysctl? - will probably break things") +if [ "$usingsysctl" = "y" ]; then + # ------------------------------------------------------------------------------ + log_info " Setting up kernel protection" + mkdir -p /etc/sysctl.conf.d + cat <<-"EOF" > /etc/sysctl.conf.d/kernel-protect.conf + kernel.kptr_restrict = 1 + kernel.dmesg_restrict = 1 + kernel.unprivileged_bpf_disabled = 1 + net.core.bpf_jit_harden = 2 + dev.tty.lsdisc_autoload = 0 + vm.unprivileged_userfaultfd = 0 + kernel.kexec_load_disabled = 1 + kernel.sysrq = 4 + vm.swappiness = 1 + EOF + + # ------------------------------------------------------------------------------ + log_info " Disabling uncommon kernel modules" + mkdir -p /etc/modprobe.d + cat <<-"EOF" > /etc/modprobe.d/blacklist.conf + # Uncommon networking protocols + install dccp /bin/false + install sctp /bin/false + install rds /bin/false + install tipc /bin/false + install n-hdlc /bin/false + install ax25 /bin/false + install netrom /bin/false + install x25 /bin/false + install rose /bin/false + install decnet /bin/false + install econet /bin/false + install af_802154 /bin/false + install ipx /bin/false + install appletalk /bin/false + install psnap /bin/false + install p8023 /bin/false + install p8022 /bin/false + install can /bin/false + install atm /bin/false + # Uncommon filesystems + install cramfs /bin/false + install freevxfs /bin/false + install jffs2 /bin/false + install hfs /bin/false + install hfsplus /bin/false + install squashfs /bin/false + install udf /bin/false + # Testing driver + install vivid /bin/false + # Bluetooth + install bluetooth /bin/false + install btusb /bin/false + EOF + + log_info " Regenerating initramfs" + if [ "$DISTRO" = "debian" ]; then + update-initramfs -u + elif [ "$DISTRO" = "fedora" ]; then + nohup dracut --regenerate-all --force & + log_info " initramfs generation will take a while. Backgrounded with pid $!" + fi + sleep 2 + + # ------------------------------------------------------------------------------ + log_info " Configuring network stack" + cat <<-"EOF" > /etc/sysctl.conf.d/network-stack.conf + net.ipv4.conf.all.arp_ignore = 1 + net.ipv4.conf.all.arp_announce = 1 + net.ipv4.conf.all.accept_redirects = 0 + net.ipv4.conf.all.accept_source_route = 0 + net.ipv4.conf.all.send_redirects = 0 + net.ipv4.conf.all.secure_redirects = 0 + net.ipv4.conf.all.log_martians = 1 + net.ipv4.conf.all.rp_filter = 1 + net.ipv4.conf.all.secure_redirects = 0 + net.ipv4.conf.default.accept_source_route = 0 + net.ipv4.conf.default.accept_redirects = 0 + net.ipv4.conf.default.accept_source_route = 0 + net.ipv4.conf.default.send_redirects = 0 + net.ipv4.conf.default.log_martians = 1 + net.ipv4.conf.default.rp_filter = 1 + net.ipv4.conf.default.secure_redirects = 0 + net.ipv4.icmp_echo_ignore_broadcasts = 0 + net.ipv4.icmp_ignore_bogus_error_responses = 1 + net.ipv4.icmp_ratelimit = 100 + net.ipv4.icmp_ratemask = 88089 + net.ipv4.tcp_fin_timeout = 30 + net.ipv4.tcp_syncookies = 1 + net.ipv4.tcp_timestamps = 0 + net.ipv4.tcp_rfc1337 = 1 + net.ipv4.tcp_sack = 0 + net.ipv4.tcp_dsack = 0 + net.ipv4.tcp_fack = 0 + net.ipv6.conf.all.accept_ra = 0 + net.ipv6.conf.all.accept_redirects = 0 + net.ipv6.conf.all.accept_source_route = 0 + net.ipv6.conf.default.accept_ra = 0 + net.ipv6.conf.default.accept_redirects = 0 + net.ipv6.conf.default.accept_source_route = 0 + EOF + + # ------------------------------------------------------------------------------ + log_info " Increasing limits" + cat <<-"EOF" > /etc/sysctl.conf.d/limits.conf + fs.file-max=100000 + EOF + + # ------------------------------------------------------------------------------ + log_info " Enabling user space protections" + printf "kernel.randomize_va_space = 2\n" > /etc/sysctl.conf.d/va_randomize.conf + cat <<-"EOF" > /etc/sysctl.conf.d/user-space.conf + kernel.yama.ptrace_scope = 2 + vm.mmap_rnd_bits = 32 + vm.mmap_rnd_compat_bits = 16 + fs.protected_symlinks = 1 + fs.protected_hardlinks = 1 + fs.protected_fifos = 2 + fs.protected_regular = 2 + EOF +fi + +# ------------------------------------------------------------------------------ +#log_info "Changing boot parameters" +# kernel protection: +# slab_nomerge init_on_alloc=1 init_on_free=1 page_alloc.shuffle=1 pti=on randomize_kstack_offset=on vsyscall=none debugfs=off module.sig_enforce=1 lockdown=confidentiality quiet loglevel=0 +# oops=panic +# CPU mitigations: +# spectre_v2=on spec_store_bypass_disable=on tsx=off tsx_async_abort=full,nosmt mds=full,nosmt l1tf=full,force nosmt=force kvm.nx_huge_pages=force +# Auditd: +# audit=1 +# Selinux: +# selinux=1 security=selinux enforcing=1 +# Protect against DMA: +# intel_iommu=on amd_iommu=on efi=disable_early_pci_dma + +# grub2-setpassword +# grub-mkconfig -o $path_to_grub_config +# update-grub +#log_error "Not yet implemented" + +# ------------------------------------------------------------------------------ +log_info "Hiding hardware info" +./hide-hardware.sh + +# ------------------------------------------------------------------------------ +log_info "Disabling services" +if [ -e "/etc/inetd.conf" -o -d "/etc/inetd.d" ]; then + inetd_services="chargen daytime echo time shell login exec talk ntalk telnet tftpd" + needinetd=$(prompt_yn " Do you need any of these inetd services?: $inetd_services") + if [ "$needinetd" = "y" ] && [ -e "/etc/inetd.conf" -o -d "/etc/inetd.d" ]; then + for service in $inetd_services; do + needservice=$(prompt_yn " Do you need $service?") + if [ "$needservice" = "n" ] ; then + printf "%b" "$COLOR_YELLOW" + find /etc/inetd.conf /etc/inetd.d -type f -exec sed -i "s/^\($service.*\)/#\1/" {} + + fi + done + else + for service in $inetd_services; do + find /etc/inetd.conf /etc/inetd.d -type f -exec sed -i "s/^\($service.*\)/#\1/" {} + + done + systemctl disable --now inetd + fi +fi + +possible_services="xinetd avahi-daemon cups dhcpd dnsmasq ldap nfs rpcbind named vsftpd httpd apache2 lighttpd nginx dovecot smb squid snmpd rsyncd ypserv" +for service in $possible_services ; do + if systemctl list-unit-files "${service}*" | grep -q "enabled" ; then + system_services="$system_services $service" + fi +done +needsystem=$(prompt_yn " Do you need any of these system services?: $system_services") +if [ "$needsystem" = "y" ]; then + for service in $system_services; do + needservice=$(prompt_yn " Do you need $service?") + if [ "$needservice" = "n" ]; then + printf "%b" "$COLOR_YELLOW" + for unit in $(systemctl list-unit-files "${service}*" | grep enabled | cut -d" " -f1); do + systemctl disable --now "$unit" + done + fi + done +else + for service in $system_services; do + systemctl disable --now "$service" + done +fi + +# ------------------------------------------------------------------------------ +log_info "Configuring Apache" +configureapache=$(prompt_yn "Configure apache?") +if [ "$configureapache" = "y" ]; then + if [ "$DISTRO" = "debian" ]; then + apacheowner="www-data" + apachegroup="www-data" + apachecmd="apache2" + apachedir="/etc/apache2" + elif [ "$DISTRO" = "fedora" ]; then + apacheowner="apache" + apachegroup="apache" + apachecmd="httpd" + apachedir="/etc/httpd" + fi + if ! command -v "$apachecmd" >/dev/null; then + log_error "Apache not found" + else + if [ "$(ps -U root | grep -qF "$apachecmd" | wc -l)" -gt 1 ] ; then + log_error "More than one root process running apache" + fi + log_info " Setting config dir permissions" + chown -R "root:${apachegroup}" "$apachedir" + find "$apachedir" -type d -exec chmod 750 {} + + find "$apachedir" -type f -exec chmod 640 {} + + + log_info " Setting server response" + find "$apachedir" -type f -exec sed -i 's/^ServerTokens.*/ServerTokens Prod/' {} + + find "$apachedir" -type f -exec sed -i 's/^ServerSignature.*/ServerSignature Off/' {} + + + log_info " Disabling trace requests" + find "$apachedir" -type f -exec sed -i 's/^TraceEnable.*/TraceEnable Off/' {} + + + log_info " Listing web root directories" + directoryfiles=$(find "$apachedir" -type f -exec grep -l "\"\n%b%s\n" "$COLOR_NONE" "$COLOR_YELLOW" "$(printf "%s" "$directoryfiles" | sed 's/^/ /')" + sections=$(for file in $directoryfiles ; do + output=0 + cat "$file" | while read -r line; do + line=$(printf "%s" "$line" | grep -v -e "^[[:blank:]]*$" -e "^[[:blank:]]*#") + if echo "$line" | grep -q "" -f1 | cut -d"<" -f2 | sed 's/"//g' | cut -d" " -f2-) + printf " %bWeb root directories\n%b%s\n" "$COLOR_NONE" "$COLOR_YELLOW" "$(printf "%s" "$apachewebdirs" | sed 's/^/ /')" + sleep 3 + + log_info " Listing files/directories that may be writable (or owned) by $apacheowner in web directories" + find $apachewebdirs ! -type l \( -user "$apacheowner" -o -group "$apachegroup" -o -perm -o+w \) -exec ls -ld {} + + + log_info " Listing .ht* files" + find $apachewebdirs -name ".ht*" -exec ls -ld {} + + + log_info " Installing mod-security with recommended configuration" + if [ "$DISTRO" = "debian" ]; then + apt-get install -y libapache2-mod-security2 modsecurity-crs + cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf + sed -i 's/^SecRuleEngine.*/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf + elif [ "$DISTRO" = "fedora" ]; then + dnf install --color=never -y mod_security mod_security_crs + cp /etc/httpd/conf.d/mod_security.conf /etc/httpd/conf.modules.d/00-mod_security.conf + sed -i 's/^SecRuleEngine.*/SecRuleEngine On/' /etc/httpd/conf.modules.d/00-mod_security.conf + fi + + sandboxapache=$(prompt_yn "Sandbox apache? - may break things") + if [ "$sandboxapache" = "y" ]; then + if [ "$DISTRO" = "debian" ]; then + exampleconf="profiles/apache2-override.conf" + apachesystemdconf="/etc/systemd/system/apache2.service.d/override.conf" + elif [ "$DISTRO" = "fedora" ]; then + exampleconf="profiles/httpd-override.conf" + apachesystemdconf="/etc/systemd/system/httpd.service.d/override.conf" + fi + + printf "%b Directories you may want to allow:\n%b%s\n" "$COLOR_NONE" "$COLOR_YELLOW" "$(printf "%s" "$apachewebdirs" | sed 's/^/ /')" + log_info " Editing systemd service override. Make sure all necessary directories are allowed. Press enter to start editing" + mkdir -p "$(dirname "$apachesystemdconf")" + cp "$exampleconf" "$apachesystemdconf" + read -r ignored + SERVICE="$apachecmd" ./sandbox.sh + systemctl daemon-reload + fi + + log_info " Restarting apache" + if ! systemctl restart "$apachecmd" ; then + systemctl status --no-pager "$apachecmd" + fi + fi +fi + +# ------------------------------------------------------------------------------ +log_info "Configuring Nginx" +configurenginx=$(prompt_yn "Configure nginx?") +if [ "$configurenginx" = "y" ]; then + if [ "$(ps -U root | grep -qF nginx | wc -l)" -gt 1 ] ; then + log_error "More than one root process running nginx" + fi + log_info " Setting config dir permissions" + find /etc/nginx -type d -exec chmod 750 {} + + find /etc/nginx -type f -exec chmod 640 {} + + + log_info " Setting server response" + log_error "Not yet implemented" + + log_info " Disabling trace requests" + log_error "Not yet implemented" + + log_info " Listing web root directories" + log_error "Not yet implemented" + + log_info " Installing mod-security with recommended configuration" + if [ "$DISTRO" = "debian" ]; then + if apt-get install -y libnginx-mod-http-modsecurity ; then + cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf + sed -i 's/^SecRuleEngine.*/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf + else + log_error "Couldn't install modsecurity for nginx" + fi + elif [ "$DISTRO" = "fedora" ]; then + if ! dnf install --color=never -y nginx-mod-modsecurity ; then + log_error "Couldn't install modsecurity for nginx" + fi + fi + + sandboxnginx=$(prompt_yn " Sandbox nginx? - may break things") + if [ "$sandboxnginx" = "y" ]; then + exampleconf="profiles/nginx-override.conf" + nginxsystemdconf="/etc/systemd/system/nginx.service.d/override.conf" + + printf "%b Directories you may want to allow:\n%b%s\n" "$COLOR_NONE" "$COLOR_YELLOW" "$(printf "%s" "$nginxwebdirs" | sed 's/^/ /')" + log_error "Not yet implemented" + log_info " Editing systemd service override. Make sure all necessary directories are allowed. Press enter to start editing" + mkdir -p "$(dirname "$nginxsystemdconf")" + cp "$exampleconf" "$nginxsystemdconf" + read -r ignored + SERVICE=nginx ./sandbox.sh + systemctl daemon-reload + fi + + log_info " Restarting nginx" + if ! systemctl restart nginx ; then + systemctl status --no-pager nginx + fi +fi + +# ------------------------------------------------------------------------------ +log_info "Installing usbguard" +if [ "$DISTRO" = "debian" ]; then + apt-get install -y usbguard +elif [ "$DISTRO" = "fedora" ]; then + dnf install --color=never -y usbguard +fi +log_info "Preparing usbguard rules. Plug in all needed usb devices, then press enter to continue" +read -r usbcontinue +usbguard generate-policy > /etc/usbguard/rules.conf +log_info "Enabling usbguard. To allow new usb devices, connect the device and run \"usbguard list-devices\", then \"usbguard allow-device \"" +systemctl enable --now usbguard + +# ------------------------------------------------------------------------------ +log_info "Installing aide" +if command -v prelink >/dev/null; then + prelink -ua; +fi +if [ "$DISTRO" = "debian" ]; then + apt-get remove -y prelink 2>/dev/null + apt-get install -y aide + aidepath="/usr/bin/aide" +elif [ "$DISTRO" = "fedora" ]; then + dnf remove --color=never -y prelink 2>/dev/null + dnf install --color=never -y aide + aidepath="/usr/sbin/aide" +fi + +cat <<-EOF > /etc/systemd/system/aidecheck.service +[Unit] +Description=Aide Check + +[Service] +Type=simple +ExecStart=$path --check --config /etc/aide/aide.conf + +[Install] +WantedBy=multi-user.targeaideinit +EOF + +cat <<-"EOF" > /etc/systemd/system/aidecheck.timer +[Unit] +Description=Aide check every hour + +[Timer] +OnCalendar=*:0 +Unit=aidecheck.service + +[Install] +WantedBy=multi-user.target +EOF +chmod 0644 /etc/systemd/system/aidecheck.* + +if [ ! -d /etc/aide -o ! -d /etc/aide/aide.conf ]; then + mkdir -p /etc/aide + cp ./configs/aide.conf /etc/aide/aide.conf + chown -R root:root /etc/aide + chmod -R 640 /etc/aide +fi + +log_info " Initializing aide (will take a while)" +if [ "$DISTRO" = "debian" ]; then + aideinit +elif [ "$DISTRO" = "fedora" ]; then + aide --init +fi +cp -p /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz + +systemctl enable --now aidecheck.timer +systemctl daemon-reload + +# ------------------------------------------------------------------------------ +printf "%b\n#############\nManual review\n#############\n%b" "$COLOR_BLUE" "$COLOR_NONE" +log_info "Verifying installed packages" +verifypackages=$(prompt_yn "Verify packages? This will take a while. Find the output in package-verify.txt.") +if [ "$verifypackages" = "y" ]; then + cat <<-"EOF" > package-verify.txt + # Verify Code Meaning + # S File size differs. + # M File mode differs (includes permissions and file type). + # 5 The MD5 checksum differs. + # D The major and minor version numbers differ on a device file. + # L A mismatch occurs in a link. + # U The file ownership differs. + # G The file group owner differs. + # T The file time (mtime) differs. + EOF + + if [ "$DISTRO" = "debian" ]; then + nohup dpkg --verify >> package-verify.txt & + elif [ "$DISTRO" = "fedora" ]; then + nohup rpm -Va --nomtime --nosize --nomd5 --nolinkto >> package-verify.txt & + fi +fi + +# ------------------------------------------------------------------------------ +log_info "Diffing current state with original state" +sleep 2 +ps -p $$ > info/shellpid-after +ps eaf --forest > info/processes-after +who -a > info/who-after +ss -ntup > info/outbound_connections-after +ss -lntup > info/inbound_connections-after +last -aFix > info/last-after +systemctl -l --all > info/systemctl_list-after +cat /etc/hosts > info/etc_hosts-after +for f in $(ls -1 info | cut -d- -f1 | sort -u); do + printf "%b%s%b\n" "$COLOR_YELLOW" "$f" "$COLOR_NONE" + diff --color "info/$f" "info/${f}-after" +done +sleep 5 + +log_info "Listing root processes" +sleep 2 +ps -fu root + +log_info "Listing world-writable files and directories" +find / -perm -o+w ! -path "/proc/*" ! -path "/dev/*" ! -path "/tmp*" ! -path "/var/tmp*" ! -type l -exec ls -l {} + 2>/dev/null + +log_info "Listing suid and sgid files" +gtfobins_suid="aa-exec ab agetty alpine ar arj arp as ascii-xfr ash aspell atobm awk base32 base64 basenc basez bash bc bridge busctl busybox bzip2 cabal capsh cat chmod choom chown chroot clamscan cmp column comm cp cpio cpulimit csh csplit csvtool cupsfilter curl cut dash date dd debugfs dialog diff dig distcc dmsetup docker dosbox ed efax elvish emacs env eqn espeak expand expect file find fish flock fmt fold gawk gcore gdb genie genisoimage gimp grep gtester gzip hd head hexdump highlight hping3 iconv install ionice ip ispell jjs join jq jrunscript julia ksh ksshell kubectl ld.so less logsave look lua make mawk minicom more mosquitto msgattrib msgcat msgconv msgfilter msgmerge msguniq multitime mv nasm nawk ncftp nft nice nl nm nmap node nohup ntpdate od openssl openvpn pandoc paste perf perl pexec pg php pidstat pr ptx python rc readelf restic rev rlwrap rsync rtorrent run-parts rview rvim sash scanmem sed setarch setfacl setlock shuf soelim softlimit sort sqlite3 ss ssh-agent ssh-keygen ssh-keyscan sshpass start-stop-daemon stdbuf strace strings sysctl systemctl tac tail taskset tbl tclsh tee terraform tftp tic time timeout troff ul unexpand uniq unshare unsquashfs unzip update-alternatives uudecode uuencode vagrant varnishncsa view vigr vim vimdiff vipw w3m watch wc wget whiptail xargs xdotool xmodmap xmore xxd xz yash zsh zsoelim" + +files_suid_sgid=$(find / -type f -perm -2000 -o -perm -4000 2>/dev/null) + +for bin in $files_suid_sgid; do + binname=$(basename "$bin") + for gtfobin in $gtfobins_suid; do + if [ "$binname" = "$gtfobin" ]; then + printf "%b%s%b\n" "$COLOR_RED" "$(ls -l "$bin")" "$COLOR_YELLOW" + continue 2 + fi + done + printf "%s\n" "$(ls -l "$bin")" +done + +printf "%b" "$COLOR_NONE" diff --git a/profiles/apache2-override.conf b/profiles/apache2-override.conf new file mode 100644 index 0000000..6e361f6 --- /dev/null +++ b/profiles/apache2-override.conf @@ -0,0 +1,108 @@ +[Service] + +# See "man 5 systemd.exec" for documentation about all of these options + +# To see what files a service needs access to, try running: +# strace -f -o apache2.strace -e trace=file /usr/sbin/apache2 +# cut -d'"' -f2 apache2.strace | sort | uniq -c +# systemctl restart apache2 || { journalctl -xeu apache2; systemctl status apache2; } + +# Or uncomment these lines to see the debug logs in journalctl +#SystemCallFilter=@debug +#BindReadOnlyPaths=/usr/bin/strace +#ExecStart= +#ExecStart=/usr/bin/strace -f /usr/sbin/apache2 + +# Restart service after 10 seconds if it fails for any reason +#Restart=on-failure +#RestartSec=10s + +# Mount / as read-only +PrivateDevices=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectSystem=strict + +# Limit executables that can be run (may need to add php,perl,etc) +TemporaryFileSystem=/bin +TemporaryFileSystem=/sbin +TemporaryFileSystem=/usr/bin +TemporaryFileSystem=/usr/sbin +BindReadOnlyPaths=-/usr/sbin/apache2 +BindReadOnlyPaths=-/usr/sbin/apache2ctl +BindReadOnlyPaths=-/usr/sbin/apachectl +# These are required for the apache2ctl script: +BindReadOnlyPaths=-/usr/bin/chmod +BindReadOnlyPaths=-/usr/bin/chown +BindReadOnlyPaths=-/usr/bin/id +BindReadOnlyPaths=-/usr/bin/mkdir +BindReadOnlyPaths=-/usr/bin/rmdir +BindReadOnlyPaths=-/usr/bin/mktemp +BindReadOnlyPaths=-/usr/bin/mv +BindReadOnlyPaths=-/usr/bin/rm +BindReadOnlyPaths=-/usr/bin/sh +CapabilityBoundingSet=CAP_CHOWN + +# Limited access to /etc +TemporaryFileSystem=/etc +BindReadOnlyPaths=-/etc/ca-certificates +BindReadOnlyPaths=-/etc/crypto-policies +BindReadOnlyPaths=-/etc/group +#BindReadOnlyPaths=-/etc/hostname +BindReadOnlyPaths=-/etc/apache2 +BindReadOnlyPaths=-/etc/modsecurity +BindReadOnlyPaths=-/etc/mime.types +BindReadOnlyPaths=-/etc/nsswitch.conf +BindReadOnlyPaths=-/etc/passwd +BindReadOnlyPaths=-/etc/pki +BindReadOnlyPaths=-/etc/ssl +TemporaryFileSystem=/etc/httpd/run/ + +# Allow access to web directories +BindReadOnlyPaths=/var/www + +# Allow logging +TemporaryFileSystem=/var +BindPaths=/var/log/apache2 + +# Give access to a lock directory +TemporaryFileSystem=/var/lock/apache2 + +# Prevent access to some paths +InaccessiblePaths=/boot +InaccessiblePaths=/media +InaccessiblePaths=/mnt +InaccessiblePaths=/usr/local + +# Prevent execution from temporary directories +PrivateTmp=true +NoExecPaths=/tmp /var/tmp + +# Allow binding ports 80 and 443 +CapabilityBoundingSet=CAP_NET_BIND_SERVICE # Commonly causes issues because this limits the types of actions the service can take. Check "man 7 capabilities" for a list +SocketBindAllow=tcp:443 +SocketBindAllow=tcp:80 +SocketBindDeny=any +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX +AmbientCapabilities= # Don't let child processes bind sockets + + +# Other protections + +MemoryDenyWriteExecute=yes +NoNewPrivileges=true + +ProtectClock=true +ProtectHome=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectProc=invisible + +RestrictNamespaces=true +RestrictSUIDSGID=true + +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@resources + +LockPersonality=yes diff --git a/profiles/generic-override.conf b/profiles/generic-override.conf new file mode 100644 index 0000000..7d8756a --- /dev/null +++ b/profiles/generic-override.conf @@ -0,0 +1,93 @@ +[Service] + +# ------------------------------------------------------------------------------ + +# See "man 5 systemd.exec" for documentation about all of these options +# Also see +# - https://www.ctrl.blog/entry/systemd-opensmtpd-hardening.html +# - https://www.sherbers.de/use-temporaryfilesystem-to-hide-files-or-directories-from-systemd-services/ + +# To see what files a service needs access to, try running: +# strace -f -o generic_service.strace -e trace=file generic_service +# cut -d'"' -f2 generic_service.strace | sort -u + +# Or see the access in journalctl by prepending "/usr/bin/strace -e trace=%%file" to the ExecStart line +#ExecStart= +#ExecStart=/usr/bin/strace /usr/sbin/generic_service + +# Uncomment lines as needed, then restart the service and make sure everything still works + +# ------------------------------------------------------------------------------ + +# Restart service after 10 seconds if it fails for any reason +#Restart=on-failure +#RestartSec=10s + +# Mount / as read-only +#PrivateDevices=true +#ProtectControlGroups=true +#ProtectKernelTunables=true +#ProtectSystem=strict + +# Only show files that have been explicitly bound with BindPaths or BindReadOnlyPaths +#TemporaryFileSystem=/ + +# Limit executables that can be run (may need to add php,perl,etc) +#TemporaryFileSystem=/bin +#TemporaryFileSystem=/sbin +#TemporaryFileSystem=/usr/bin +#TemporaryFileSystem=/usr/sbin +#BindReadOnlyPaths=/usr/sbin/generic_service + +# Usually necessary for services to start +#BindReadOnlyPaths=/lib/ /lib64/ /usr/lib/ /usr/lib64/ /etc/ld.so.cache /etc/ld.so.conf /etc/ld.so.conf.d/ /usr/share/zoneinfo/ /usr/share/locale/ /etc/localtime /usr/share/common-licenses/ /etc/ssl/certs/ /etc/alternatives/ +#BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout /run/systemd/notify + +# Limited access to /etc +#TemporaryFileSystem=/etc +#BindReadOnlyPaths=-/etc/generic_service_dir + +# Allow logging +#TemporaryFileSystem=/var +#BindPaths=/var/log/generic_service_dir + +# Prevent access to some paths +#InaccessiblePaths=/boot +#InaccessiblePaths=/media +#InaccessiblePaths=/mnt + +# Prevent execution from temporary directories +#PrivateTmp=true +#NoExecPaths=/tmp /var/tmp + +# Allow binding some ports +#CapabilityBoundingSet=CAP_NET_BIND_SERVICE # Commonly causes issues because this limits the types of actions the service can take. Check "man 7 capabilities" for a list +#SocketBindAllow=tcp:1337 +#SocketBindDeny=any +#RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX + + +# Other protections + +# May need to change system calls +#SystemCallArchitectures=native +#SystemCallFilter=@system-service +#SystemCallFilter=~@resources + +#MemoryDenyWriteExecute=yes +#NoNewPrivileges=true + +#ProtectClock=true +#ProtectHome=true +#ProtectKernelLogs=true +#ProtectKernelModules=true +#ProtectProc=invisible + +#RestrictNamespaces=true +#RestrictSUIDSGID=true + + +#LockPersonality=yes + +# End of generic_service override +# ------------------------------------------------------------------------------ diff --git a/profiles/httpd-override.conf b/profiles/httpd-override.conf new file mode 100644 index 0000000..3b14938 --- /dev/null +++ b/profiles/httpd-override.conf @@ -0,0 +1,93 @@ +[Service] + +# See "man 5 systemd.exec" for documentation about all of these options + +# To see what files a service needs access to, try running: +# strace -f -o httpd.strace -e trace=file /usr/sbin/httpd +# cut -d'"' -f2 httpd.strace | sort | uniq -c +# systemctl restart httpd || { journalctl -xeu httpd; systemctl status httpd; } + +# Or uncomment these lines to see the debug logs in journalctl +#SystemCallFilter=@debug +#BindReadOnlyPaths=/usr/bin/strace +#ExecStart= +#ExecStart=/usr/bin/strace -f /usr/sbin/httpd + +# Restart service after 10 seconds if it fails for any reason +#Restart=on-failure +#RestartSec=10s + +# Mount / as read-only +PrivateDevices=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectSystem=strict + +# Limit executables that can be run (may need to add php,perl,etc) +TemporaryFileSystem=/bin +TemporaryFileSystem=/sbin +TemporaryFileSystem=/usr/bin +TemporaryFileSystem=/usr/sbin +BindReadOnlyPaths=-/usr/sbin/httpd +BindReadOnlyPaths=-/usr/sbin/suexec + +# Limited access to /etc +TemporaryFileSystem=/etc +BindReadOnlyPaths=-/etc/ca-certificates +BindReadOnlyPaths=-/etc/crypto-policies +BindReadOnlyPaths=-/etc/group +#BindReadOnlyPaths=-/etc/hostname +BindReadOnlyPaths=-/etc/httpd +BindReadOnlyPaths=-/etc/mime.types +BindReadOnlyPaths=-/etc/nsswitch.conf +BindReadOnlyPaths=-/etc/passwd +BindReadOnlyPaths=-/etc/pki +BindReadOnlyPaths=-/etc/ssl +TemporaryFileSystem=/etc/httpd/run/ # Can cause issues. Try commenting out or replacing with BindPaths=-/etc/httpd/run/ + +# Allow access to web directories +BindReadOnlyPaths=/var/www + +# Allow logging +TemporaryFileSystem=/var +BindPaths=/var/log/httpd + +# Prevent access to some paths +InaccessiblePaths=/boot +InaccessiblePaths=/media +InaccessiblePaths=/mnt +InaccessiblePaths=/run/media +InaccessiblePaths=/usr/local + +# Prevent execution from temporary directories +PrivateTmp=true +NoExecPaths=/tmp /var/tmp + +# Allow binding ports 80 and 443 +CapabilityBoundingSet=CAP_NET_BIND_SERVICE # Commonly causes issues because this limits the types of actions the service can take. Check "man 7 capabilities" for a list +SocketBindAllow=tcp:443 +SocketBindAllow=tcp:80 +SocketBindDeny=any +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX +AmbientCapabilities= # Don't let child processes bind sockets + + +# Other protections + +MemoryDenyWriteExecute=yes +#NoNewPrivileges=true # This is useful, but may cause the service to fail to start + +ProtectClock=true +ProtectHome=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectProc=invisible + +RestrictNamespaces=true +RestrictSUIDSGID=true + +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@resources + +LockPersonality=yes diff --git a/profiles/nginx-override.conf b/profiles/nginx-override.conf new file mode 100644 index 0000000..8094b8f --- /dev/null +++ b/profiles/nginx-override.conf @@ -0,0 +1,105 @@ +[Service] + +# See "man 5 systemd.exec" for documentation about all of these options + +# To see what files a service needs access to, try running: +# strace -f -o nginx.strace -e trace=file /usr/sbin/nginx +# cut -d'"' -f2 nginx.strace | sort | uniq -c +# systemctl restart nginx || { journalctl -xeu nginx; systemctl status nginx; } + +# Or uncomment these lines to see the debug logs in journalctl +#SystemCallFilter=@debug +#BindReadOnlyPaths=/usr/bin/strace +#ExecStart= +#ExecStart=/usr/bin/strace -f /usr/sbin/nginx + +# Restart service after 10 seconds if it fails for any reason +#Restart=on-failure +#RestartSec=10s + +## Mount / as read-only +PrivateDevices=true +ProtectControlGroups=true +ProtectKernelTunables=true +ProtectSystem=strict + +ProtectHome=tmpfs + +# Allow access to web directories +#BindReadOnlyPaths=/var/www +BindReadOnlyPaths=/usr + +# Limit executables that can be run (may need to add php,perl,etc) +TemporaryFileSystem=/bin +TemporaryFileSystem=/sbin +TemporaryFileSystem=/usr/bin +TemporaryFileSystem=/usr/sbin +BindReadOnlyPaths=/usr/sbin/nginx +BindReadOnlyPaths=/usr/bin/rm + +# Commonly needed for services to start +BindReadOnlyPaths=/lib/ /lib64/ /usr/lib/ /usr/lib64/ /usr/share/zoneinfo/ /usr/share/locale/ /etc/localtime /etc/ssl/certs/ /etc/alternatives/ +#BindReadOnlyPaths=/etc/ld.so.cache /etc/ld.so.conf /etc/ld.so.conf.d/ /etc/bindresvport.blacklist +#BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout /run/systemd/notify + +# Allow access to {/var/cache,/etc,/var/log,/run,/var/lib}/nginx +CacheDirectory=nginx +ConfigurationDirectory=nginx +LogsDirectory=nginx +RuntimeDirectory=nginx +StateDirectory=nginx +TemporaryFileSystem=/var/lib/nginx/tmp +BindReadOnlyPaths=/usr/share/nginx + +# Limited access to /etc +TemporaryFileSystem=/etc +BindReadOnlyPaths=-/etc/group +BindReadOnlyPaths=-/etc/localtime +BindReadOnlyPaths=-/etc/nsswitch.conf +BindReadOnlyPaths=-/etc/passwd +BindReadOnlyPaths=-/etc/pki/ +BindReadOnlyPaths=-/etc/ssl/ +BindReadOnlyPaths=-/etc/selinux/config +BindReadOnlyPaths=-/etc/system-fips +BindReadOnlyPaths=-/etc/crypto-policies + +# Prevent access to most things in /var +TemporaryFileSystem=/var + +# Prevent access to some paths +InaccessiblePaths=/boot +InaccessiblePaths=/media +InaccessiblePaths=/mnt + +# Prevent execution from temporary directories +PrivateTmp=true +NoExecPaths=/tmp /var/tmp + +# Allow binding ports +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN CAP_SETGID CAP_SETUID # Commonly causes issues because this limits the types of actions the service can take. Check "man 7 capabilities" for a list +SocketBindAllow=tcp:80 tcp:443 +SocketBindDeny=any +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX + + +# Other protections + +# May need to change system calls +SystemCallArchitectures=native +SystemCallFilter=@system-service @chown +SystemCallFilter=~@resources + +MemoryDenyWriteExecute=yes +#NoNewPrivileges=true + +ProtectClock=true +ProtectHome=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectProc=invisible + +RestrictNamespaces=true +RestrictSUIDSGID=true + +LockPersonality=yes diff --git a/sandbox.sh b/sandbox.sh new file mode 100755 index 0000000..fcfac17 --- /dev/null +++ b/sandbox.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# Use systemd sandboxing to harden services. Prompts for making changes if the +# service fails after sandboxing + +if [ "$(/usr/bin/id -u)" -ne 0 ]; then + printf "Must run as root\n" >&2 + exit 1 +fi + +if [ -z "$SERVICE" ]; then + printf "What service do you want to sandbox?: " + read -r SERVICE +fi + +if systemctl list-unit-files "${SERVICE}.service" | grep "^0 unit files listed"; then + printf "Service not found\n" + exit 1 +fi + +prompt_yn() { + printf "%s [y/N]\n" "$1" >&2 + read -r promptmessage + case "$promptmessage" in + [yY]|[yY][eE][sS]) + printf "y" + ;; + *) + printf "n" + ;; + esac +} + +OVERRIDE_DIR="/etc/systemd/system/${SERVICE}.service.d" +OVERRIDE_CONF="/etc/systemd/system/${SERVICE}.service.d/override.conf" + +if ! [ -e "$OVERRIDE_CONF" ]; then + mkdir -p "$OVERRIDE_DIR" + cp "profiles/generic-override.conf" "$OVERRIDE_CONF" +fi + +while true; do + systemctl edit "$SERVICE" || exit 1 + restartservice=$(prompt_yn "Restart $SERVICE to test new sandbox config?") + if [ "$restartservice" = "y" ]; then + printf "Restarting service...\n" + systemctl restart "$SERVICE" || { journalctl -xeu "$SERVICE"; systemctl status "$SERVICE"; } + if [ $? = 0 ]; then + viewjournal=$(prompt_yn "$SERVICE successfully started (but could have failed after starting). View journalctl output?") + if [ "$viewjournal" = "y" ]; then + sleep 2 + journalctl -xeu "$SERVICE" + fi + keepediting=$(prompt_yn "Keep editing the sandbox config?") + if [ "$keepediting" = "y" ]; then + continue + else + break + fi + else + keepediting=$(prompt_yn "Keep editing the sandbox config? Consider commenting everything out first, then adding restrictions.") + if [ "$keepediting" = "y" ]; then + continue + else + cancel=$(prompt_yn "Delete the sanbox config?") + if [ "$cancel" = "y" ]; then + rm -i $(systemctl cat "$SERVICE" | grep override.conf | cut -d" " -f2) + else + break + fi + fi + fi + else + printf "Not restarting...\n" + break + fi +done -- 2.39.5