This commit is contained in:
2026-05-11 09:15:08 +02:00
parent 9bec2b9e42
commit 404ee3fec4
641 changed files with 416825 additions and 0 deletions
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
CHECK_DIR="/dev/shm"
findmnt -kn "$CHECK_DIR" &>/dev/null
exit $?
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
GRUB_CFG="/etc/default/grub"
if [[ ! -f "$GRUB_CFG" ]]; then
echo "Error: $GRUB_CFG does not exist."
exit 1
fi
if grep -q "apparmor=1" "$GRUB_CFG"; then
echo "Found 'apparmor=1' in $GRUB_CFG."
exit 0
else
echo "'apparmor=1' not found in $GRUB_CFG."
exit 1
fi
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
unconfined_lines=$(apparmor_status | grep unconfined)
while IFS= read -r line; do
if [[ ! "$line" =~ ^0 ]]; then
exit 1
fi
done <<<"$unconfined_lines"
exit 0
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
kernel_parameters=("fs.suid_dumpable")
kernel_values=("0")
len=${#kernel_parameters[@]}
for ((i = 0; i < len; i++)); do
param=${kernel_parameters[$i]}
value=${kernel_values[$i]}
current_value=$(sysctl -n "$param" 2>/dev/null)
# Check if sysctl command was successful
if [ $? -ne 0 ]; then
echo "Error: Kernel parameter $param does not exist or could not be retrieved."
exit 1
fi
# Check if the current value matches the expected value
if [ "$current_value" == "$value" ]; then
echo "Kernel parameter $param is set correctly to $value."
else
echo "Kernel parameter $param is not set to $value (current value: $current_value)."
exit 1
fi
done
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Extract the OS ID from /etc/os-release
OS_ID=$(grep '^ID=' /etc/os-release | cut -d= -f2 | sed -e 's/"//g')
# Run the grep command with the OS ID incorporated
grep -Eis "(\\v|\\r|\\m|\\s|$OS_ID)" /etc/motd
# Check the exit code of the grep command
if [ $? -ne 0 ]; then
# Grep did not find any matches, return 0
exit 0
else
# Grep found matches, return 1
exit 1
fi
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
TEST_FILE="/etc/motd"
if [ -e "$TEST_FILE" ]; then
DESIRED_PERM="644"
ACTUAL_PERM=$(stat -c "%a" "$TEST_FILE")
if [[ "$ACTUAL_PERM" == "$DESIRED_PERM" ]]; then
exit 0
else
exit 1
fi
fi
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
config_file="/etc/gdm/custom.conf"
if [[ ! -f "$config_file" || ! -r "$config_file" ]]; then
exit 0
fi
value="Enable"
if grep -Eq "^\s*$value\s*=\s*true\s*$" "$config_file"; then
echo -e " \"$value\" in $config_file is true"
exit 1
else
echo -e "\"$value\" not found or not set "
fi
exit 0
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
if command -v dpkg-query >/dev/null 2>&1; then
l_pq="dpkg-query -W"
elif command -v rpm >/dev/null 2>&1; then
l_pq="rpm -q"
fi
found=1
for gdm in "gdm" "gdm3"; do # Space seporated list of packages to check
$l_pq $gdm &>/dev/null && found=0
done
if [[ $found -eq 0 ]]; then
l_gdmfile="$(grep -Prils '^\h*banner-message-enable\b' /etc/dconf/db/*.d)" # can be multipale
num_gdmfile=$(wc -l <<< $l_gdmfile)
if [[ -n "$l_gdmfile" ]]; then
# wc -l because all files need to be set to true; grep -q states min 1 file is set to true
[[ $(grep -Pisl '^\h*banner-message-enable\h*=\h*true\b' $l_gdmfile | wc -l) < $num_gdmfile ]] && exit 1
[[ $(grep -Pisl '^\h*banner-message-text\h*=\h*.*$' $l_gdmfile | wc -l) < $num_gdmfile ]] && exit 1
l_gdmprofile="$(awk -F\/ '{split($(NF-1),a,".");print a[1]}' <<<"$l_gdmfile")" # can be multipale
for prof in $l_gdmprofile; do
# -r because local db config rules etc. can be listet under /etc/dconf/profile/user or others
grep -Prq "^\h*system-db:$prof" /etc/dconf/profile/ || exit 1
[ -f "/etc/dconf/db/$prof" ] || exit 1
done
else
exit 1
fi
fi
exit 0
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
if command -v dpkg-query >/dev/null 2>&1; then
l_pq="dpkg-query -W"
elif command -v rpm >/dev/null 2>&1; then
l_pq="rpm -q"
fi
found=1
for gdm in "gdm" "gdm3"; do # Space seporated list of packages to check
$l_pq $gdm &>/dev/null && found=0
done
if [[ $found -eq 0 ]]; then
l_gdmfile="$(grep -Prils '^\h*disable-user-list\h*=\h*true\b' /etc/dconf/db/*.d)" # can be multipale
if [[ -n "$l_gdmfile" ]]; then
l_gdmprofile="$(awk -F\/ '{split($(NF-1),a,".");print a[1]}' <<<"$l_gdmfile")" # can be multipale
for prof in $l_gdmprofile; do
# -r because local db config rules etc. can be listet under /etc/dconf/profile/user or others
grep -Prq "^\h*system-db:$prof" /etc/dconf/profile/ || exit 1
[ -f "/etc/dconf/db/$prof" ] || exit 1
done
else
exit 1
fi
fi
exit 0
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# untested - changed settings don't take effect?!
max_lockdelay=5
max_idledelay=900
unit_lockdelay=$(gsettings get org.gnome.desktop.screensaver lock-delay 2>/dev/null)
unit_idledelay=$(gsettings get org.gnome.desktop.session idle-delay 2>/dev/null)
if [[ -n "$unit_lockdelay" && -n "$unit_idledelay" ]]; then # is gnome installed
idledelay=$(cut -d ' ' -f 2 <<<"$unit_idledelay")
[[ $idledelay -gt $max_idledelay || $idledelay -le 0 ]] && exit 1
[[ $(cut -d ' ' -f 2 <<<"$unit_lockdelay") -gt $max_lockdelay ]] && exit 1
fi
exit 0
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
if command -v dpkg-query >/dev/null 2>&1; then
l_pq="dpkg-query -W"
elif command -v rpm >/dev/null 2>&1; then
l_pq="rpm -q"
fi
found=1
for gdm in "gdm" "gdm3"; do # Space seporated list of packages to check
$l_pq $gdm &>/dev/null && found=0
done
checkLock() {
l_gdmfile="$(grep -Prils "^\h*$1\h*=\h*\d+\b" /etc/dconf/db/*.d)" # can be multipale
if [[ -n "$l_gdmfile" ]]; then
for path in $(dirname $l_gdmfile); do
grep -Prisq "^\h*\/org\/gnome\/desktop\/$2\/$1\b" "$path/locks" || exit 1
done
else
exit 1
fi
}
if [[ $found -eq 0 ]]; then
checkLock "idle-delay" "session"
checkLock "lock-delay" "screensaver"
fi
exit 0
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
auto=$(gsettings get org.gnome.desktop.media-handling automount 2>/dev/null)
# -n checks for gnome installed
[[ -n "$auto" && "$auto" != "false" ]] && exit 1
autOpen=$(gsettings get org.gnome.desktop.media-handling automoun-open 2>/dev/null)
[[ -n "$autOpen" && "$autOpen" != "false" ]] && exit 1
exit 0
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
if command -v dpkg-query >/dev/null 2>&1; then
l_pq="dpkg-query -W"
elif command -v rpm >/dev/null 2>&1; then
l_pq="rpm -q"
fi
found=1
for gdm in "gdm" "gdm3"; do # Space seporated list of packages to check
$l_pq $gdm &>/dev/null && found=0
done
checkLock() {
l_gdmfile="$(grep -Prils "^\h*$1\h*=\h*\w+\b" /etc/dconf/db/*.d)" # can be multipale
if [[ -n "$l_gdmfile" ]]; then
for path in $(dirname $l_gdmfile); do
grep -Prisq "^\h*\/org\/gnome\/desktop\/media-handling\/$1\b" "$path/locks" || exit 1
done
else
exit 1
fi
}
if [[ $found -eq 0 ]]; then
checkLock "automount"
checkLock "automount-open"
fi
exit 0
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
auto=$(gsettings get org.gnome.desktop.media-handling autorun-never 2>/dev/null)
# -n checks for gnome installed
[[ -n "$auto" && "$auto" != "true" ]] && exit 1
exit 0
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
if command -v dpkg-query >/dev/null 2>&1; then
l_pq="dpkg-query -W"
elif command -v rpm >/dev/null 2>&1; then
l_pq="rpm -q"
fi
found=1
for gdm in "gdm" "gdm3"; do # Space seporated list of packages to check
$l_pq $gdm &>/dev/null && found=0
done
checkLock() {
l_gdmfile="$(grep -Prils "^\h*$1\h*=\h*\w+\b" /etc/dconf/db/*.d)" # can be multipale
if [[ -n "$l_gdmfile" ]]; then
for path in $(dirname $l_gdmfile); do
grep -Prisq "^\h*\/org\/gnome\/desktop\/media-handling\/$1\b" "$path/locks" || exit 1
done
else
exit 1
fi
}
if [[ $found -eq 0 ]]; then
checkLock "autorun-never"
fi
exit 0
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
{
output="" l_tsd="" l_sdtd="" chrony="" l_ntp=""
dpkg-query -W chrony >/dev/null 2>&1 && l_chrony="y"
dpkg-query -W ntp >/dev/null 2>&1 && l_ntp="y" || l_ntp=""
systemctl list-units --all --type=service | grep -q 'systemd-timesyncd.service' && systemctl is-enabled systemd-timesyncd.service | grep -q 'enabled' && l_sdtd="y"
# ! systemctl is-enabled systemd-timesyncd.service | grep -q 'enabled' && l_nsdtd="y" || l_nsdtd=""
if [[ "$l_chrony" = "y" && "$l_ntp" != "y" && "$l_sdtd" != "y" ]]; then
l_tsd="chrony"
output="$output\n- chrony is in use on the system"
elif [[ "$l_chrony" != "y" && "$l_ntp" = "y" && "$l_sdtd" != "y" ]]; then
l_tsd="ntp"
output="$output\n- ntp is in use on the system"
elif [[ "$l_chrony" != "y" && "$l_ntp" != "y" ]]; then
if systemctl list-units --all --type=service | grep -q 'systemd-timesyncd.service' && systemctl is-enabled systemd-timesyncd.service | grep -Eq '(enabled|disabled|masked)'; then
l_tsd="sdtd"
output="$output\n- systemd-timesyncd is in use on the system"
fi
else
[[ "$l_chrony" = "y" && "$l_ntp" = "y" ]] && output="$output\n- both chrony and ntp are in use on the system"
[[ "$l_chrony" = "y" && "$l_sdtd" = "y" ]] && output="$output\n- both chrony and systemd-timesyncd are in use on the system"
[[ "$l_ntp" = "y" && "$l_sdtd" = "y" ]] && output="$output\n- both ntp and systemd-timesyncd are in use on the system"
fi
if [ -n "$l_tsd" ]; then
echo -e "\n- PASS:\n$output\n"
else
echo -e "\n- FAIL:\n$output\n"
fi
}
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
if ! command -v chronyd &>/dev/null; then
# chronyd is not installed
exit 0
fi
if ps -ef | grep -v grep | grep -q "chronyd"; then
if ps -ef | grep -v grep | grep "chronyd" | awk '{print $1}' | grep -q "^_chrony$"; then
exit 0
else
exit 1
fi
else
exit 0
fi
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
{
output=""
grubfile=$(find /boot -type f \( -name 'grubenv' -o -name 'grub.conf' -o -name 'grub.cfg' \) -exec grep -Pl -- '^\h*(kernelopts=|linux|kernel)' {} \;)
searchloc="/run/sysctl.d/*.conf /etc/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /lib/sysctl.d/*.conf /etc/sysctl.conf"
if [ -s "$grubfile" ]; then
! grep -P -- "^\h*(kernelopts=|linux|kernel)" "$grubfile" | grep -vq -- ipv6.disable=1 && output="IPv6 Disabled in \"$grubfile\""
fi
if
grep -Pqs -- "^\h*net\.ipv6\.conf\.all\.disable_ipv6\h*=\h*1\h*(#.*)?$" $searchloc && \
grep -Pqs -- "^\h*net\.ipv6\.conf\.default\.disable_ipv6\h*=\h*1\h*(#.*)?$" $searchloc && \
sysctl net.ipv6.conf.all.disable_ipv6 | grep -Pqs -- "^\h*net\.ipv6\.conf\.all\.disable_ipv6\h*=\h*1\h*(#.*)?$" && \
sysctl net.ipv6.conf.default.disable_ipv6 | grep -Pqs -- "^\h*net\.ipv6\.conf\.default\.disable_ipv6\h*=\h*1\h*(#.*)?$"
then
[ -n "$output" ] && output="$output, and in sysctl config" || output="ipv6 disabled in sysctl config"
fi
[ -n "$output" ] && echo -e "\n$output\n" || echo -e "\nIPv6 is enabled on the system\n"
}
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
which ufw &>/dev/null || echo "no ufw" && exit 0
ufw_out="$(ufw status verbose)"
ss -tuln | awk '($5!~/%lo:/ && $5!~/127.0.0.1:/ && $5!~/::1/) {split($5, a, ":"); print a[2]}' | sort | uniq | while read -r lpn; do
! grep -Pq "^\h*$lpn\b" <<<"$ufw_out" && echo "- Port: \"$lpn\" is missing a firewall rule"
done
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
[ -n "$(grep -E '^\s*include' /etc/nftables.conf)" ] && awk '/hook input/,/}/' $(awk '$1 ~ /^\s*include/ { gsub("\"","",$2);print $2 }' /etc/nftables.conf)
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
[ -n "$(grep -E '^\s*include' /etc/nftables.conf)" ] && awk '/hook forward/,/}/' $(awk '$1 ~ /^\s*include/ { gsub("\"","",$2);print $2 }' /etc/nftables.conf)
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
[ -n "$(grep -E '^\s*include' /etc/nftables.conf)" ] && awk '/hook output/,/}/' $(awk '$1 ~ /^\s*include/ { gsub("\"","",$2);print $2 }' /etc/nftables.conf)
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
{
awk '/^ *-w/ \
&&(/\/var\/run\/utmp/ \
||/\/var\/log\/wtmp/ \
||/\/var\/log\/btmp/) \
&&/ +-p *wa/ \
&&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)' /etc/audit/rules.d/*.rules
}
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
{
auditctl -l | awk '/^ *-w/ \
&&(/\/var\/run\/utmp/ \
||/\/var\/log\/wtmp/ \
||/\/var\/log\/btmp/) \
&&/ +-p *wa/ \
&&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)'
}
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
checkForRules() {
# check if a Block states at least 1 reference (ufw blocks)
# and has more 2 lines (Input, Output, Forward blocks)
$1 -L | awk -v RS="\n\n" '$0 !~ /\(0 references\)/ && $0 ~ /.+\n.+\n.+/ {print $0}'
}
[[ -n "$(checkForRules ip6tables)" || -n "$(checkForRules iptables)" ]] && exit 1
exit 0
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
parameter_sshd_t=hostbasedauthentication
parameter_sshd_config=HostbasedAuthentication
desired_value=no
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq "^$parameter_sshd_config" /etc/ssh/sshd_config; then
actual_value=$(grep "^$parameter_sshd_config" /etc/ssh/sshd_config | awk '{print $2}')
else
exit 1
fi
fi
if [ "$actual_value" = "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
parameter_sshd_t=ignorerhosts
parameter_sshd_config=IgnoreRhosts
desired_value=yes
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq '^$parameter_sshd_config' /etc/ssh/sshd_config; then
actual_value=$(grep -i '^$parameter_sshd_config' /etc/ssh/sshd_config | awk '{print $2}')
else
echo "$parameter_sshd_config not set in sshd_config, using default"
actual_value=no
fi
fi
if [ "$actual_value" = "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
output=$(sshd -T -C user=root -C host="$(hostname)" -C addr="$(hostname -I | cut -d ' ' -f1)" | grep -Ei "kexalgorithms\s+([^#\n\r]+,)?(diffie-hellman-group1-sha1|diffie-hellman-group14-sha1|diffie-hellman-group-exchange-sha1)\b")
if [[ -n "$output" ]]; then
exit 1
else
exit 0
fi
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
#test
parameter_sshd_t=logingracetime
parameter_sshd_config=LoginGraceTime
desired_value=60
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq '^$parameter_sshd_config' /etc/ssh/sshd_config; then
actual_value=$(grep -i '^$parameter_sshd_config' /etc/ssh/sshd_config | awk '{print $2}')
else
echo "$parameter_sshd_config not set in sshd_config, using default"
actual_value=120
fi
fi
if [ "$actual_value" -le "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
parameter_sshd_t=loglevel
parameter_sshd_config=LogLevel
desired_value=INFO
desired_value1=VERBOSE
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq "^$parameter_sshd_config" /etc/ssh/sshd_config; then
actual_value=$(grep "^$parameter_sshd_config" /etc/ssh/sshd_config | awk '{print $2}')
else
echo "$parameter_sshd_config not set in sshd_config, using default"
actual_value=INFO
fi
fi
if [ "$actual_value" = "$desired_value" ] || [ "$actual_value" = "$desired_value1" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -Pi -- 'macs\h+([^#\n\r]+,)?(hmac-md5|hmac-md5-96|hmac-ripemd160|hmac-sha1-96|umac-64@openssh\.com|hmac-md5-etm@openssh\.com|hmac-md5-96-etm@openssh\.com|hmac-ripemd160-etm@openssh\.com|hmac-sha1-96-etm@openssh\.com|umac-64-etm@openssh\.com|umac-128-etm@openssh\.com)')
if [ -z "$actual_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
parameter_sshd_t=maxsessions
parameter_sshd_config=MaxSessions
FILE="/etc/ssh/sshd_config"
desired_value=10
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq '^$parameter_sshd_config' /etc/ssh/sshd_config; then
actual_value=$(grep -i '^$parameter_sshd_config' /etc/ssh/sshd_config | awk '{print $2}')
else
exit 1
fi
fi
if [ "$actual_value" -le "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
parameter_sshd_t=maxstartups
parameter_sshd_config=MaxStartups
desired_value="10:30:60"
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -Ei "^$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq "^$parameter_sshd_config" /etc/ssh/sshd_config; then
actual_value=$(grep -E "^$parameter_sshd_config" /etc/ssh/sshd_config | awk '{print $2}')
else
echo "$parameter_sshd_config not set in sshd_config, using default"
exit 1
fi
fi
if [ "$actual_value" = "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -Pi -- '^ciphers\h+\"?([^#\n\r]+,)?((3des|blowfish|cast128|aes(128|192|256))-cbc|arcfour(128|256)?|rijndael-cbc@lysator\.liu\.se|chacha20-poly1305@openssh\.com)')
if [ -z "$actual_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
parameter_sshd_t=clientaliveinterval
parameter_sshd_config=ClientAliveInterval
desired_value=15
parameter_sshd_t1=clientalivecountmax
parameter_sshd_config1=ClientAliveCountMax
desired_value1=3
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
actual_value1=$(sshd -T | grep -i "$parameter_sshd_t1" | awk '{print $2}')
if [ -z "$actual_value" ] && [ -z "$actual_value1" ]; then
if (grep -iq '^$parameter_sshd_config' /etc/ssh/sshd_config) && (grep -iq '^$parameter_sshd_config1' /etc/ssh/sshd_config); then
actual_value=$(grep -i '^$parameter_sshd_config' /etc/ssh/sshd_config | awk '{print $2}')
actual_value1=$(grep -i '^$parameter_sshd_config1' /etc/ssh/sshd_config | awk '{print $2}')
else
echo "$parameter_sshd_config not set in sshd_config, using default"
exit 1
fi
fi
if [ "$actual_value" -eq "$desired_value" ] && [ "$actual_value1" -eq "$desired_value1" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
parameter_sshd_t=disableforwarding
parameter_sshd_config=DisableForwarding
desired_value=yes
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq '^$parameter_sshd_config' /etc/ssh/sshd_config; then
actual_value=$(grep -i '^$parameter_sshd_config' /etc/ssh/sshd_config | awk '{print $2}')
else
exit 1
fi
fi
if [ "$actual_value" = "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
parameter_sshd_t=gssapiauthentication
parameter_sshd_config=GSSAPIAuthentication
desired_value=no
if ! command -v sshd &>/dev/null; then
echo "sshd command could not be found"
exit 0
fi
# Check using sshd -T output
actual_value=$(sshd -T | grep -i "$parameter_sshd_t" | awk '{print $2}')
if [ -z "$actual_value" ]; then
if grep -iq "^$parameter_sshd_config" /etc/ssh/sshd_config; then
actual_value=$(grep "^$parameter_sshd_config" /etc/ssh/sshd_config | awk '{print $2}')
else
exit 1
fi
fi
if [ "$actual_value" = "$desired_value" ]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
sufile="/etc/sudoers"
includes=$(awk '/^[^#]*(@|#)include(dir)?/{
if ($1 ~ /^(@|#)includedir/)
print $2"/*";
else print $2}' $sufile)
for file in $sufile $includes; do
# exclude hardening file
if [[ ! $file =~ /\*$ ]] && grep -q "^[^#]*NOPASSWD" $file && [[ $file != "/etc/sudoers.d/DSC" ]]; then
exit 1
fi
done
exit 0
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
sufile="/etc/sudoers"
includes=$(awk '/^[^#]*(@|#)include(dir)?/{
if ($1 ~ /^(@|#)includedir/)
print $2"/*";
else print $2}' $sufile)
for file in $sufile $includes; do
if [[ ! $file =~ /\*$ ]] && grep -q "^[^#]*!authenticate" $file; then
exit 1
fi
done
exit 0
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# multiple groups can be configured to switch to diffrent set of users
while IFS='=' read -r _ confGroup; do
# options not in specific Order -> cut of
group="$(echo $confGroup | awk '{print $1}')"
membercount=$(grep -Pi "^$group:" /etc/group | awk -F ':' '{print $NF}' | awk -F ',' '{print NF}')
# groups should have no members
[[ $membercount -gt 0 ]] && exit 1
done < <(grep -Pi '^\h*auth\h+(?:required|requisite)\h+pam_wheel\.so\h+(?:[^#\n\r]+\h+)?((?!\2)(use_uid\b|group=\H+\b))\h+(?:[^#\n\r]+\h+)?((?!\1)(use_uid\b|group=\H+\b))(\h+.*)?$' /etc/pam.d/su)
exit 0
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
pam_files=("/etc/pam.d/common-account" "/etc/pam.d/common-session" "/etc/pam.d/common-auth" "/etc/pam.d/common-password")
pam_module="pam_unix.so"
error_found=false
for file in "${pam_files[@]}"; do
echo "Checking $file..."
if grep -q "$pam_module" "$file"; then
echo "OK: $pam_module is enabled in $file"
else
echo "Error: $pam_module is NOT enabled in $file"
error_found=true
fi
done
if [ "$error_found" = true ]; then
echo "Test Failed: pam_unix.so is NOT enabled in all PAM configuration files."
exit 1
else
echo "Test Passed: pam_unix.so is enabled in all PAM configuration files."
exit 0
fi
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
pam_path="/usr/share/pam-configs"
pam_files=("faillock" "faillock_notify")
expected_faillock=(
'Name: Enable pam_faillock to deny access'
'Default: yes'
'Priority: 0'
'Auth-Type: Primary'
'Auth: [default=die] pam_faillock.so authfail'
)
expected_faillock_notify=(
'Name: Notify of failed login attempts and reset count upon success'
'Default: yes'
'Priority: 1024'
'Auth-Type: Primary'
'Auth: requisite pam_faillock.so preauth'
'Account-Type: Primary'
'Account: required pam_faillock.so'
)
check_profile() {
local profile_path="$pam_path/$1"
local expected_content=("${!2}")
if [[ ! -f "$profile_path" ]]; then
echo "ERROR: Profile $profile_path does not exist."
exit 1
fi
echo "Checking profile: $profile_path"
# Read the actual content of the profile file
for line in "${expected_content[@]}"; do
if ! grep -Fxq "$line" "$profile_path"; then
echo "ERROR: Expected line not found in $profile_path: $line"
exit 1
fi
done
}
check_profile "faillock" expected_faillock[@]
check_profile "faillock_notify" expected_faillock_notify[@]
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
pam_path="/usr/share/pam-configs"
profile_name="pwquality"
expected_content=(
'Name: Pwquality password strength checking'
'Default: yes'
'Priority: 1024'
'Conflicts: cracklib'
'Password-Type: Primary'
'Password:' 'requisite pam_pwquality.so retry=3'
'Password-Initial:'
'requisite'
)
# check if the pwquality exists
if [[ -f "$pam_path/$profile_name" ]]; then
echo "$profile_name profile found in $pam_path:"
else
echo "ERROR: $profile_name profile not found in $pam_path."
exit 1
fi
# check content of pwquality
for line in "${expected_pwquality[@]}"; do
if ! grep -Fxq "$line" "$pam_path/$profile_name"; then
echo "ERROR: Expected line not found in $profile_name: $line"
exit 1
fi
done
echo "pwquality profile content in $pam_path/$profile_name is correct."
exit 0
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
pam_path="/usr/share/pam-configs"
profile_name="pwhistory"
expected_content=(
'Name: pwhistory password history checking'
'Default: yes'
'Priority: 1024'
'Password-Type: Primary' 'Password:'
'requisite pam_pwhistory.so remember=24 enforce_for_root try_first_pass use_authtok'
)
# check content of pwhistory
if [[ -f "$pam_path/$profile_name" ]]; then
echo "$profile_name profile found in $pam_path:"
else
echo "ERROR: $profile_name profile not found in $pam_path."
exit 1
fi
# check content of pwhistory
for line in "${expected_pwquality[@]}"; do
if ! grep -Fxq "$line" "$pam_path/$profile_name"; then
echo "ERROR: Expected line not found in $profile_name: $line"
exit 1
fi
done
echo "$profile_name profile content in $pam_path/$profile_name is correct."
exit 0
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Parameter to search for
parameter_config="enforcing"
unwanted_value=0
file="/etc/security/pwquality.conf"
# Search for the line containing the parameter with '=' and the unwanted value, even if commented
line=$(grep -E "^\s*$parameter_config\s*=\s*$unwanted_value\s*$" "$file")
# Check if the unwanted line exists
if [ -n "$line" ]; then
echo "Error: The line '$parameter_config=$unwanted_value' exists in $file (even if commented)."
exit 1
else
echo "No unwanted or commented line '$parameter_config=$unwanted_value' found in $file."
exit 0
fi
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# File configuration
FILE="/etc/security/pwquality.conf"
# what we look for
PATTERN="enforce_for_root"
# Check if the file exists
if [ ! -f "$FILE" ]; then
echo "File $FILE wa not found."
exit 1
fi
# Search for the pattern, regardless of its case, even if it is commented out
grep -Ei "^[[:space:]]*#?[[:space:]]*$PATTERN" "$FILE" >/dev/null
FOUND=$?
# if the pattern is found
if [ $FOUND -eq 0 ]; then
# check if it is commented
grep -Ei "^[[:space:]]*#[[:space:]]*$PATTERN" "$FILE" >/dev/null
COMMENTED=$?
if [ $COMMENTED -eq 0 ]; then
exit 1
fi
exit 0
else
exit 1
fi
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
files_to_check=$(awk '/Password-Type:/{ f = 1;next } /-Type:/{ f = 0 } f {if (/pam_pwhistory\.so/) print FILENAME}' /usr/share/pam-configs/*)
if [[ -z $files_to_check ]]; then
echo "file was not found"
else
for file in "$files_to_check"; do
if grep -Eq "pam_pwhistory\.so.*remember=" "$file"; then
current_value=$(grep -Eo "remember=[0-9]+" "$file" | grep -Eo "[0-9]+")
if [ "$current_value" -lt 24 ]; then
exit 1
fi
else
exit 1
fi
done
exit 0
fi
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
files_to_check=$(awk '/Password-Type:/{ f = 1;next } /-Type:/{ f = 0 } f {if (/pam_pwhistory\.so/) print FILENAME}' /usr/share/pam-configs/*)
if [[ -z $files_to_check ]]; then
echo "file was not found"
else
for file in "$files_to_check"; do
if grep -Eq "pam_pwhistory\.so.*enforce_for_root" "$file"; then
exit 0
else
exit 1
fi
done
exit 1
fi
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
files_to_check=$(grep -El 'pam_unix\.so.*remember=' /usr/share/pam-configs/*)
if [[ -z "$files_to_check" ]]; then
exit 0
else
exit 1
fi
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
files_to_check=$(grep -Elz "Password-Type:.*\n.*pam_unix\.so" /usr/share/pam-configs/*)
if [ -z "$files_to_check" ]; then
echo "No relevant files found."
exit 0
fi
for file in $files_to_check; do
if ! grep -Eq "pam_unix\.so.*(yescrypt|sha512)" "$file"; then
exit 1
fi
done
exit 0
@@ -0,0 +1,10 @@
#!/bin/bash
root_password=$(getent shadow root | cut -d: -f2)
if [[ "$root_password" == "*" || "$root_password" == "!" || -z "$root_password" ]]; then
exit 1
fi
exit 0
@@ -0,0 +1,9 @@
#!/bin/bash
{
awk -F: '/^[^:]+:[^!*]/{print $1}' /etc/shadow | while read -r usr; do
change=$(date -d "$(chage --list $usr | grep '^Last password change' | cut -d: -f2 | grep -v 'never$')" +%s)
if [[ "$change" -gt "$(date +%s)" ]]; then
echo "User: \"$usr\" last password change was \"$(chage --list $usr | grep '^Last password change' | cut -d: -f2)\""
fi
done
}
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
regex_pattern="^\s*ForwardToSyslog\s*=\s*no"
config_files=("/etc/systemd/journald.conf" "/etc/systemd/journald.conf.d/*")
for config_file in "${config_files[@]}"; do
for file in $config_file; do
if [[ -f "$file" ]]; then
if grep -qE "$regex_pattern" "$file"; then
exit 0
fi
fi
done
done
exit 1
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
regex_pattern="^\s*Storage\s*=\s*persistent"
config_files=("/etc/systemd/journald.conf" "/etc/systemd/journald.conf.d/*")
for config_file in "${config_files[@]}"; do
for file in $config_file; do
if [[ -f "$file" ]]; then
if grep -qE "$regex_pattern" "$file"; then
exit 0
fi
fi
done
done
exit 1
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
regex_pattern="^\s*Compress\s*=\s*yes"
config_files=("/etc/systemd/journald.conf" "/etc/systemd/journald.conf.d/*")
for config_file in "${config_files[@]}"; do
for file in $config_file; do
if [[ -f "$file" ]]; then
if grep -qE "$regex_pattern" "$file"; then
exit 0
fi
fi
done
done
exit 1
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
socket_installed=$(systemctl list-unit-files | grep -q 'systemd-journal-remote.socket' && echo true || echo false)
service_installed=$(systemctl list-unit-files | grep -q 'systemd-journal-remote.service' && echo true || echo false)
if [[ "$socket_installed" == "false" && "$service_installed" == "false" ]]; then
exit 0 # True if neither is installed
elif [[ "$socket_installed" == "true" && "$(systemctl is-active systemd-journal-remote.socket)" =~ ^(inactive|failed)$ ]] &&
[[ "$service_installed" == "true" && "$(systemctl is-active systemd-journal-remote.service)" =~ ^(inactive|failed)$ ]]; then
exit 0 # True if both are not active (including failed)
else
exit 1 # False otherwise
fi
@@ -0,0 +1,5 @@
#!/bin/bash
for i in $(cut -s -d: -f4 /etc/passwd | sort -u); do
grep -q -P "^.*?:[^:]*:$i:" /etc/group || exit 1
done
@@ -0,0 +1,10 @@
#!/bin/bash
cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read 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
@@ -0,0 +1,5 @@
#!/bin/bash
cut -d: -f3 /etc/group | sort | uniq -d | while read x; do
echo "Duplicate GID ($x) in /etc/group"
done
@@ -0,0 +1,5 @@
#!/bin/bash
cut -d: -f1 /etc/passwd | sort | uniq -d | while read -r x; do
echo "Duplicate login name $x in /etc/passwd"
done
@@ -0,0 +1,5 @@
#!/bin/bash
cut -d: -f1 /etc/group | sort | uniq -d | while read -r x; do
echo "Duplicate group name $x in /etc/group"
done
@@ -0,0 +1,9 @@
#!/bin/bash
awk -F: '($1!~/(root|halt|sync|shutdown)/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7!~/(\/usr)?\/bin\/false(\/)?$/) { print $1 " " $6 }' /etc/passwd | while read -r user dir; do
if [ -d "$dir" ]; then
file="$dir/.forward"
if [ ! -h "$file" ] && [ -f "$file" ]; then
echo "User: \"$user\" file: \"$file\" exists"
fi
fi
done
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
GRUB_CFG="/etc/default/grub"
if [[ ! -f "$GRUB_CFG" ]]; then
echo "Error: $GRUB_CFG does not exist."
exit 1
fi
if grep -q "audit=1" "$GRUB_CFG"; then
echo "Found 'audit=1' in $GRUB_CFG."
exit 0
else
echo "'audit=1' not found in $GRUB_CFG."
exit 1
fi
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
GRUB_CFG="/etc/default/grub"
if [[ ! -f "$GRUB_CFG" ]]; then
echo "Error: $GRUB_CFG does not exist."
exit 1
fi
if grep -q "audit_backlog_limit" "$GRUB_CFG"; then
echo "Found 'audit_backlog_limit=1' in $GRUB_CFG."
exit 0
else
echo "'audit_backlog_limit=1' not found in $GRUB_CFG."
exit 1
fi
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
l_perm_mask="0137"
if [ -e "/etc/audit/auditd.conf" ]; then
# Extract the log directory from the configuration file
l_audit_log_directory="$(dirname "$(awk -F= '/^\s*log_file\s*/{print $2}' /etc/audit/auditd.conf | xargs)")"
if [ -d "$l_audit_log_directory" ]; then
l_maxperm="$(printf '%o' $((0777 & ~$l_perm_mask)))"
# Find files matching the permission mask and process them line by line
while IFS= read -r l_file; do
# Ensure the file exists and get its mode
if [ -e "$l_file" ]; then
l_file_mode="$(stat -Lc '%#a' "$l_file")"
exit 1
fi
done < <(find "$l_audit_log_directory" -maxdepth 1 -type f -perm /"$l_perm_mask")
# Check if any files were processed
if [ $? -eq 0 ]; then
exit 0
fi
else
exit 0
fi
else
exit 0
fi
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
l_output="" l_output2=""
if [ -e "/etc/audit/auditd.conf" ]; then
l_audit_log_directory="$(dirname "$(awk -F= '/^\s*log_file\s*/{print $2}' /etc/audit/auditd.conf | xargs)")"
if [ -d "$l_audit_log_directory" ]; then
while IFS= read -r l_file; do
l_output2="$l_output2\n - File: \"$l_file\" is owned by user: \"$(stat -Lc '%U' "$l_file")\"\n (should be owned by user: \"root\")\n"
done < <(find "$l_audit_log_directory" -maxdepth 1 -type f ! -user root)
else
l_output2="$l_output2\n - Log file directory not set in \"/etc/audit/auditd.conf\" please set log file directory"
fi
else
l_output2="$l_output2\n - File: \"/etc/audit/auditd.conf\" not found.\n - ** Verify auditd is installed **"
fi
if [ -z "$l_output2" ]; then
l_output="$l_output\n - All files in \"$l_audit_log_directory\" are owned by user: \"root\"\n"
echo -e "\n- Audit Result:\n ** PASS **\n - * Correctly configured * :$l_output"
exit 0
else
echo -e "\n- Audit Result:\n ** FAIL **\n - * Reasons for auditgfailure * :$l_output2\n"
exit 1
fi
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
audit_conf="/etc/audit/auditd.conf"
perm_mask="0177"
if [ ! -f "$audit_conf" ]; then
exit 1
fi
audit_log_dir=$(grep -E '^\s*log_file\s*=' "$audit_conf" | cut -d= -f2 | xargs dirname 2>/dev/null)
if [ -z "$audit_log_dir" ]; then
exit 1
fi
audit_log_group=$(grep -E '^\s*log_group\s*=' "$audit_conf" | cut -d= -f2 | xargs)
if [ -z "$audit_log_group" ]; then
exit 1
fi
if [ ! -d "$audit_log_dir" ]; then
exit 1
fi
for file in "$audit_log_dir"/*; do
if [ -f "$file" ]; then
group=$(ls -l "$file" | awk '{print $4}')
if [[ "$group" != "root" && "$group" != "adm" ]]; then
exit 1
fi
fi
done
exit 0
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
perm_mask="0027"
if [ -e "/etc/audit/auditd.conf" ]; then
log_dir="$(dirname "$(awk -F= '/^\s*log_file\s*/{print $2}' /etc/audit/auditd.conf | xargs)")"
if [ -d "$log_dir" ]; then
maxperm="$(printf '%o' $((0777 & ~$perm_mask)))"
log_dir_mode="$(stat -Lc '%#a' "$log_dir")"
if [ $(($log_dir_mode & $perm_mask)) -gt 0 ]; then
exit 1
fi
else
exit 1
fi
else
exit 1
fi
exit 0