# IDS, log monitoring, login tracking, file integrity, process auditing, and alerting # Each function returns a bash command string that app.py executes via ssh_run() def auth_log_cmd(lines=100): """Return bash cmd to get recent auth log entries (failed/successful logins).""" return ( "echo '=== Recent Auth Log Entries ===' && " "if [ -f /var/log/auth.log ]; then " f" grep -E '(Failed|Accepted|Invalid|session opened|session closed|authentication failure)' /var/log/auth.log | tail -n {lines}; " "elif command -v journalctl >/dev/null 2>&1; then " f" journalctl -u sshd -u ssh --no-pager -n {lines} 2>&1; " "else " " echo 'No auth.log found and journalctl not available'; " "fi" ) def login_tracker_cmd(): """Return bash cmd to show login attempts with IP, count, and geo info.""" return ( "echo '=== Login Tracker: Top 20 IPs ===' && " "echo '' && " "echo '--- Failed Logins ---' && " "if [ -f /var/log/auth.log ]; then " " FAILED_IPS=$(grep -oP 'Failed password.*from \\K[0-9.]+' /var/log/auth.log 2>/dev/null | " " sort | uniq -c | sort -rn | head -20); " "else " " FAILED_IPS=$(journalctl -u sshd -u ssh --no-pager 2>/dev/null | " " grep -oP 'Failed password.*from \\K[0-9.]+' | " " sort | uniq -c | sort -rn | head -20); " "fi && " "if [ -z \"$FAILED_IPS\" ]; then " " echo 'No failed login attempts found'; " "else " " echo \"$FAILED_IPS\" | while read COUNT IP; do " " GEO=''; " " if command -v geoiplookup >/dev/null 2>&1; then " " GEO=$(geoiplookup \"$IP\" 2>/dev/null | head -1 | sed 's/GeoIP Country Edition: //'); " " elif command -v whois >/dev/null 2>&1; then " " GEO=$(whois \"$IP\" 2>/dev/null | grep -i -m1 'country' | awk '{print $NF}'); " " fi; " " printf '%6s %-16s %s\\n' \"$COUNT\" \"$IP\" \"$GEO\"; " " done; " "fi && " "echo '' && " "echo '--- Accepted Logins ---' && " "if [ -f /var/log/auth.log ]; then " " ACCEPT_IPS=$(grep -oP 'Accepted.*from \\K[0-9.]+' /var/log/auth.log 2>/dev/null | " " sort | uniq -c | sort -rn | head -20); " "else " " ACCEPT_IPS=$(journalctl -u sshd -u ssh --no-pager 2>/dev/null | " " grep -oP 'Accepted.*from \\K[0-9.]+' | " " sort | uniq -c | sort -rn | head -20); " "fi && " "if [ -z \"$ACCEPT_IPS\" ]; then " " echo 'No accepted logins found'; " "else " " echo \"$ACCEPT_IPS\" | while read COUNT IP; do " " GEO=''; " " if command -v geoiplookup >/dev/null 2>&1; then " " GEO=$(geoiplookup \"$IP\" 2>/dev/null | head -1 | sed 's/GeoIP Country Edition: //'); " " elif command -v whois >/dev/null 2>&1; then " " GEO=$(whois \"$IP\" 2>/dev/null | grep -i -m1 'country' | awk '{print $NF}'); " " fi; " " printf '%6s %-16s %s\\n' \"$COUNT\" \"$IP\" \"$GEO\"; " " done; " "fi" ) def active_sessions_cmd(): """Return bash cmd to show who is currently logged in.""" return ( "echo '=== Currently Logged In ===' && " "w 2>&1 && " "echo '' && " "echo '=== Active Sessions (who) ===' && " "who 2>&1 && " "echo '' && " "echo '=== Recent Logins (last 10) ===' && " "last -10 2>&1" ) def file_integrity_check_cmd(paths="/etc /usr/bin /usr/sbin /var/www"): """Return bash cmd to create/check file integrity baseline.""" db = "/var/lib/setec-integrity.db" return ( f"if [ -f {db} ]; then " f" echo '=== File Integrity Check (comparing to baseline) ===' && " f" CURRENT=$(mktemp) && " f" find {paths} -type f -exec md5sum {{}} + 2>/dev/null | sort -k2 > \"$CURRENT\" && " f" BASELINE=$(sort -k2 {db}) && " " echo '' && " " echo '--- Modified Files ---' && " f" diff <(echo \"$BASELINE\") \"$CURRENT\" 2>/dev/null | grep '^[<>]' | head -50 && " " echo '' && " " echo '--- New Files (not in baseline) ---' && " f" comm -13 <(awk '{{print $2}}' {db} | sort) <(awk '{{print $2}}' \"$CURRENT\" | sort) | head -50 && " " echo '' && " " echo '--- Deleted Files (in baseline but missing) ---' && " f" comm -23 <(awk '{{print $2}}' {db} | sort) <(awk '{{print $2}}' \"$CURRENT\" | sort) | head -50 && " " MODIFIED=$(diff <(echo \"$BASELINE\") \"$CURRENT\" 2>/dev/null | grep -c '^[<>]' || true) && " " echo '' && " " echo \"Summary: $MODIFIED differences found\" && " " rm -f \"$CURRENT\"; " "else " f" echo 'No baseline found at {db}. Creating initial baseline...' && " f" find {paths} -type f -exec md5sum {{}} + 2>/dev/null | sort -k2 > {db} && " f" COUNT=$(wc -l < {db}) && " " echo \"Baseline created with $COUNT files\"; " "fi" ) def file_integrity_init_cmd(paths="/etc /usr/bin /usr/sbin /var/www"): """Return bash cmd to initialize/reset the integrity baseline.""" db = "/var/lib/setec-integrity.db" return ( f"echo '=== Initializing File Integrity Baseline ===' && " f"mkdir -p /var/lib && " f"find {paths} -type f -exec md5sum {{}} + 2>/dev/null | sort -k2 > {db} && " f"COUNT=$(wc -l < {db}) && " f"echo \"Baseline created at {db} with $COUNT files\" && " f"echo \"Monitored paths: {paths}\"" ) def process_audit_cmd(): """Return bash cmd to find suspicious processes.""" return ( "echo '=== Process Security Audit ===' && " "echo '' && " "echo '--- Listening Ports with Processes ---' && " "ss -tlnp 2>&1 && " "echo '' && " "echo '--- UDP Listening Ports ---' && " "ss -ulnp 2>&1 && " "echo '' && " "echo '--- Processes Running as Root (non-kernel) ---' && " "ps aux --sort=-%mem 2>/dev/null | awk '$1==\"root\" && $11!~/^\\[/' | head -30 && " "echo '' && " "echo '--- Processes with Deleted Binaries (suspicious) ---' && " "ls -la /proc/*/exe 2>/dev/null | grep '(deleted)' || echo 'None found' && " "echo '' && " "echo '--- Recently Modified Binaries (last 7 days) ---' && " "find /usr/bin /usr/sbin /usr/local/bin -type f -mtime -7 -ls 2>/dev/null | head -30 || echo 'None found' && " "echo '' && " "echo '--- Unusual SUID/SGID Binaries ---' && " "find /usr/bin /usr/sbin /usr/local/bin /tmp /var/tmp -type f \\( -perm -4000 -o -perm -2000 \\) -ls 2>/dev/null | head -30 || echo 'None found'" ) def security_log_cmd(lines=100): """Return bash cmd to get combined security-relevant logs.""" return ( "echo '=== Combined Security Logs ===' && " "( " " [ -f /var/log/auth.log ] && grep -E '(Failed|Accepted|Invalid|authentication failure|sudo|su:)' /var/log/auth.log 2>/dev/null; " " [ -f /var/log/fail2ban.log ] && tail -50 /var/log/fail2ban.log 2>/dev/null; " " [ -f /var/log/kern.log ] && grep -iE '(iptables|firewall|segfault|oom)' /var/log/kern.log 2>/dev/null; " " [ -f /var/log/syslog ] && grep -iE '(security|attack|denied|unauthorized|blocked)' /var/log/syslog 2>/dev/null; " " journalctl -p warning --since '24 hours ago' --no-pager 2>/dev/null | head -50; " f") | sort -t' ' -k1,3 2>/dev/null | tail -n {lines}" ) def alert_setup_cmd(email, webhook_url=""): """Return bash cmd to set up alert script for suspicious activity.""" webhook_section = "" if webhook_url: webhook_section = ( f" if command -v curl >/dev/null 2>&1; then\\n" f" curl -s -X POST -H 'Content-Type: application/json' " f"-d \\\"{{\\\\\\\"text\\\\\\\": \\\\\\\"$MSG\\\\\\\"}}\\\" " f"'{webhook_url}' >/dev/null 2>&1\\n" f" fi\\n" ) script = ( "#!/bin/bash\\n" "# Setec Labs Security Alert Script\\n" "LOGFILE=/var/log/setec-alerts.log\\n" "STATEFILE=/var/lib/setec-alert-state\\n" "THRESHOLD=10\\n" "\\n" "mkdir -p /var/lib\\n" "touch \\\"$STATEFILE\\\" \\\"$LOGFILE\\\"\\n" "\\n" "LAST_CHECK=$(cat \\\"$STATEFILE\\\" 2>/dev/null || echo 0)\\n" "NOW=$(date +%s)\\n" "echo \\\"$NOW\\\" > \\\"$STATEFILE\\\"\\n" "\\n" "# Check failed SSH logins since last check\\n" "if [ -f /var/log/auth.log ]; then\\n" " FAILED=$(grep 'Failed password' /var/log/auth.log 2>/dev/null | wc -l)\\n" "else\\n" " FAILED=$(journalctl -u sshd --since '5 minutes ago' --no-pager 2>/dev/null | grep -c 'Failed password')\\n" "fi\\n" "\\n" "# Check fail2ban bans\\n" "BANS=0\\n" "if [ -f /var/log/fail2ban.log ]; then\\n" " BANS=$(grep -c 'Ban' /var/log/fail2ban.log 2>/dev/null || echo 0)\\n" "fi\\n" "\\n" "# Check for new SUID files\\n" "NEWSUID=$(find /tmp /var/tmp /home -type f -perm -4000 2>/dev/null | wc -l)\\n" "\\n" "ALERT=0\\n" "MSG=\\\"\\\"\\n" "\\n" "if [ \\\"$FAILED\\\" -gt \\\"$THRESHOLD\\\" ]; then\\n" " MSG=\\\"ALERT: $FAILED failed SSH login attempts detected\\\"\\n" " ALERT=1\\n" "fi\\n" "\\n" "if [ \\\"$NEWSUID\\\" -gt 0 ]; then\\n" " MSG=\\\"$MSG\\\\nALERT: $NEWSUID SUID files found in /tmp, /var/tmp, or /home\\\"\\n" " ALERT=1\\n" "fi\\n" "\\n" "if [ \\\"$ALERT\\\" -eq 1 ]; then\\n" " HOSTNAME=$(hostname)\\n" " MSG=\\\"[$HOSTNAME] $(date): $MSG\\\"\\n" " echo \\\"$MSG\\\" >> \\\"$LOGFILE\\\"\\n" f" if command -v mail >/dev/null 2>&1; then\\n" f" echo -e \\\"$MSG\\\" | mail -s \\\"Setec Security Alert: $HOSTNAME\\\" {email} 2>/dev/null\\n" f" fi\\n" f"{webhook_section}" "fi\\n" ) return ( "echo '=== Setting Up Security Alerting ===' && " f"echo -e '{script}' > /usr/local/bin/setec-alert.sh && " "chmod +x /usr/local/bin/setec-alert.sh && " "touch /var/log/setec-alerts.log && " "(crontab -l 2>/dev/null | grep -v 'setec-alert.sh'; " "echo '*/5 * * * * /usr/local/bin/setec-alert.sh') | crontab - && " f"echo 'Alert script installed at /usr/local/bin/setec-alert.sh' && " f"echo 'Cron job added: runs every 5 minutes' && " f"echo 'Alert email: {email}'" ) def alert_status_cmd(): """Return bash cmd to check if alerting is configured and show recent alerts.""" return ( "echo '=== Alert System Status ===' && " "echo '' && " "echo '--- Script ---' && " "if [ -f /usr/local/bin/setec-alert.sh ]; then " " echo 'Alert script: INSTALLED'; " " ls -la /usr/local/bin/setec-alert.sh; " "else " " echo 'Alert script: NOT INSTALLED'; " "fi && " "echo '' && " "echo '--- Cron Job ---' && " "if crontab -l 2>/dev/null | grep -q 'setec-alert.sh'; then " " echo 'Cron job: ACTIVE'; " " crontab -l 2>/dev/null | grep 'setec-alert.sh'; " "else " " echo 'Cron job: NOT FOUND'; " "fi && " "echo '' && " "echo '--- Recent Alerts (last 20) ---' && " "if [ -f /var/log/setec-alerts.log ]; then " " tail -20 /var/log/setec-alerts.log; " "else " " echo 'No alert log found'; " "fi" ) def alert_remove_cmd(): """Return bash cmd to remove alerting.""" return ( "echo '=== Removing Security Alerting ===' && " "(crontab -l 2>/dev/null | grep -v 'setec-alert.sh') | crontab - && " "rm -f /usr/local/bin/setec-alert.sh && " "echo 'Alert script removed' && " "echo 'Cron job removed' && " "echo 'Alert log preserved at /var/log/setec-alerts.log'" ) def suid_audit_cmd(): """Return bash cmd to find all SUID/SGID binaries.""" return ( "echo '=== SUID/SGID Binary Audit ===' && " "echo '' && " "echo '--- SUID Binaries ---' && " "find / -type f -perm -4000 -not -path '/proc/*' -not -path '/sys/*' -ls 2>/dev/null && " "echo '' && " "echo '--- SGID Binaries ---' && " "find / -type f -perm -2000 -not -path '/proc/*' -not -path '/sys/*' -ls 2>/dev/null && " "echo '' && " "SUID_COUNT=$(find / -type f -perm -4000 -not -path '/proc/*' -not -path '/sys/*' 2>/dev/null | wc -l) && " "SGID_COUNT=$(find / -type f -perm -2000 -not -path '/proc/*' -not -path '/sys/*' 2>/dev/null | wc -l) && " "echo \"Total: $SUID_COUNT SUID, $SGID_COUNT SGID binaries\"" ) def world_writable_cmd(): """Return bash cmd to find world-writable files/dirs.""" return ( "echo '=== World-Writable Files ===' && " "find / -type f -perm -0002 " "-not -path '/proc/*' -not -path '/sys/*' -not -path '/dev/*' " "-ls 2>/dev/null | head -50 && " "echo '' && " "echo '=== World-Writable Directories (without sticky bit) ===' && " "find / -type d -perm -0002 -not -perm -1000 " "-not -path '/proc/*' -not -path '/sys/*' -not -path '/dev/*' " "-ls 2>/dev/null | head -50" ) def cron_audit_cmd(): """Return bash cmd to audit all cron jobs on the system.""" return ( "echo '=== Cron Job Audit ===' && " "echo '' && " "echo '--- System Crontab (/etc/crontab) ---' && " "cat /etc/crontab 2>/dev/null || echo 'Not found' && " "echo '' && " "echo '--- /etc/cron.d/ ---' && " "for f in /etc/cron.d/*; do " " [ -f \"$f\" ] && echo \"== $f ==\" && cat \"$f\" && echo ''; " "done 2>/dev/null && " "echo '' && " "echo '--- /etc/cron.daily/ ---' && " "ls -la /etc/cron.daily/ 2>/dev/null || echo 'Not found' && " "echo '' && " "echo '--- /etc/cron.hourly/ ---' && " "ls -la /etc/cron.hourly/ 2>/dev/null || echo 'Not found' && " "echo '' && " "echo '--- /etc/cron.weekly/ ---' && " "ls -la /etc/cron.weekly/ 2>/dev/null || echo 'Not found' && " "echo '' && " "echo '--- /etc/cron.monthly/ ---' && " "ls -la /etc/cron.monthly/ 2>/dev/null || echo 'Not found' && " "echo '' && " "echo '--- User Crontabs ---' && " "for user in $(cut -f1 -d: /etc/passwd 2>/dev/null); do " " CRON=$(crontab -u \"$user\" -l 2>/dev/null); " " if [ -n \"$CRON\" ]; then " " echo \"== $user ==\"; " " echo \"$CRON\"; " " echo ''; " " fi; " "done && " "echo '' && " "echo '--- Systemd Timers ---' && " "systemctl list-timers --all --no-pager 2>/dev/null || echo 'systemctl not available'" )