Bash Scripting for Security

Master Bash to automate system administration, build security monitoring tools, and create powerful scripts for penetration testing and defense.

Why Bash for Security

Bash (Bourne Again Shell) is the default shell on most Linux distributions. It is the backbone of system administration and essential for any security professional.

Why Security Professionals Choose Bash

  • Native on Linux - Every Linux server has Bash. No installation needed.
  • System control - Manage users, processes, permissions, services, and firewalls.
  • Log analysis - Parse and filter massive log files efficiently with grep, sed, awk.
  • Automation - Schedule tasks with cron, automate security scans and reports.
  • Tool integration - Chain security tools together with pipes and redirection.
Key Concept

Bash is not just for running commands. Mastering Bash scripting allows you to build complete security solutions that run unattended on servers.

Bash Basics

Core Bash concepts every security professional needs to master for scripting and automation.

Variables

bash
# Variables (no spaces around =)
TARGET="192.168.1.1"
PORT_RANGE="1-1024"
LOG_FILE="/var/log/auth.log"

# Command substitution
DATE=$(date +%Y-%m-%d)
HOSTNAME=$(hostname)

# Read user input
read -p "Enter target IP: " TARGET
read -sp "Enter password: " PASS

Conditionals

bash
# Check if file exists
if [ -f "/etc/shadow" ]; then
    echo "[+] Shadow file found"
fi

# Check if port is open
if nc -z -w1 $TARGET 22 2>/dev/null; then
    echo "[+] Port 22 open on $TARGET"
fi

# Numeric comparison
OPEN_PORTS=$(ss -tlnp | grep -c LISTEN)
if [ $OPEN_PORTS -gt 10 ]; then
    echo "[!] Warning: $OPEN_PORTS open ports detected"
fi

Loops

bash
# For loop - scan ports
for port in $(seq 1 1024); do
    (echo >/dev/tcp/$TARGET/$port) 2>/dev/null && \
        echo "[+] Port $port OPEN"
done

# While loop - read from file
while read -r ip; do
    ping -c 1 -W 1 $ip &>/dev/null && \
        echo "[+] $ip is alive"
done < ips.txt

# Infinite monitoring loop
while true; do
    ALERTS=$(grep -c "Failed password" /var/log/auth.log)
    [ $ALERTS -gt 50 ] && echo "[ALERT] Brute force detected!"
    sleep 60
done

Functions

bash
# Reusable port check
check_port() {
    local host=$1
    local port=$2
    (echo >/dev/tcp/$host/$port) 2>/dev/null
    return $?
}

# Usage
check_port "192.168.1.1" 22 && echo "[+] SSH open"

# Service name lookup
get_service() {
    case $1 in
        21)  echo "FTP" ;;
        22)  echo "SSH" ;;
        80)  echo "HTTP" ;;
        443) echo "HTTPS" ;;
        *)   echo "Unknown" ;;
    esac
}

Text Processing for Security

Master grep, sed, and awk - the essential tools for parsing logs, filtering data, and extracting information.

grep - Pattern Matching

bash
# Find failed login attempts
grep "Failed password" /var/log/auth.log

# Extract IPs from failed logins
grep "Failed password" /var/log/auth.log | \
    grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" | \
    sort | uniq -c | sort -rn | head -10

# Search configs for passwords
grep -rn --include="*.{conf,cfg,ini}" "password" /etc/

sed - Stream Editor

bash
# Replace passwords in config
sed -i 's/password=.*/password=REDACTED/' config.ini

# Remove commented lines
sed '/^#/d' /etc/ssh/sshd_config

# Sanitize sensitive data in logs
sed 's/\b[0-9]\{4\}-[0-9]\{4\}-[0-9]\{4\}\b/[REDACTED]/g' access.log

awk - Pattern Processing

bash
# Top 10 IPs from access log
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

# Find 404 errors
awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -rn

# Detect SQL injection in logs
awk 'tolower($0) ~ /union.*select|drop.*table/ {print NR": "$0}' access.log

# Users with real shells
awk -F: '$7 !~ /nologin|false/ {print $1, $7}' /etc/passwd

Pipes & Redirection

Chain commands together and control input/output flows for powerful data processing pipelines.

bash
# Chain commands
cat access.log | grep "404" | awk '{print $7}' | sort | uniq -c | sort -rn

# Redirect stdout and stderr
nmap -sV $TARGET > scan_output.txt 2>&1

# Suppress all output
ping -c 1 $TARGET > /dev/null 2>&1

# Append to log
echo "$(date): Scan completed" >> scan_history.log

# Tee - output to screen and file
nmap -sV $TARGET | tee scan_report.txt

System Administration Security

Harden Linux systems by auditing users, permissions, and services with Bash commands.

bash
# Users with empty passwords
awk -F: '$2 == "" || $2 == "!" {print "WARNING: "$1}' /etc/shadow

# Users with UID 0 (root-level)
awk -F: '$3 == 0 {print $1}' /etc/passwd

# Find SUID files
find / -perm -4000 -type f 2>/dev/null

# World-writable files
find / -perm -0002 -type f ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null

# List listening services
ss -tlnp | awk 'NR>1 {print $4, $6}' | sort

# Disable unused services
for svc in telnet avahi-daemon cups; do
    systemctl stop $svc 2>/dev/null
    systemctl disable $svc 2>/dev/null
done

Log Analysis

Detect brute force attacks, privilege escalation attempts, and web attack patterns in system logs.

bash
# SSH brute force detection
echo "=== Top SSH Attackers ==="
grep "Failed password" /var/log/auth.log | \
    grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" | \
    sort | uniq -c | sort -rn | head -10

# Successful logins
grep "Accepted" /var/log/auth.log | \
    awk '{print $1,$2,$3,$9,"from",$11}' | tail -20

