Created
October 9, 2025 07:40
-
-
Save xakepp35/164470ecd136ba4fabe246eaf0e48a40 to your computer and use it in GitHub Desktop.
Проверка и (опционно) исправление набора рекомендаций по харденингу Linux (FSTEC-like).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # fstec_harden.sh | |
| # Проверка и (опционно) исправление набора рекомендаций по харденингу Linux (FSTEC-like). | |
| # Usage: | |
| # ./fstec_harden.sh # только проверки | |
| # ./fstec_harden.sh --apply # применить безопасные исправления | |
| # ./fstec_harden.sh --apply --force # применить и рискованные исправления | |
| # | |
| # Автор: ChatGPT | |
| # Дата: 2025-10-09 | |
| # Лицензия MIT | |
| set -euo pipefail | |
| LOGFILE="/var/log/fstec_harden.log" | |
| [ -w "$(dirname "$LOGFILE")" ] || LOGFILE="./fstec_harden.log" | |
| APPLY=0 | |
| FORCE=0 | |
| # Colors | |
| GREEN="\e[32m" | |
| YELLOW="\e[33m" | |
| RED="\e[31m" | |
| RESET="\e[0m" | |
| INFO="\e[36m" | |
| timestamp() { date -Iseconds; } | |
| log() { | |
| echo -e "[$(timestamp)] $*" | tee -a "$LOGFILE" | |
| } | |
| # status helpers | |
| pass() { log -e "${GREEN}PASS${RESET} $*"; } | |
| warn() { log -e "${YELLOW}WARN${RESET} $*"; } | |
| err() { log -e "${RED}ERR${RESET} $*"; } | |
| # utils | |
| require_root() { | |
| if [ "$EUID" -ne 0 ]; then | |
| err "Для этой операции требуются root-привилегии. Перезапустите скрипт как root." | |
| exit 2 | |
| fi | |
| } | |
| backup_file() { | |
| local f="$1" | |
| if [ -e "$f" ]; then | |
| local b="${f}.fstecbak.$(date +%Y%m%d%H%M%S)" | |
| cp -a -- "$f" "$b" | |
| log "backup: $f -> $b" | |
| fi | |
| } | |
| # parse args | |
| while (( "$#" )); do | |
| case "$1" in | |
| --apply) APPLY=1; shift ;; | |
| --force) FORCE=1; shift ;; | |
| --help|-h) echo "Usage: $0 [--apply] [--force]"; exit 0 ;; | |
| *) echo "Unknown arg: $1"; exit 1 ;; | |
| esac | |
| done | |
| log "=== START fstec_harden run (apply=$APPLY force=$FORCE) ===" | |
| ######### Checks & fixes ######### | |
| ######################################## | |
| # 2.1.1 Check accounts with empty passwords and /etc/shadow perms | |
| check_shadow_empty_passwords() { | |
| log "Check: empty-password accounts and /etc/shadow permissions" | |
| local shadow="/etc/shadow" | |
| if [ ! -r "$shadow" ]; then | |
| err "/etc/shadow недоступен для чтения. Проверьте права." | |
| return | |
| fi | |
| # list accounts with empty password field (second field empty) | |
| local empty_accounts | |
| empty_accounts=$(awk -F: '($2=="" ) {print $1}' /etc/shadow || true) | |
| if [ -n "$empty_accounts" ]; then | |
| warn "Найдены учётные записи с пустым паролем: $(echo $empty_accounts | tr '\n' ' ')" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| for u in $empty_accounts; do | |
| if [ "$FORCE" -eq 1 ]; then | |
| log "Locking account $u (passwd -l)" | |
| passwd -l "$u" 2>>"$LOGFILE" || warn "Не удалось заблокировать $u" | |
| else | |
| warn "Чтобы заблокировать аккаунты с пустыми паролями, перезапустить с --apply --force" | |
| fi | |
| done | |
| fi | |
| else | |
| pass "Пустых паролей в /etc/shadow не найдено" | |
| fi | |
| # permissions | |
| local perms | |
| perms=$(stat -c "%a %n" "$shadow") | |
| if [ "$(stat -c %a $shadow)" -gt 600 ]; then | |
| warn "/etc/shadow имеет права $(stat -c %a $shadow) — рекомендуется 600" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod 600 "$shadow" && pass "Установлены права 600 на $shadow" | |
| fi | |
| else | |
| pass "/etc/shadow права OK: $(stat -c %a $shadow)" | |
| fi | |
| } | |
| ######################################## | |
| # 2.1.2 Disable PermitRootLogin over SSH | |
| check_sshd_root_login() { | |
| log "Check: PermitRootLogin in sshd_config" | |
| local f="/etc/ssh/sshd_config" | |
| if [ ! -f "$f" ]; then | |
| warn "sshd_config не найден ($f) — пропускаем" | |
| return | |
| fi | |
| local cur | |
| cur=$(sshd -T 2>/dev/null | awk '/permitrootlogin/ {print $2}' || true) | |
| if [ -z "$cur" ]; then | |
| # fallback to file parse | |
| cur=$(grep -i '^PermitRootLogin' "$f" 2>/dev/null | tail -n1 | awk '{print $2}' || true) | |
| fi | |
| if [ "$cur" = "no" ]; then | |
| pass "PermitRootLogin уже выключен ($cur)" | |
| else | |
| warn "PermitRootLogin = ${cur:-unspecified} — рекомендуется no" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| backup_file "$f" | |
| # Set or add | |
| if grep -qi '^PermitRootLogin' "$f"; then | |
| sed -ri 's/^(#\s*)?PermitRootLogin\s+.*/PermitRootLogin no/' "$f" | |
| else | |
| echo -e "\n# hardened by fstec_harden\nPermitRootLogin no" >> "$f" | |
| fi | |
| systemctl restart sshd 2>>"$LOGFILE" && pass "sshd restarted and PermitRootLogin set to no" | |
| fi | |
| fi | |
| } | |
| ######################################## | |
| # 2.2.1 PAM wheel for su | |
| check_pam_su_wheel() { | |
| log "Check: PAM wheel for /bin/su" | |
| local f="/etc/pam.d/su" | |
| if [ ! -f "$f" ]; then | |
| warn "$f not found — возможно systemd-based distro without su. Пропускаем" | |
| return | |
| fi | |
| if grep -qE '^\s*auth\s+required\s+pam_wheel.so\b' "$f"; then | |
| pass "PAM wheel for su present" | |
| else | |
| warn "PAM wheel not present in $f (auth required pam_wheel.so use_uid recommended)" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| backup_file "$f" | |
| # add line near top | |
| sed -i '1i# added by fstec_harden\nauth required pam_wheel.so use_uid' "$f" | |
| pass "Добавлена строка в $f: auth required pam_wheel.so use_uid" | |
| fi | |
| fi | |
| # check wheel group exists | |
| if getent group wheel >/dev/null; then | |
| pass "Группа wheel существует" | |
| else | |
| warn "Группа wheel отсутствует" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| groupadd wheel && pass "Создана группа wheel" | |
| fi | |
| fi | |
| } | |
| ######################################## | |
| # 2.2.2 sudoers review (non destructive) | |
| check_sudoers() { | |
| log "Check: /etc/sudoers and /etc/sudoers.d" | |
| if [ -f /etc/sudoers ]; then | |
| # look for unrestricted ALL=(ALL) NOPASSWD | |
| if grep -E '^[^#]*ALL\s*=\s*\(ALL:ALL\)\s*ALL' /etc/sudoers >/dev/null 2>&1 || grep -E 'NOPASSWD' /etc/sudoers >/dev/null 2>&1; then | |
| warn "Найдены потенциально широкие правила в /etc/sudoers (ALL / NOPASSWD). Рекомендуется пересмотреть." | |
| else | |
| pass "/etc/sudoers выглядит аккуратно" | |
| fi | |
| else | |
| warn "/etc/sudoers не найден" | |
| fi | |
| # scan sudoers.d | |
| if [ -d /etc/sudoers.d ]; then | |
| local wide | |
| wide=$(grep -R --line-number -E 'NOPASSWD|ALL\s*=\s*\(ALL:ALL\)\s*ALL' /etc/sudoers.d 2>/dev/null || true) | |
| if [ -n "$wide" ]; then | |
| warn "Найдены широкие правила в /etc/sudoers.d: $(echo "$wide" | tr '\n' ';')" | |
| else | |
| pass "/etc/sudoers.d проверки пройдены" | |
| fi | |
| fi | |
| if [ "$APPLY" -eq 1 ]; then | |
| log "Прямое редактирование sudoers небезопасно — предлагаем отдельный файл в /etc/sudoers.d/ с ограничениями" | |
| if [ "$FORCE" -eq 1 ]; then | |
| require_root | |
| local snippet="/etc/sudoers.d/fstec_restrict" | |
| backup_file "$snippet" | |
| cat > "$snippet" <<'EOF' | |
| # fragment created by fstec_harden - restrict example (edit to your needs) | |
| # Пример: дать user1 право запускать только /bin/systemctl | |
| # user1 ALL=(ALL) /bin/systemctl | |
| EOF | |
| chmod 440 "$snippet" | |
| pass "Создан шаблон $snippet — отредактируйте под свои нужды" | |
| else | |
| warn "Для создания шаблона sudoers используйте --apply --force" | |
| fi | |
| fi | |
| } | |
| ######################################## | |
| # 2.3.* File system permissions | |
| check_file_permissions() { | |
| log "Check: базовые права на /etc/passwd, /etc/group, /etc/shadow" | |
| for f in /etc/passwd /etc/group /etc/shadow; do | |
| if [ -e "$f" ]; then | |
| cur=$(stat -c "%a %U:%G %n" "$f") | |
| log "$cur" | |
| else | |
| warn "Не найден $f" | |
| fi | |
| done | |
| # verify recommended perms | |
| if [ -e /etc/passwd ] && [ "$(stat -c %a /etc/passwd)" -ne 644 ]; then | |
| warn "/etc/passwd рекомендуется 644" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod 644 /etc/passwd && pass "chmod 644 /etc/passwd" | |
| fi | |
| else | |
| pass "/etc/passwd права OK" | |
| fi | |
| if [ -e /etc/group ] && [ "$(stat -c %a /etc/group)" -ne 644 ]; then | |
| warn "/etc/group рекомендуется 644" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod 644 /etc/group && pass "chmod 644 /etc/group" | |
| fi | |
| else | |
| pass "/etc/group права OK" | |
| fi | |
| if [ -e /etc/shadow ] && [ "$(stat -c %a /etc/shadow)" -ne 600 ]; then | |
| warn "/etc/shadow рекомендуется 600" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod 600 /etc/shadow && pass "chmod 600 /etc/shadow" | |
| fi | |
| else | |
| pass "/etc/shadow права OK" | |
| fi | |
| } | |
| # 2.3.2 - find executables with world-writable bit or in writable dirs | |
| check_exec_writable() { | |
| log "Check: исполняемые файлы и библиотеки доступны для записи группой/прочими?" | |
| # Find executables that are writable by group/other | |
| warn_files=$(find / -xdev -type f \( -perm -002 -o -perm -020 \) -exec ls -ld {} + 2>/dev/null || true) | |
| if [ -n "$warn_files" ]; then | |
| warn "Найдены файлы, доступные для записи group/other (показаны частично)." | |
| log "$(echo "$warn_files" | head -n 20)" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| # be conservative: change only for common bin dirs | |
| for d in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin; do | |
| if [ -d "$d" ]; then | |
| find "$d" -type f \( -perm -002 -o -perm -020 \) -exec chmod go-w {} \; 2>/dev/null || true | |
| fi | |
| done | |
| pass "Поправлены права записи для /bin,/usr/bin и т.п. (консервативно)" | |
| fi | |
| else | |
| pass "Нет исполняемых файлов с правом записи для group/other на проанализированных FS" | |
| fi | |
| } | |
| # 2.3.3 cron files permissions | |
| check_cron_files() { | |
| log "Check: права на системные cron файлы" | |
| if [ -e /etc/crontab ]; then | |
| if [ "$(stat -c %a /etc/crontab)" -gt 644 ]; then | |
| warn "/etc/crontab имеет слишком открытые права $(stat -c %a /etc/crontab)" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod go-wx /etc/crontab && pass "chmod go-wx /etc/crontab" | |
| fi | |
| else | |
| pass "/etc/crontab права OK" | |
| fi | |
| fi | |
| if [ -d /etc/cron.d ]; then | |
| local bad | |
| bad=$(find /etc/cron.d -type f ! -perm -go-wx 2>/dev/null || true) | |
| if [ -n "$bad" ]; then | |
| warn "Некоторые файлы в /etc/cron.d имеют открытые права" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| find /etc/cron.d -type f -exec chmod go-wx {} \; && pass "Исправлены права в /etc/cron.d" | |
| fi | |
| else | |
| pass "/etc/cron.d права OK" | |
| fi | |
| fi | |
| # user crons | |
| if [ -d /var/spool/cron ]; then | |
| if [ "$(find /var/spool/cron -type f -exec stat -c '%a %n' {} + 2>/dev/null | awk '{print $1}' | grep -E '^[0-9]+$' | sort -u | grep -v '^600$' || true)" ]; then | |
| warn "Есть пользовательские cron-файлы с нестандартными правами" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| find /var/spool/cron -type f -exec chmod 600 {} \; 2>/dev/null && pass "Установлены права 600 на user crons" | |
| fi | |
| else | |
| pass "Права на пользовательские cron OK (либо нет /var/spool/cron)" | |
| fi | |
| fi | |
| } | |
| # 2.3.9 SUID/SGID audit | |
| check_suid_sgid() { | |
| log "Check: SUID/SGID приложения" | |
| local suid_list | |
| suid_list=$(find / -perm -4000 -o -perm -2000 -type f 2>/dev/null || true) | |
| if [ -z "$suid_list" ]; then | |
| pass "SUID/SGID не найдены" | |
| return | |
| fi | |
| log "Найдено SUID/SGID (первые 40):" | |
| echo "$suid_list" | head -n40 | tee -a "$LOGFILE" | |
| # whitelist common bins that usually have SUID | |
| local WHITELIST="/bin/su|/bin/ping|/usr/bin/sudo|/usr/bin/chfn|/usr/bin/chsh|/sbin/mount.*|/sbin/umount.*|/usr/bin/passwd" | |
| local suspect | |
| suspect=$(echo "$suid_list" | grep -Ev "$WHITELIST" || true) | |
| if [ -n "$suspect" ]; then | |
| warn "Есть SUID/SGID вне белого списка (показаны первые 20):" | |
| echo "$suspect" | head -n20 | tee -a "$LOGFILE" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| if [ "$FORCE" -eq 1 ]; then | |
| echo "$suspect" | while read -r f; do | |
| [ -z "$f" ] && continue | |
| chmod -s "$f" && log "suid/sgid снят: $f" | |
| done | |
| pass "Сняты SUID/SGID для подозрительных файлов (force)" | |
| else | |
| warn "Чтобы автоматически снять SUID/SGID для подозрительных файлов, запустите с --apply --force" | |
| fi | |
| fi | |
| else | |
| pass "SUID/SGID соответствуют ожидаемому списку" | |
| fi | |
| } | |
| # 2.3.10/11 home dirs and dotfiles | |
| check_home_permissions() { | |
| log "Check: права на домашние директории и скрытые файлы" | |
| local users | |
| users=$(awk -F: '($3>=1000 && $1!="nobody"){print $1 ":" $6}' /etc/passwd || true) | |
| if [ -z "$users" ]; then | |
| warn "Не найдено обычных пользователей (UID>=1000) — пропускаем" | |
| return | |
| fi | |
| while IFS=: read -r user homedir; do | |
| [ -z "$homedir" ] && continue | |
| if [ -d "$homedir" ]; then | |
| local hperm | |
| hperm=$(stat -c %a "$homedir") | |
| if [ "$hperm" -ne 700 ]; then | |
| warn "Домашняя директория $homedir пользователя $user имеет права $hperm (рекомендуется 700)" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod 700 "$homedir" && pass "chmod 700 $homedir" | |
| fi | |
| else | |
| pass "$homedir ($user) права OK" | |
| fi | |
| # dot-files | |
| local df | |
| df=$(find "$homedir" -maxdepth 1 -name ".*" -type f 2>/dev/null || true) | |
| if [ -n "$df" ]; then | |
| echo "$df" | while read -r f; do | |
| [ -z "$f" ] && continue | |
| if [ "$(stat -c %a "$f")" -gt 700 ]; then | |
| warn "Файл $f слишком открыт ($(stat -c %a "$f"))" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| chmod go-rwx "$f" && log "chmod go-rwx $f" | |
| fi | |
| fi | |
| done | |
| pass "$user: проверены скрытые файлы" | |
| fi | |
| fi | |
| done <<< "$users" | |
| } | |
| # 2.4.* kernel protection sysctls | |
| apply_sysctl_kv() { | |
| local key="$1" val="$2" desc="$3" | |
| local cur | |
| cur=$(sysctl -n "$key" 2>/dev/null || echo "") | |
| if [ "$cur" = "$val" ]; then | |
| pass "$key = $val" | |
| else | |
| warn "$key = ${cur:-unset} (рекомендуется $val) -- $desc" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| sysctl -w "$key=$val" >>"$LOGFILE" 2>&1 || warn "sysctl -w $key failed" | |
| # persist to /etc/sysctl.d/99-fstec.conf | |
| local conf="/etc/sysctl.d/99-fstec.conf" | |
| backup_file "$conf" | |
| grep -q "^$key" "$conf" 2>/dev/null && sed -ri "s|^$key.*|$key = $val|" "$conf" || echo "$key = $val" >> "$conf" | |
| pass "Установлен $key=$val и сохранён в $conf" | |
| fi | |
| fi | |
| } | |
| check_sysctls() { | |
| log "Check: kernel/sysctl hardening" | |
| apply_sysctl_kv "kernel.dmesg_restrict" "1" "ограничить dmesg" | |
| apply_sysctl_kv "kernel.kptr_restrict" "2" "скрыть kernel pointers" | |
| apply_sysctl_kv "net.core.bpf_jit_harden" "2" "bpf jit harden" | |
| apply_sysctl_kv "kernel.perf_event_paranoid" "3" "ограничить perf events" | |
| apply_sysctl_kv "kernel.kexec_load_disabled" "1" "запретить kexec_load" | |
| apply_sysctl_kv "user.max_user_namespaces" "0" "ограничить user namespaces" | |
| apply_sysctl_kv "kernel.unprivileged_bpf_disabled" "1" "запретить bpf" | |
| apply_sysctl_kv "vm.unprivileged_userfaultfd" "0" "запретить userfaultfd" | |
| apply_sysctl_kv "dev.tty.ldisc_autoload" "0" "запрет автозагрузки line discipline modules" | |
| apply_sysctl_kv "vm.mmap_min_addr" "4096" "минимальный mmap адрес" | |
| apply_sysctl_kv "kernel.randomize_va_space" "2" "ASLR" | |
| apply_sysctl_kv "kernel.yama.ptrace_scope" "3" "ограничить ptrace" | |
| apply_sysctl_kv "fs.protected_symlinks" "1" "защита symlinks" | |
| apply_sysctl_kv "fs.protected_hardlinks" "1" "защита hardlinks" | |
| apply_sysctl_kv "fs.protected_fifos" "2" "защита fifos" | |
| apply_sysctl_kv "fs.protected_regular" "2" "защита обычных файлов" | |
| apply_sysctl_kv "fs.suid_dumpable" "0" "запрет core dump для suid" | |
| } | |
| # 2.4.* and 2.5.* GRUB kernel cmdline flags (append) | |
| check_grub_cmdline() { | |
| log "Check: GRUB kernel command line options (append recommended params)" | |
| # recommended kernel params list | |
| local want=( "init_on_alloc=1" "slab_nomerge" "iommu=force" "iommu.strict=1" "iommu.passthrough=0" "randomize_kstack_offset=1" "mitigations=auto,nosmt" "vsyscall=none" "debugfs=off" "tsx=off" ) | |
| # get current cmdline from /proc/cmdline | |
| local cur | |
| cur=$(cat /proc/cmdline 2>/dev/null || true) | |
| local missing=() | |
| for p in "${want[@]}"; do | |
| if ! echo "$cur" | grep -qw "$p"; then | |
| missing+=("$p") | |
| fi | |
| done | |
| if [ "${#missing[@]}" -eq 0 ]; then | |
| pass "GRUB/kernel cmdline уже содержит рекомендуемые параметры" | |
| return | |
| fi | |
| warn "Некоторые kernel options отсутствуют в текущем cmdline: ${missing[*]}" | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| # attempt to update /etc/default/grub or /etc/default/grub.d/* | |
| local grubfile="/etc/default/grub" | |
| if [ ! -f "$grubfile" ]; then | |
| warn "$grubfile не найден — возможно другая система (grub2 not present). Пропускаем автоматическую правку." | |
| return | |
| fi | |
| backup_file "$grubfile" | |
| # Append missing to GRUB_CMDLINE_LINUX_DEFAULT | |
| local curval | |
| curval=$(grep -E "^GRUB_CMDLINE_LINUX_DEFAULT=" "$grubfile" | head -n1 || true) | |
| if [ -z "$curval" ]; then | |
| # add new | |
| echo "GRUB_CMDLINE_LINUX_DEFAULT=\"${missing[*]}\"" >> "$grubfile" | |
| else | |
| # append | |
| # strip trailing quote then append if not present | |
| sed -ri "s~^GRUB_CMDLINE_LINUX_DEFAULT=(\"?)(.*)(\"?)$~GRUB_CMDLINE_LINUX_DEFAULT=\"\2 ${missing[*]}\"~" "$grubfile" | |
| fi | |
| # Update grub config depending on distro | |
| if command -v update-grub >/dev/null 2>&1; then | |
| update-grub >>"$LOGFILE" 2>&1 && pass "update-grub выполнен, kernel options добавлены (перезагрузка нужна)" | |
| elif command -v grub2-mkconfig >/dev/null 2>&1 && [ -d /boot/efi -o -d /boot ]; then | |
| grub2-mkconfig -o /boot/grub2/grub.cfg >>"$LOGFILE" 2>&1 && pass "grub2-mkconfig выполнен" | |
| else | |
| warn "Не удалось автоматически обновить grub — выполните вручную: проверьте $grubfile и запустите update-grub или grub2-mkconfig" | |
| fi | |
| if [ "$FORCE" -ne 1 ]; then | |
| warn "Для внесения per-boot опций требуются перезагрузка и --force при следующем запуске (если хотите рискованные правки)." | |
| fi | |
| fi | |
| } | |
| # 2.6.* userspace protections (ptrace etc handled in sysctl) | |
| # Additional small checks: core dumps | |
| check_core_dumps() { | |
| log "Check: core dumps (fs.suid_dumpable already проверён)" | |
| local cur | |
| cur=$(ulimit -c 2>/dev/null || echo "unknown") | |
| if [ "$cur" = "0" ]; then | |
| pass "core dumps disabled (ulimit -c = 0)" | |
| else | |
| warn "ulimit -c = $cur (кор-дамп включён). Рекомендуется 0." | |
| if [ "$APPLY" -eq 1 ]; then | |
| require_root | |
| if grep -q "^*.*hard.*core" /etc/security/limits.conf 2>/dev/null; then | |
| pass "limits.conf уже содержит правило для core" | |
| else | |
| echo "* hard core 0" >> /etc/security/limits.conf | |
| pass "Добавлено правило * hard core 0 в /etc/security/limits.conf" | |
| fi | |
| fi | |
| fi | |
| } | |
| ######################################## | |
| # Run all checks | |
| main() { | |
| check_shadow_empty_passwords | |
| check_sshd_root_login | |
| check_pam_su_wheel | |
| check_sudoers | |
| check_file_permissions | |
| check_exec_writable | |
| check_cron_files | |
| check_suid_sgid | |
| check_home_permissions | |
| check_sysctls | |
| check_grub_cmdline | |
| check_core_dumps | |
| log "=== FINISHED checks. См. лог: $LOGFILE ===" | |
| # summary (simple) | |
| echo -e "\nSummary: лог записан в $LOGFILE" | |
| echo -e "${GREEN}PASS${RESET} — пункты, которые выглядят OK" | |
| echo -e "${YELLOW}WARN${RESET} — несоответствия, требующие внимания (часто безопасно исправить)" | |
| echo -e "${RED}ERR${RESET} — критичные проблемы/ошибки\n" | |
| log "=== END fstec_harden run ===" | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment