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.
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
# 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
# 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
# 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
# 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
# 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
# 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
# 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.
# 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.
# 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.
# 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
#!/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
#!/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
#!/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
#!/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
Combine all four scripts into a single security suite with a menu interface. Add cron scheduling for automated execution and email alerting.
Resources
- GNU Bash Manual: gnu.org/software/bash/manual
- ShellCheck: shellcheck.net - Linter for shell scripts
- Linux Command Library: linuxcommand.org
- OverTheWire: Bandit: overthewire.org
- Linux Security Cookbook: O'Reilly Media