454 lines
16 KiB
Bash
454 lines
16 KiB
Bash
#!/bin/bash
|
|
|
|
# [STRG-1846] Disable drivers like firewire
|
|
sudo tee /etc/modprobe.d/firewire-disable.conf > /dev/null <<EOL
|
|
# Disable FireWire kernel modules to prevent unauthorized DMA access
|
|
blacklist firewire-core
|
|
install firewire-core /bin/false
|
|
# Optional additional modules to blacklist
|
|
blacklist firewire-ohci
|
|
blacklist firewire-sbp2
|
|
install firewire-ohci /bin/false
|
|
install firewire-sbp2 /bin/false
|
|
EOL
|
|
|
|
# [LOGG-2154] Ensure system log is configured to send logs to a remote log server
|
|
sudo pacman -S --noconfirm --needed syslog-ng
|
|
sudo systemctl enable --now syslog-ng@default.service
|
|
|
|
# [NETW-2706] Ensure DNSSEC validation is enabled
|
|
echo 'DNSSEC=yes' | sudo tee -a /etc/systemd/resolved.conf > /dev/null
|
|
sudo systemctl restart systemd-resolved
|
|
|
|
# [USB-3000] Ensure USBGUARD is installed and configured
|
|
sudo pacman -S --noconfirm --needed usbguard
|
|
sudo usbguard generate-policy | sudo tee /etc/usbguard/rules.conf > /dev/null
|
|
sudo sed -i 's/^PresentControllerPolicy=.*/PresentControllerPolicy=apply-policy/' /etc/usbguard/usbguard-daemon.conf
|
|
sudo systemctl enable --now usbguard
|
|
|
|
# [NETW-3032] Checking for ARP monitoring software
|
|
sudo pacman -S --noconfirm --needed arpwatch
|
|
# Find first non-loopback, non-virbr/vmbr interface and enable arpwatch on it
|
|
iface=$(ip -o link show | awk -F': ' '{print $2}' | sed 's/@.*$//' | grep -Ev '^(lo|virbr|vmbr)' | head -n1)
|
|
if [ -n "$iface" ]; then
|
|
sudo systemctl enable --now "arpwatch@${iface}.service"
|
|
else
|
|
echo "No suitable network interface found for arpwatch; service not enabled." >&2
|
|
fi
|
|
|
|
# [NETW-3200] Disable unused network protocols
|
|
sudo tee /etc/modprobe.d/network-protocols-disable.conf > /dev/null <<EOL
|
|
# Disable unnecessary network protocols to reduce attack surface
|
|
blacklist dccp
|
|
install dccp /bin/false
|
|
|
|
blacklist sctp
|
|
install sctp /bin/false
|
|
|
|
blacklist rds
|
|
install rds /bin/false
|
|
|
|
blacklist tipc
|
|
install tipc /bin/false
|
|
EOL
|
|
|
|
# [MALW-3276] Ensure rkhunter is installed
|
|
sudo pacman -S --noconfirm --needed rkhunter
|
|
sudo rkhunter --propupd
|
|
sudo tee /etc/rkhunter.conf > /dev/null <<EOL
|
|
# rkhunter configuration file
|
|
|
|
# Whitelist to avoid false positive
|
|
SCRIPTWHITELIST=/usr/bin/egrep
|
|
SCRIPTWHITELIST=/usr/bin/fgrep
|
|
SCRIPTWHITELIST=/usr/bin/ldd
|
|
SCRIPTWHITELIST=/usr/bin/vendor_perl/GET
|
|
EOL
|
|
|
|
# [MALW-3282] Ensure ClamAV is installed
|
|
sudo pacman -S --noconfirm --needed clamav
|
|
sudo freshclam
|
|
sudo systemctl enable --now clamav-freshclam
|
|
sleep 5
|
|
sudo systemctl enable --now clamav-daemon
|
|
|
|
# [FINT-4350] Install a file integrity tool
|
|
sudo pacman -S --noconfirm --needed aide
|
|
sudo aide --init
|
|
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
|
|
sudo systemctl enable --now aidecheck.timer
|
|
|
|
# [FIRE-45XX] Firewall configuration
|
|
# remove iptables if installed
|
|
if pacman -Qi iptables &> /dev/null; then
|
|
sudo pacman -R --noconfirm iptables
|
|
fi
|
|
sudo pacman -S --noconfirm --needed nftables
|
|
|
|
sudo tee /etc/modprobe.d/ip_tables-disable.conf > /dev/null <<EOL
|
|
# Disable ip_tables to prevent conflicts with nftables
|
|
blacklist ip_tables
|
|
install ip_tables /bin/false
|
|
EOL
|
|
|
|
# [TOOL-5190] Ensure IDS/IPS tools are installed
|
|
sudo pacman -S --noconfirm --needed snort
|
|
sudo systemctl enable --now snort
|
|
|
|
# [KRNL-5820] Disable core dumps
|
|
|
|
# Disable coredump handling in systemd's coredump configuration and mask units
|
|
sudo mkdir -p /etc/systemd/coredump.conf.d
|
|
sudo tee /etc/systemd/coredump.conf.d/99-disable-coredumps.conf > /dev/null <<'EOL'
|
|
[Coredump]
|
|
# Prevent any core file data being stored and limit accepted size to 0
|
|
ProcessSizeMax=0
|
|
Storage=none
|
|
EOL
|
|
sudo systemctl daemon-reload
|
|
|
|
sudo mkdir -p /etc/security/limits.d/
|
|
sudo tee /etc/security/limits.d/20-disable-core-dumps.conf > /dev/null <<EOL
|
|
# Disable core dumps for ALL users
|
|
# The format is: <domain> <type> <item> <value>
|
|
* hard core 0
|
|
* soft core 0
|
|
EOL
|
|
# Append to /etc/profile to enforce core dump restriction system-wide
|
|
echo '# Disable core dumps system-wide' | sudo tee -a /etc/profile > /dev/null
|
|
echo 'ulimit -c 0 > /dev/null 2>&1' | sudo tee -a /etc/profile > /dev/null
|
|
echo '# Set the core dump soft limit to 0 (current enforceable limit)' | sudo tee -a /etc/profile > /dev/null
|
|
echo 'ulimit -S -c 0 > /dev/null 2>&1' | sudo tee -a /etc/profile > /dev/null
|
|
echo '# Set the hard limit to 0 (absolute maximum limit)' | sudo tee -a /etc/profile > /dev/null
|
|
echo 'ulimit -H -c 0 > /dev/null 2>&1' | sudo tee -a /etc/profile > /dev/null
|
|
|
|
# [KRNL-6000] Check sysctl settings for kernel hardening
|
|
sudo tee /etc/sysctl.d/99-hardened.conf > /dev/null <<'EOL'
|
|
# Kernel and filesystem hardening settings
|
|
kernel.randomize_va_space = 2
|
|
kernel.kptr_restrict = 2
|
|
kernel.unprivileged_bpf_disabled = 1
|
|
#kernel.modules_disabled = 1 # Uncomment to disable module loading entirely at your own risk
|
|
kernel.sysrq = 0
|
|
kernel.core_uses_pid = 1
|
|
|
|
fs.suid_dumpable = 0
|
|
fs.protected_fifos = 2
|
|
fs.protected_hardlinks = 1
|
|
fs.protected_regular = 2
|
|
fs.protected_symlinks = 1
|
|
|
|
dev.tty.ldisc_autoload = 0
|
|
|
|
net.core.bpf_jit_harden = 2
|
|
|
|
net.ipv4.conf.all.forwarding = 0
|
|
net.ipv4.conf.all.accept_redirects = 0
|
|
net.ipv4.conf.all.send_redirects = 0
|
|
net.ipv4.conf.all.log_martians = 1
|
|
net.ipv4.conf.all.rp_filter = 1
|
|
|
|
net.ipv4.conf.default.accept_redirects = 0
|
|
net.ipv4.conf.default.log_martians = 1
|
|
|
|
net.ipv6.conf.all.accept_redirects = 0
|
|
net.ipv6.conf.default.accept_redirects = 0
|
|
EOL
|
|
|
|
sudo sysctl --system
|
|
|
|
# [SHLL-6220] Idle session handling
|
|
echo 'TMOUT=900' | sudo tee -a /etc/profile > /dev/null
|
|
echo 'readonly TMOUT' | sudo tee -a /etc/profile > /dev/null
|
|
echo 'export TMOUT' | sudo tee -a /etc/profile > /dev/null
|
|
|
|
# [MACF-6290] Enable MAC framework (AppArmor)
|
|
sudo pacman -S --noconfirm --needed apparmor apparmor.d-git
|
|
sudo systemctl enable --now apparmor
|
|
|
|
# [FILE-6344] Restricting process details to users
|
|
## Editing fstab
|
|
if ! grep -q '^proc\s\+/proc\s\+proc\s\+' /etc/fstab; then
|
|
echo '# /proc' | sudo tee -a /etc/fstab > /dev/null
|
|
echo 'proc /proc proc defaults,hidepid=2,gid=wheel 0 0' | sudo tee -a /etc/fstab > /dev/null
|
|
else
|
|
sudo sed -i 's|^proc[[:space:]]\+/proc[[:space:]]\+proc[[:space:]]\+.*$|proc /proc proc defaults,hidepid=1,gid=wheel 0 0|' /etc/fstab
|
|
fi
|
|
## Remount /proc to apply changes immediately
|
|
sudo systemctl daemon-reload
|
|
sudo mount -o remount /proc
|
|
|
|
# [FILE-6374] Check mount options
|
|
# if /dev/shm is not in /etc/fstab, add it with the correct options
|
|
if ! grep -q '^tmpfs\s\+/dev/shm\s\+tmpfs\s\+' /etc/fstab; then
|
|
echo '# /dev/shm' | sudo tee -a /etc/fstab > /dev/null
|
|
echo 'tmpfs /dev/shm tmpfs rw,nosuid,nodev,noexec 0 0' | sudo tee -a /etc/fstab > /dev/null
|
|
else
|
|
sudo sed -i 's|^tmpfs[[:space:]]\+/dev/shm[[:space:]]\+tmpfs[[:space:]]\+.*$|tmpfs /dev/shm tmpfs rw,nosuid,nodev,noexec 0 0|' /etc/fstab
|
|
fi
|
|
# Remount /dev/shm to apply changes immediately
|
|
sudo systemctl daemon-reload
|
|
sudo mount -o remount /dev/shm
|
|
|
|
# Replace /tmp mount
|
|
if ! grep -q '^tmpfs\s\+/tmp\s\+tmpfs\s\+' /etc/fstab; then
|
|
echo '# /tmp' | sudo tee -a /etc/fstab > /dev/null
|
|
echo 'tmpfs /tmp tmpfs rw,nosuid,nodev,noexec 0 0' | sudo tee -a /etc/fstab > /dev/null
|
|
else
|
|
sudo sed -i 's|^tmpfs[[:space:]]\+/tmp[[:space:]]\+tmpfs[[:space:]]\+.*$|tmpfs /tmp tmpfs rw,nosuid,nodev,noexec 0 0|' /etc/fstab
|
|
fi
|
|
# Remount /tmp to apply changes immediately
|
|
sudo systemctl daemon-reload
|
|
sudo mount -o remount /tmp
|
|
|
|
# [FILE-6430] Disable mounting of some filesystems
|
|
sudo tee /etc/modprobe.d/fs_blacklist.conf > /dev/null <<EOL
|
|
# Blacklist unnecessary filesystem modules to reduce attack surface
|
|
|
|
# Cramfs (Compressed ROM filesystem)
|
|
blacklist cramfs
|
|
install cramfs /bin/false
|
|
|
|
# HFS and HFS+ (Apple filesystems)
|
|
blacklist hfs
|
|
install hfs /bin/false
|
|
|
|
blacklist hfsplus
|
|
install hfsplus /bin/false
|
|
|
|
# JFFS2 (Journaling Flash Filesystem)
|
|
blacklist jffs2
|
|
install jffs2 /bin/false
|
|
|
|
# SquashFS (Compressed read-only filesystem, often used for live media/AppImage)
|
|
blacklist squashfs
|
|
install squashfs /bin/false
|
|
|
|
# UDF (Universal Disk Format, used for optical media like DVD/BD)
|
|
blacklist udf
|
|
install udf /bin/false
|
|
EOL
|
|
|
|
# [BANN-7126] Add legal banner to /etc/issue
|
|
sudo tee /etc/issue > /dev/null <<EOL
|
|
********************************************************************
|
|
* WARNING - UNAUTHORIZED ACCESS *
|
|
* *
|
|
* Unauthorized access to this computer system is strictly *
|
|
* prohibited. Individuals accessing, using, or modifying this *
|
|
* system without explicit authorization will be subject to legal *
|
|
* action and prosecuted to the fullest extent of the law. *
|
|
* *
|
|
* Authorized users should have no expectation of privacy. All *
|
|
* activity on this system is monitored, recorded, and may be used *
|
|
* as evidence in criminal or civil proceedings. *
|
|
********************************************************************
|
|
\n - \l
|
|
EOL
|
|
|
|
# [HRDN-7220] Don't install /usr/bin/as by adding it to NoExtract
|
|
if sudo grep -q 'usr/bin/as' /etc/pacman.conf; then
|
|
: # already present
|
|
else
|
|
if sudo grep -qE '^[[:space:]]*NoExtract' /etc/pacman.conf; then
|
|
sudo sed -i '0,/^[[:space:]]*NoExtract/ s|^\([[:space:]]*NoExtract[[:space:]]*=[[:space:]]*\)\(.*\)$|\1\2 usr/bin/as|' /etc/pacman.conf
|
|
elif sudo grep -qE '^[[:space:]]*#[[:space:]]*NoExtract' /etc/pacman.conf; then
|
|
sudo sed -i '/^[[:space:]]*#[[:space:]]*NoExtract/ a NoExtract = usr/bin/as' /etc/pacman.conf
|
|
else
|
|
sudo bash -c 'printf "\n# NoExtract added by hardening script\nNoExtract = usr/bin/as\n" >> /etc/pacman.conf'
|
|
fi
|
|
fi
|
|
|
|
# [HRDN-7222] Restricting compilator access to root user only
|
|
sudo chown 700 /usr/bin/as
|
|
sudo chmod 700 /usr/bin/gcc
|
|
sudo chmod 700 /usr/bin/g++
|
|
sudo chmod 700 /usr/bin/cc
|
|
sudo chmod 700 /usr/bin/c++
|
|
sudo chmod 700 /usr/bin/ld
|
|
sudo chmod 700 /usr/bin/lld
|
|
sudo chmod 700 /usr/bin/clang
|
|
|
|
# [PKGS-7320] Checking for package auditing tools
|
|
sudo pacman -S --noconfirm --needed arch-audit
|
|
|
|
# [FILE-7524] Ensuring file permissions
|
|
sudo chmod 600 /etc/ssh/sshd_config
|
|
sudo chmod 700 /etc/cron.hourly
|
|
|
|
# [CRYP-8004] Presence of hardware random number generator
|
|
sudo pacman -S --noconfirm --needed rng-tools
|
|
sudo systemctl enable --now rngd
|
|
|
|
# [CRYP-8005] Presence of software pseudo random number generator
|
|
sudo pacman -S --noconfirm --needed haveged
|
|
sudo systemctl enable --now haveged
|
|
|
|
# [CRYP-8006] Ensure MemoryOverwriteRequest-bit set
|
|
sudo tee /usr/lib/systemd/system-shutdown/mor-bit-wipe.sh > /dev/null <<'EOL'
|
|
#!/bin/bash
|
|
|
|
# Path to the MemoryOverwriteRequestControl UEFI variable
|
|
MOR_VAR_PATH="/sys/firmware/efi/efivars/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829"
|
|
|
|
# Check if the UEFI variable path exists
|
|
if [ -e "$MOR_VAR_PATH" ]; then
|
|
# The expected format is: Attributes (4 bytes) + Value (1 byte for MOR state)
|
|
# We need to write 5 bytes in total: 0x07 0x00 0x00 0x00 (Attributes) + 0x01 (MOR-bit set)
|
|
|
|
# Use printf to create the necessary 5-byte data and write it to the variable
|
|
# 0x01 means MOR is SET (request memory wipe)
|
|
printf "\x07\x00\x00\x00\x01" | dd of="$MOR_VAR_PATH" bs=5 count=1 conv=notrunc >/dev/null 2>&1
|
|
|
|
# Log the action (optional, for debugging/audit logs)
|
|
echo "$(date) - Successfully set MOR-bit (MemoryOverwriteRequestControl) for next boot memory wipe." >> /var/log/mor-wipe.log
|
|
fi
|
|
|
|
exit 0
|
|
EOL
|
|
sudo chmod +x /usr/lib/systemd/system-shutdown/mor-bit-wipe.sh
|
|
|
|
# [AUTH-9230] Ensure password hashing algorithm is set to YESCRYPT and hashing rounds to minimum of 5000 and maximum of 5000000
|
|
sudo sed -i 's/^ENCRYPT_METHOD .*/ENCRYPT_METHOD YESCRYPT/' /etc/login.defs
|
|
sudo sed -i 's/^#SHA_CRYPT_MIN_ROUNDS .*/SHA_CRYPT_MIN_ROUNDS 5000/' /etc/login.defs
|
|
sudo sed -i 's/^#SHA_CRYPT_MAX_ROUNDS .*/SHA_CRYPT_MAX_ROUNDS 5000000/' /etc/login.defs
|
|
|
|
# [AUTH-9262] Password strength checking tool is installed
|
|
sudo pacman -S --noconfirm --needed libpwquality
|
|
sudo tee /etc/security/pwquality.conf > /dev/null <<EOL
|
|
# PAM pwquality configuration file
|
|
retry = 3
|
|
difok = 6
|
|
minlen = 14
|
|
dcredit = -1
|
|
ucredit = -1
|
|
ocredit = -1
|
|
lcredit = -1
|
|
EOL
|
|
|
|
sudo sed -i '/^password\s*required\s*pam_unix.so\s*try_first_pass\s*nullok\s*shadow/i password required pam_pwquality.so' /etc/pam.d/system-auth
|
|
|
|
# [AUTH-9286] Ensure minimum days between password changes is 7 or more and maximum days is 90 or less
|
|
sudo sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 7/' /etc/login.defs
|
|
sudo sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs
|
|
|
|
# [AUTH-9328] Ensure default user umask is 027 or more restrictive
|
|
sudo sed -i 's/^UMASK.*/UMASK 027/' /etc/login.defs
|
|
if sudo grep -qE '^[[:space:]]*#?[[:space:]]*umask' /etc/bash.bashrc; then
|
|
sudo sed -i 's/^[[:space:]]*#\?[[:space:]]*umask.*/umask 027/' /etc/bash.bashrc
|
|
else
|
|
echo 'umask 027' | sudo tee -a /etc/bash.bashrc > /dev/null
|
|
fi
|
|
if sudo grep -qE '^[[:space:]]*#?[[:space:]]*umask' /etc/profile; then
|
|
sudo sed -i 's/^[[:space:]]*#\?[[:space:]]*umask.*/umask 027/' /etc/profile
|
|
else
|
|
echo 'umask 027' | sudo tee -a /etc/profile > /dev/null
|
|
fi
|
|
|
|
# [AUTH-9408] Logging of failed login attempts is enabled
|
|
if sudo grep FAILLOG_ENAB /etc/login.defs; then
|
|
sudo sed -i 's/^FAILLOG_ENAB .*/FAILLOG_ENAB yes/' /etc/login.defs
|
|
else
|
|
echo 'FAILLOG_ENAB yes' | sudo tee -a /etc/login.defs > /dev/null
|
|
fi
|
|
|
|
# [ACCT-9622] Enable process accounting
|
|
sudo pacman -S --noconfirm --needed acct
|
|
sudo systemctl enable --now acct
|
|
|
|
# [ACCT-9626] Enable sysstat to collect accounting data
|
|
sudo pacman -S --noconfirm --needed sysstat
|
|
sudo systemctl enable --now sysstat-collect.timer sysstat-rotate.timer
|
|
|
|
# [ACCT-9628] Enable auditd to collect audit data
|
|
sudo systemctl enable --now auditd audit-rules
|
|
|
|
# [ACCT-9630] Configure auditd rules
|
|
sudo tee /etc/audit/rules.d/10-harden.rules > /dev/null <<EOL
|
|
# Monitor attempts to change system time
|
|
-w /etc/localtime -p wa -k time-change
|
|
|
|
# Monitor attempts to change user/group info (password changes)
|
|
-w /etc/passwd -p wa -k user-info
|
|
-w /etc/shadow -p wa -k user-info
|
|
-w /etc/group -p wa -k user-info
|
|
-w /etc/gshadow -p wa -k user-info
|
|
|
|
# Make the configuration immutable (must be the last line)
|
|
-e 2
|
|
EOL
|
|
|
|
# To test
|
|
# Function to create basic systemd hardening drop-in
|
|
create_systemd_hardening () {
|
|
SERVICE="$1"
|
|
DROPIN="/etc/systemd/system/${SERVICE}.d"
|
|
sudo mkdir -p "$DROPIN"
|
|
sudo tee "$DROPIN/hardening.conf" > /dev/null <<EOL
|
|
[Service]
|
|
PrivateTmp=true
|
|
ProtectSystem=full
|
|
ProtectHome=true
|
|
NoNewPrivileges=true
|
|
ProtectKernelTunables=yes
|
|
ProtectKernelModules=yes
|
|
ProtectClock=true
|
|
ProtectHostname=true
|
|
ProtectControlGroups=true
|
|
PrivateDevices=false
|
|
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
SystemCallFilter=@system-service
|
|
UMask=0077
|
|
EOL
|
|
sudo systemctl daemon-reload
|
|
}
|
|
|
|
# Add conservative hardening overrides for high-risk services you should review
|
|
SERVICES_TO_HARDEN=(
|
|
"NetworkManager"
|
|
"accounts-daemon"
|
|
"aidecheck"
|
|
"auditd"
|
|
"bluetooth"
|
|
"bolt"
|
|
"dbus-broker"
|
|
"dirmngr@etc-pacman.d-gnupg"
|
|
"dm-event"
|
|
"emergency"
|
|
"firewalld"
|
|
"fprintd"
|
|
"getty@tty1"
|
|
"gpg-agent@etc-pacman.d-gnupg"
|
|
"keyboxd@etc-pacman.d-gnupg"
|
|
"lenovo-cfgservice"
|
|
"libvirtd"
|
|
"meshagent"
|
|
"ollama"
|
|
"packagekit"
|
|
"plymouth-start"
|
|
"rescue"
|
|
"rtkit-daemon"
|
|
"sddm"
|
|
"snapper-cleanup"
|
|
"snapper-timeline"
|
|
"syslog-ng@default"
|
|
"systemd-ask-password-console"
|
|
"systemd-ask-password-plymouth"
|
|
"systemd-ask-password-wall"
|
|
"systemd-bsod"
|
|
"systemd-rfkill"
|
|
"systemd-importd"
|
|
"systemd-machined"
|
|
"systemd-udevd"
|
|
"udisks2"
|
|
"user@1000"
|
|
"virtlockd"
|
|
"waydroid-container"
|
|
"wpa_supplicant"
|
|
)
|
|
for S in "${SERVICES_TO_HARDEN[@]}"; do
|
|
if systemctl list-unit-files | grep -q "$S"; then
|
|
create_systemd_hardening "$S"
|
|
fi
|
|
done
|