# Privilege escalation attempts
grep "sudo" /var/log/auth.log | grep "COMMAND" | \
    awk -F'CMD:' '{print $1}' | sort | uniq -c | sort -rn

# Web attack patterns
awk 'tolower($0) ~ /\.\.\/|cmd=|eval\(/ {print NR": "$0}' access.log

Bash Port Scanner

bash - port_scanner.sh
#!/bin/bash
# Simple Bash Port Scanner

TARGET=${1:-"127.0.0.1"}
START=${2:-1}
END=${3:-1024}

echo "[*] Scanning $TARGET ports $START-$END"
echo "[*] Start: $(date)"
echo "-----------------------------------"

OPEN_PORTS=()

for port in $(seq $START $END); do
    (echo >/dev/tcp/$TARGET/$port) 2>/dev/null
    if [ $? -eq 0 ]; then
        OPEN_PORTS+=($port)
        echo "[+] Port $port OPEN"
    fi &
done
wait

echo "-----------------------------------"
echo "[*] Found ${#OPEN_PORTS[@]} open ports"
echo "[*] End: $(date)"
[ ${#OPEN_PORTS[@]} -gt 0 ] && echo "[+] Ports: ${OPEN_PORTS[*]}"

Real-Time Log Monitor

bash - log_monitor.sh
#!/bin/bash
# Real-time security log monitor with alerting

LOG_FILE="/var/log/auth.log"
ALERT_LOG="/var/log/security_alerts.log"
THRESHOLD=5

echo "[*] Monitoring $LOG_FILE for brute force attacks"

tail -F $LOG_FILE | while read -r line; do
    if echo "$line" | grep -q "Failed password"; then
        IP=$(echo "$line" | grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}")
        COUNT=$(grep "$IP" $LOG_FILE | grep -c "Failed password")

        if [ $COUNT -ge $THRESHOLD ]; then
            MSG="$(date) [ALERT] $IP has $COUNT failed attempts"
            echo $MSG >> $ALERT_LOG
            echo $MSG

            # Block the IP with iptables
            iptables -A INPUT -s $IP -j DROP 2>/dev/null
            echo "[+] Blocked $IP via iptables"
        fi
    fi
done

Secure Backup Tool

bash - backup.sh
#!/bin/bash
# Encrypted incremental backup tool

SRC="/var/www"
DEST="/backup/encrypted"
KEY="/root/.backup_key"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $DEST

# Generate encryption key if missing
[ ! -f $KEY ] && openssl rand -base64 32 > $KEY && chmod 600 $KEY

# Create compressed tarball
tar czf /tmp/backup_$DATE.tar.gz $SRC 2>/dev/null

# Encrypt the backup
openssl enc -aes-256-cbc -salt -pbkdf2 \
    -in /tmp/backup_$DATE.tar.gz \
    -out $DEST/backup_$DATE.tar.gz.enc \
    -pass file:$KEY

# Cleanup
rm /tmp/backup_$DATE.tar.gz

# Remove backups older than 30 days
find $DEST -name "*.enc" -mtime +30 -delete

echo "[+] Backup completed: $DEST/backup_$DATE.tar.gz.enc"
echo "[+] Size: $(du -h $DEST/backup_$DATE.tar.gz.enc | awk '{print $1}')"

User Auditor

bash - user_auditor.sh
#!/bin/bash
# Comprehensive user security auditor

REPORT="/tmp/user_audit_$(date +%Y%m%d).txt"

echo "=========================================" > $REPORT
echo "  USER SECURITY AUDIT REPORT" >> $REPORT
echo "  Date: $(date)" >> $REPORT
echo "  Host: $(hostname)" >> $REPORT
echo "=========================================" >> $REPORT

# 1. Check for root-equivalent users
echo -e "\n[1] Users with UID 0 (root-level):" >> $REPORT
awk -F: '$3 == 0 {print "  [!] "$1}' /etc/passwd >> $REPORT

# 2. Check for empty passwords
echo -e "\n[2] Users with empty passwords:" >> $REPORT
EMPTY=$(awk -F: '$2 == "" {print $1}' /etc/shadow 2>/dev/null)
if [ -z "$EMPTY" ]; then
    echo "  [OK] No empty passwords found" >> $REPORT
else
    echo "$EMPTY" | while read user; do
        echo "  [!] $user has empty password" >> $REPORT
    done
fi

# 3. Users with login shells
echo -e "\n[3] Users with login shells:" >> $REPORT
awk -F: '$7 !~ /nologin|false/ {print "  "$1" -> "$7}' /etc/passwd >> $REPORT

# 4. Sudo group members
echo -e "\n[4] Sudo/sudoers group members:" >> $REPORT
getent group sudo 2>/dev/null | awk -F: '{print $4}' | tr ',' '\n' | \
    while read user; do echo "  [sudo] $user" >> $REPORT; done

# 5. Recently modified password files
echo -e "\n[5] Recently modified account files:" >> $REPORT
for f in /etc/passwd /etc/shadow /etc/group; do
    MOD=$(stat -c %y $f 2>/dev/null | cut -d. -f1)
    echo "  $f - Modified: $MOD" >> $REPORT
done

# 6. SSH authorized keys audit
echo -e "\n[6] SSH authorized_keys:" >> $REPORT
find /home -name "authorized_keys" -exec sh -c \
    'echo "  $1:"; cat "$1" | while read key; do echo "    $(echo $key | cut -d" " -f1-3)"; done' _ {} \; 2>/dev/null >> $REPORT

echo -e "\n=========================================" >> $REPORT
echo "  Report saved to $REPORT" >> $REPORT
cat $REPORT
Practice

Combine all four scripts into a single security suite with a menu interface. Add cron scheduling for automated execution and email alerting.

Resources