Bash and PowerShell for Security Automation
TL;DR: Scripting is essential for security engineers. Bash handles Linux/Unix automation while PowerShell dominates Windows environments. Both are crucial for automating recon, log analysis, incident response, and repetitive security tasks.
Table of Contents
Open Table of Contents
Quick Reference
Bash Essentials
| Concept | Syntax | Example |
|---|---|---|
| Variable | VAR="value" | TARGET="10.10.10.1" |
| Command substitution | $(command) | DATE=$(date +%Y%m%d) |
| Loop | for i in list; do; done | for port in 22 80 443; do |
| Conditional | if [[ condition ]]; then | if [[ -f file ]]; then |
| Read file | while read line; do | while read ip; do scan $ip; done < ips.txt |
| Pipe | cmd1 | cmd2 | cat log | grep error |
| Redirect | > (overwrite) >> (append) | echo "test" >> log.txt |
| Exit code | $? | if [[ $? -eq 0 ]]; then |
PowerShell Essentials
| Concept | Syntax | Example |
|---|---|---|
| Variable | $var = "value" | $target = "10.10.10.1" |
| Loop | foreach ($i in $list) | foreach ($port in 22,80,443) |
| Conditional | if ($condition) { } | if (Test-Path $file) { } |
| Pipeline | cmd1 | cmd2 | Get-Process | Where-Object {$_.CPU -gt 50} |
| Read file | Get-Content | Get-Content ips.txt | ForEach-Object { } |
| Export | Export-Csv, Out-File | $results | Export-Csv report.csv |
| Error handling | try { } catch { } | try { code } catch { Write-Error $_ } |
Why Scripting Matters in Security
Security Engineers Need Automation
Manual tasks that scripting eliminates:
| Manual Task | Time (Manual) | Time (Scripted) |
|---|---|---|
| Check 100 IPs for open ports | 2 hours | 5 minutes |
| Parse 1GB of logs for IOCs | 4 hours | 2 minutes |
| Collect system info from 50 hosts | 8 hours | 10 minutes |
| Generate security report | 1 hour | Instant |
| Validate firewall rules | 30 minutes | Seconds |
When to Use Each Language
| Scenario | Bash | PowerShell |
|---|---|---|
| Linux server administration | ✅ Primary | ⚠️ Available (pwsh) |
| Windows endpoint investigation | ❌ Limited (WSL) | ✅ Primary |
| Network reconnaissance | ✅ Excellent | ✅ Good |
| Log parsing (Linux) | ✅ Primary | ⚠️ Secondary |
| Active Directory queries | ❌ No | ✅ Primary |
| Cloud automation (AWS CLI) | ✅ Primary | ✅ Good |
| Cloud automation (Azure) | ⚠️ Limited | ✅ Primary |
| Quick one-liners | ✅ Excellent | ⚠️ Verbose |
| Complex data manipulation | ⚠️ Limited | ✅ Excellent |
The Security Automation Mindset
Before writing a script, ask:
1. Will I do this task more than once?
2. Is it error-prone when done manually?
3. Does it need to scale to many targets?
4. Does it need to be auditable/reproducible?
If YES to any → Script it!
Bash Basics for Security
Script Structure
#!/bin/bash
# Description: Security scan automation script
# Author: Security Team
# Date: 2024-01-15
# Exit on error
set -e
# Variables
TARGET=""
OUTPUT_DIR="./results"
LOG_FILE="scan.log"
# Functions
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
usage() {
echo "Usage: $0 -t <target> [-o <output_dir>]"
exit 1
}
# Parse arguments
while getopts "t:o:h" opt; do
case $opt in
t) TARGET="$OPTARG" ;;
o) OUTPUT_DIR="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
# Validate input
if [[ -z "$TARGET" ]]; then
log "ERROR: Target is required"
usage
fi
# Main logic
log "Starting scan of $TARGET"
mkdir -p "$OUTPUT_DIR"
# Your security tasks here
log "Scan complete. Results in $OUTPUT_DIR"
Essential Bash for Security
Working with Files and Directories
# Check if file exists
if [[ -f "/etc/passwd" ]]; then
echo "File exists"
fi
# Check if directory exists
if [[ -d "/var/log" ]]; then
echo "Directory exists"
fi
# Find files modified in last 24 hours (incident response)
find /var/log -type f -mtime -1
# Find files by permission (SUID hunting)
find / -perm -4000 -type f 2>/dev/null
# Secure file handling
TEMP_FILE=$(mktemp)
trap "rm -f $TEMP_FILE" EXIT
String Manipulation
# Extract domain from URL
URL="https://evil.com/malware.exe"
DOMAIN=$(echo "$URL" | awk -F/ '{print $3}')
# Check if string contains substring
if [[ "$LOG_LINE" == *"failed"* ]]; then
echo "Found failure"
fi
# Remove whitespace
CLEAN=$(echo "$DIRTY" | tr -d '[:space:]')
# Convert to lowercase
LOWER=$(echo "$INPUT" | tr '[:upper:]' '[:lower:]')
Arrays and Loops
# Define array
PORTS=(22 80 443 8080 8443)
# Loop through array
for port in "${PORTS[@]}"; do
echo "Checking port $port"
done
# Read file into loop
while IFS= read -r ip; do
echo "Processing $ip"
done < targets.txt
# Loop with counter
for i in {1..100}; do
echo "Iteration $i"
done
Process and Network Commands
# Check if process is running
if pgrep -x "nginx" > /dev/null; then
echo "Nginx is running"
fi
# Get listening ports
ss -tulnp | grep LISTEN
# Check network connections
netstat -an | grep ESTABLISHED
# DNS lookup
dig +short evil.com
# HTTP request
curl -s -o /dev/null -w "%{http_code}" https://target.com
Bash One-Liners for Security
# Find all IP addresses in a file
grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' access.log | sort -u
# Count failed SSH logins by IP
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn
# Extract URLs from file
grep -oP 'https?://[^\s"<>]+' file.txt | sort -u
# Check SSL certificate expiry
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509 -noout -dates
# Find large files (data exfil detection)
find / -type f -size +100M 2>/dev/null
# List users with bash shell
grep "/bin/bash" /etc/passwd | cut -d: -f1
# Quick port check
timeout 1 bash -c "echo >/dev/tcp/10.10.10.1/22" 2>/dev/null && echo "Open" || echo "Closed"
PowerShell Basics for Security
Script Structure
<#
.SYNOPSIS
Security investigation script
.DESCRIPTION
Collects security-relevant information from Windows systems
.PARAMETER Target
Target computer name or IP
.EXAMPLE
.\Investigate.ps1 -Target SERVER01
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Target,
[Parameter(Mandatory=$false)]
[string]$OutputPath = ".\results"
)
# Strict mode for better error catching
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# Functions
function Write-Log {
param([string]$Message)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp - $Message" | Tee-Object -FilePath "$OutputPath\investigation.log" -Append
}
function Test-AdminPrivilege {
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
# Main
try {
if (-not (Test-AdminPrivilege)) {
throw "This script requires administrator privileges"
}
Write-Log "Starting investigation of $Target"
# Create output directory
if (-not (Test-Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
# Your security tasks here
Write-Log "Investigation complete"
}
catch {
Write-Log "ERROR: $_"
throw
}
Essential PowerShell for Security
Working with Objects
# PowerShell returns objects, not text!
$processes = Get-Process
# Filter objects
$suspicious = $processes | Where-Object { $_.CPU -gt 50 -and $_.ProcessName -notlike "System*" }
# Select specific properties
$suspicious | Select-Object ProcessName, Id, CPU, Path
# Sort objects
$processes | Sort-Object CPU -Descending | Select-Object -First 10
# Group objects
Get-EventLog -LogName Security | Group-Object EventID | Sort-Object Count -Descending
Working with Event Logs
# Get failed logons (Event ID 4625)
Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4625
StartTime=(Get-Date).AddDays(-1)
} | Select-Object TimeCreated, Message
# Get successful logons (Event ID 4624)
Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4624
} -MaxEvents 100
# Search event logs for keyword
Get-WinEvent -LogName Security | Where-Object { $_.Message -like "*password*" }
# Export to CSV for analysis
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4625} |
Select-Object TimeCreated, @{N='IP';E={$_.Properties[19].Value}} |
Export-Csv failed_logons.csv -NoTypeInformation
Active Directory Queries
# Import AD module
Import-Module ActiveDirectory
# Find all domain admins
Get-ADGroupMember -Identity "Domain Admins" | Select-Object Name, SamAccountName
# Find users who haven't logged in for 90 days
$cutoff = (Get-Date).AddDays(-90)
Get-ADUser -Filter {LastLogonDate -lt $cutoff} -Properties LastLogonDate |
Select-Object Name, LastLogonDate
# Find computers with old OS
Get-ADComputer -Filter * -Properties OperatingSystem |
Where-Object { $_.OperatingSystem -like "*2008*" -or $_.OperatingSystem -like "*XP*" }
# Find accounts with passwords that don't expire
Get-ADUser -Filter {PasswordNeverExpires -eq $true} -Properties PasswordNeverExpires
# Find service accounts with SPNs (Kerberoastable)
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName
Network and System Information
# Get network connections
Get-NetTCPConnection | Where-Object State -eq 'Established' |
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, OwningProcess
# Get process with connections
Get-NetTCPConnection | ForEach-Object {
$process = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
[PSCustomObject]@{
LocalPort = $_.LocalPort
RemoteAddress = $_.RemoteAddress
RemotePort = $_.RemotePort
ProcessName = $process.ProcessName
ProcessPath = $process.Path
}
}
# Get installed software
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
# Get scheduled tasks
Get-ScheduledTask | Where-Object State -eq 'Ready' |
Select-Object TaskName, TaskPath, @{N='Actions';E={$_.Actions.Execute}}
# Get services running as non-System accounts
Get-WmiObject Win32_Service | Where-Object {
$_.StartName -ne 'LocalSystem' -and
$_.StartName -ne 'NT AUTHORITY\LocalService' -and
$_.StartName -ne 'NT AUTHORITY\NetworkService'
} | Select-Object Name, StartName, State
PowerShell One-Liners for Security
# Find files modified in last 24 hours
Get-ChildItem -Path C:\ -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-1) }
# Check for unsigned executables
Get-ChildItem C:\Windows\System32\*.exe | ForEach-Object {
$sig = Get-AuthenticodeSignature $_.FullName
if ($sig.Status -ne 'Valid') { $_.FullName }
}
# Find processes with no parent (potential injection)
Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq 0 -and $_.ProcessId -ne 0 }
# Get hash of suspicious file
Get-FileHash -Algorithm SHA256 C:\suspicious.exe
# Check for persistence in Run keys
Get-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run'
Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run'
# Find PowerShell execution in logs
Get-WinEvent -LogName 'Windows PowerShell' | Where-Object { $_.Message -like "*Invoke-*" }
Automating Reconnaissance and Scans
Bash: Network Reconnaissance Script
#!/bin/bash
# recon.sh - Automated reconnaissance script
TARGET=$1
OUTPUT_DIR="./recon_$TARGET"
if [[ -z "$TARGET" ]]; then
echo "Usage: $0 <target>"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
echo "[*] Starting reconnaissance on $TARGET"
# DNS Enumeration
echo "[*] DNS Enumeration..."
{
echo "=== DNS Records ==="
dig +short A "$TARGET"
dig +short MX "$TARGET"
dig +short NS "$TARGET"
dig +short TXT "$TARGET"
} > "$OUTPUT_DIR/dns.txt"
# Subdomain enumeration (basic)
echo "[*] Subdomain enumeration..."
for sub in www mail ftp vpn remote admin dev staging api; do
result=$(dig +short "$sub.$TARGET" 2>/dev/null)
if [[ -n "$result" ]]; then
echo "$sub.$TARGET: $result"
fi
done > "$OUTPUT_DIR/subdomains.txt"
# Port scan (top ports)
echo "[*] Port scanning..."
nmap -sV -sC -oA "$OUTPUT_DIR/nmap" "$TARGET"
# Web enumeration (if port 80/443 open)
if grep -q "80/open\|443/open" "$OUTPUT_DIR/nmap.nmap" 2>/dev/null; then
echo "[*] Web enumeration..."
# HTTP headers
curl -sI "http://$TARGET" > "$OUTPUT_DIR/http_headers.txt" 2>/dev/null
curl -sI "https://$TARGET" > "$OUTPUT_DIR/https_headers.txt" 2>/dev/null
# Robots.txt
curl -s "http://$TARGET/robots.txt" > "$OUTPUT_DIR/robots.txt" 2>/dev/null
# Directory bruteforce (if gobuster available)
if command -v gobuster &>/dev/null; then
gobuster dir -u "http://$TARGET" -w /usr/share/wordlists/dirb/common.txt -o "$OUTPUT_DIR/dirs.txt" 2>/dev/null
fi
fi
# SSL Certificate info
echo "[*] SSL Certificate check..."
echo | openssl s_client -connect "$TARGET:443" 2>/dev/null | openssl x509 -noout -text > "$OUTPUT_DIR/ssl_cert.txt" 2>/dev/null
echo "[+] Reconnaissance complete. Results in $OUTPUT_DIR"
PowerShell: Windows Host Investigation
# Investigate-Host.ps1 - Windows security investigation
param(
[Parameter(Mandatory=$false)]
[string]$ComputerName = $env:COMPUTERNAME,
[string]$OutputPath = ".\investigation_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
)
New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
Write-Host "[*] Investigating $ComputerName" -ForegroundColor Cyan
# System Information
Write-Host "[*] Collecting system information..."
Get-ComputerInfo | Out-File "$OutputPath\system_info.txt"
# User Information
Write-Host "[*] Collecting user information..."
Get-LocalUser | Select-Object Name, Enabled, LastLogon, PasswordRequired |
Export-Csv "$OutputPath\local_users.csv" -NoTypeInformation
Get-LocalGroupMember -Group "Administrators" |
Export-Csv "$OutputPath\local_admins.csv" -NoTypeInformation
# Running Processes
Write-Host "[*] Collecting process information..."
Get-Process | Select-Object ProcessName, Id, Path, Company, StartTime |
Export-Csv "$OutputPath\processes.csv" -NoTypeInformation
# Network Connections
Write-Host "[*] Collecting network connections..."
Get-NetTCPConnection | Where-Object State -eq 'Established' |
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, OwningProcess |
Export-Csv "$OutputPath\connections.csv" -NoTypeInformation
# Scheduled Tasks
Write-Host "[*] Collecting scheduled tasks..."
Get-ScheduledTask | Where-Object State -eq 'Ready' |
Select-Object TaskName, TaskPath, @{N='Actions';E={$_.Actions.Execute}} |
Export-Csv "$OutputPath\scheduled_tasks.csv" -NoTypeInformation
# Services
Write-Host "[*] Collecting services..."
Get-Service | Select-Object Name, DisplayName, Status, StartType |
Export-Csv "$OutputPath\services.csv" -NoTypeInformation
# Startup Programs
Write-Host "[*] Collecting startup programs..."
$startup = @()
$startup += Get-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run' -ErrorAction SilentlyContinue
$startup += Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' -ErrorAction SilentlyContinue
$startup | Out-File "$OutputPath\startup_programs.txt"
# Recent Security Events
Write-Host "[*] Collecting security events..."
Get-WinEvent -FilterHashtable @{LogName='Security'; StartTime=(Get-Date).AddDays(-1)} -MaxEvents 1000 -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, Message |
Export-Csv "$OutputPath\security_events.csv" -NoTypeInformation
# PowerShell History
Write-Host "[*] Collecting PowerShell history..."
$historyPath = (Get-PSReadLineOption).HistorySavePath
if (Test-Path $historyPath) {
Copy-Item $historyPath "$OutputPath\powershell_history.txt"
}
# File Hashes of Common Persistence Locations
Write-Host "[*] Collecting file hashes..."
$suspiciousPaths = @(
"$env:TEMP",
"$env:APPDATA",
"C:\Windows\Temp"
)
foreach ($path in $suspiciousPaths) {
Get-ChildItem -Path $path -File -ErrorAction SilentlyContinue |
ForEach-Object { Get-FileHash $_.FullName -ErrorAction SilentlyContinue } |
Export-Csv "$OutputPath\file_hashes_$(Split-Path $path -Leaf).csv" -Append -NoTypeInformation
}
Write-Host "[+] Investigation complete. Results in $OutputPath" -ForegroundColor Green
Bash: Mass Port Scanner
#!/bin/bash
# mass_scan.sh - Scan multiple targets from file
TARGETS_FILE=$1
PORTS="22,80,443,3389,445,3306,5432"
if [[ ! -f "$TARGETS_FILE" ]]; then
echo "Usage: $0 <targets_file>"
exit 1
fi
OUTPUT_DIR="./mass_scan_$(date +%Y%m%d)"
mkdir -p "$OUTPUT_DIR"
# Parallel scanning with GNU parallel (if available)
if command -v parallel &>/dev/null; then
cat "$TARGETS_FILE" | parallel -j 10 "nmap -Pn -p $PORTS {} -oG $OUTPUT_DIR/{}.gnmap"
else
# Sequential fallback
while read -r target; do
echo "[*] Scanning $target"
nmap -Pn -p "$PORTS" "$target" -oG "$OUTPUT_DIR/${target//\//_}.gnmap"
done < "$TARGETS_FILE"
fi
# Summary report
echo "=== Open Ports Summary ===" > "$OUTPUT_DIR/summary.txt"
grep "open" "$OUTPUT_DIR"/*.gnmap | while read -r line; do
echo "$line" >> "$OUTPUT_DIR/summary.txt"
done
echo "[+] Scan complete. Summary in $OUTPUT_DIR/summary.txt"
Log Parsing Examples
Bash: Parse Authentication Logs
#!/bin/bash
# parse_auth_logs.sh - Analyze Linux authentication logs
LOG_FILE="${1:-/var/log/auth.log}"
echo "=== Authentication Log Analysis ==="
echo "Log file: $LOG_FILE"
echo ""
# Failed SSH logins by IP
echo "--- Top 10 Failed SSH Login IPs ---"
grep "Failed password" "$LOG_FILE" |
awk '{print $(NF-3)}' |
sort | uniq -c | sort -rn | head -10
echo ""
# Successful logins
echo "--- Successful Logins ---"
grep "Accepted" "$LOG_FILE" |
awk '{print $1, $2, $3, $9, $11}' | tail -20
echo ""
# Sudo commands
echo "--- Recent Sudo Commands ---"
grep "sudo:" "$LOG_FILE" |
grep "COMMAND=" |
awk -F'COMMAND=' '{print $2}' | tail -10
echo ""
# User additions/changes
echo "--- User Account Changes ---"
grep -E "(useradd|usermod|userdel|passwd)" "$LOG_FILE" | tail -10
echo ""
# Failed login timeline (hourly)
echo "--- Failed Logins by Hour (Last 24h) ---"
grep "Failed password" "$LOG_FILE" |
awk '{print $3}' |
cut -d: -f1 |
sort | uniq -c
PowerShell: Parse Windows Event Logs
# Parse-SecurityLogs.ps1 - Analyze Windows Security Event Logs
param(
[int]$Days = 7,
[string]$OutputPath = ".\event_analysis"
)
New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
$startDate = (Get-Date).AddDays(-$Days)
Write-Host "=== Windows Security Log Analysis ===" -ForegroundColor Cyan
Write-Host "Analyzing last $Days days of events..."
# Failed Logons (4625)
Write-Host "`n--- Failed Logons (4625) ---"
$failedLogons = Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4625
StartTime=$startDate
} -ErrorAction SilentlyContinue
$failedLogons | Group-Object { $_.Properties[5].Value } | # Group by username
Sort-Object Count -Descending |
Select-Object Count, @{N='Username';E={$_.Name}} -First 10 |
Format-Table
$failedLogons | Export-Csv "$OutputPath\failed_logons.csv" -NoTypeInformation
# Successful Logons (4624)
Write-Host "--- Successful Logons (4624) ---"
$successLogons = Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4624
StartTime=$startDate
} -MaxEvents 1000 -ErrorAction SilentlyContinue
# Filter for interactive and remote logons (types 2, 10)
$interactiveLogons = $successLogons | Where-Object {
$_.Properties[8].Value -in @(2, 10)
}
$interactiveLogons | Select-Object TimeCreated,
@{N='User';E={$_.Properties[5].Value}},
@{N='LogonType';E={$_.Properties[8].Value}},
@{N='SourceIP';E={$_.Properties[18].Value}} |
Export-Csv "$OutputPath\successful_logons.csv" -NoTypeInformation
Write-Host "Interactive logons: $($interactiveLogons.Count)"
# Account Lockouts (4740)
Write-Host "`n--- Account Lockouts (4740) ---"
$lockouts = Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4740
StartTime=$startDate
} -ErrorAction SilentlyContinue
if ($lockouts) {
$lockouts | Select-Object TimeCreated,
@{N='User';E={$_.Properties[0].Value}},
@{N='Computer';E={$_.Properties[1].Value}} |
Format-Table
}
# Privilege Escalation Events (4672, 4673)
Write-Host "--- Privilege Use Events ---"
$privEvents = Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4672
StartTime=$startDate
} -MaxEvents 500 -ErrorAction SilentlyContinue
$privEvents | Group-Object { $_.Properties[1].Value } |
Sort-Object Count -Descending |
Select-Object Count, @{N='User';E={$_.Name}} -First 10 |
Format-Table
# Process Creation (4688) - requires advanced auditing
Write-Host "--- Process Creation Events (4688) ---"
$processEvents = Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4688
StartTime=$startDate
} -MaxEvents 500 -ErrorAction SilentlyContinue
if ($processEvents) {
$processEvents | Select-Object TimeCreated,
@{N='User';E={$_.Properties[1].Value}},
@{N='Process';E={$_.Properties[5].Value}},
@{N='CommandLine';E={$_.Properties[8].Value}} |
Export-Csv "$OutputPath\process_creation.csv" -NoTypeInformation
Write-Host "Process creation events: $($processEvents.Count)"
}
Write-Host "`n[+] Analysis complete. Reports in $OutputPath" -ForegroundColor Green
Bash: Parse Web Server Logs
#!/bin/bash
# parse_web_logs.sh - Analyze Apache/Nginx access logs
LOG_FILE="${1:-/var/log/apache2/access.log}"
echo "=== Web Server Log Analysis ==="
# Top IPs
echo "--- Top 10 Source IPs ---"
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10
# Top requested paths
echo -e "\n--- Top 10 Requested Paths ---"
awk '{print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10
# HTTP status codes distribution
echo -e "\n--- HTTP Status Codes ---"
awk '{print $9}' "$LOG_FILE" | sort | uniq -c | sort -rn
# 404 errors (potential reconnaissance)
echo -e "\n--- Top 10 404 Requests ---"
awk '$9 == 404 {print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10
# Potential SQL injection attempts
echo -e "\n--- Potential SQL Injection Attempts ---"
grep -iE "(union|select|insert|update|delete|drop|'|--|;)" "$LOG_FILE" | head -10
# Potential XSS attempts
echo -e "\n--- Potential XSS Attempts ---"
grep -iE "(<script|javascript:|onerror|onload)" "$LOG_FILE" | head -10
# Large responses (potential data exfiltration)
echo -e "\n--- Largest Responses ---"
awk '{print $10, $7}' "$LOG_FILE" | sort -rn | head -10
# User agents
echo -e "\n--- Top User Agents ---"
awk -F'"' '{print $6}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -10
Red Team vs Blue Team Use Cases
Red Team Scripts
Bash: Quick Host Enumeration
#!/bin/bash
# redteam_enum.sh - Post-exploitation enumeration
echo "=== System Information ==="
hostname
uname -a
cat /etc/os-release 2>/dev/null
echo -e "\n=== Current User ==="
id
whoami
echo -e "\n=== Interesting Files ==="
ls -la /home/
cat /etc/passwd
cat /etc/crontab
echo -e "\n=== Network ==="
ip a
ss -tulnp
cat /etc/hosts
echo -e "\n=== SUID Binaries ==="
find / -perm -4000 -type f 2>/dev/null
echo -e "\n=== Writable Directories ==="
find / -writable -type d 2>/dev/null | head -20
echo -e "\n=== Running Processes ==="
ps auxf
echo -e "\n=== Sudo Permissions ==="
sudo -l 2>/dev/null
PowerShell: Domain Enumeration
# redteam_ad_enum.ps1 - Active Directory enumeration
Write-Host "=== Domain Information ===" -ForegroundColor Red
$domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$domain
Write-Host "`n=== Current User Privileges ===" -ForegroundColor Red
whoami /all
Write-Host "`n=== Domain Admins ===" -ForegroundColor Red
net group "Domain Admins" /domain
Write-Host "`n=== Domain Controllers ===" -ForegroundColor Red
nltest /dclist:$($domain.Name)
Write-Host "`n=== Interesting Shares ===" -ForegroundColor Red
net view /domain
Write-Host "`n=== Kerberoastable Accounts ===" -ForegroundColor Red
# Requires AD module or direct LDAP
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName 2>$null
Write-Host "`n=== Computers in Domain ===" -ForegroundColor Red
Get-ADComputer -Filter * | Select-Object Name, DNSHostName 2>$null
Blue Team Scripts
Bash: Threat Hunting Script
#!/bin/bash
# blueteam_hunt.sh - Linux threat hunting
OUTPUT_DIR="./hunt_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTPUT_DIR"
echo "[*] Starting threat hunt..."
# Check for unexpected users
echo "[*] Checking users..."
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd > "$OUTPUT_DIR/users.txt"
awk -F: '$3 == 0 {print}' /etc/passwd > "$OUTPUT_DIR/uid0_users.txt"
# Check for unusual processes
echo "[*] Checking processes..."
ps auxf > "$OUTPUT_DIR/processes.txt"
# Processes running from /tmp or /dev/shm
ps aux | awk '$11 ~ /^\/tmp|^\/dev\/shm/ {print}' > "$OUTPUT_DIR/suspicious_processes.txt"
# Check network connections
echo "[*] Checking network..."
ss -tulnp > "$OUTPUT_DIR/listening_ports.txt"
ss -tnp | grep ESTABLISHED > "$OUTPUT_DIR/established_connections.txt"
# Check cron jobs
echo "[*] Checking cron..."
for user in $(cut -d: -f1 /etc/passwd); do
crontab -l -u "$user" 2>/dev/null
done > "$OUTPUT_DIR/cron_jobs.txt"
cat /etc/cron.* > "$OUTPUT_DIR/system_cron.txt" 2>/dev/null
# Check for suspicious files
echo "[*] Checking suspicious files..."
find /tmp /dev/shm /var/tmp -type f -executable 2>/dev/null > "$OUTPUT_DIR/executable_temp.txt"
find / -name ".*" -type f 2>/dev/null | head -100 > "$OUTPUT_DIR/hidden_files.txt"
# Check SSH authorized keys
echo "[*] Checking SSH keys..."
find /home -name "authorized_keys" -exec cat {} \; 2>/dev/null > "$OUTPUT_DIR/authorized_keys.txt"
find /root -name "authorized_keys" -exec cat {} \; 2>/dev/null >> "$OUTPUT_DIR/authorized_keys.txt"
# Check for persistence
echo "[*] Checking persistence mechanisms..."
cat /etc/rc.local 2>/dev/null > "$OUTPUT_DIR/rc_local.txt"
systemctl list-unit-files --type=service | grep enabled > "$OUTPUT_DIR/enabled_services.txt"
echo "[+] Hunt complete. Results in $OUTPUT_DIR"
PowerShell: Incident Response Collector
# blueteam_ir.ps1 - Windows incident response collection
param(
[string]$OutputPath = ".\IR_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
)
$ErrorActionPreference = "SilentlyContinue"
New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
Write-Host "[*] Starting IR collection..." -ForegroundColor Blue
# System Info
Write-Host "[*] Collecting system info..."
Get-ComputerInfo | Out-File "$OutputPath\system_info.txt"
systeminfo | Out-File "$OutputPath\systeminfo.txt"
# Running Processes with full paths
Write-Host "[*] Collecting processes..."
Get-Process | Select-Object Name, Id, Path, StartTime, Company |
Export-Csv "$OutputPath\processes.csv" -NoTypeInformation
# Process with command lines (WMI)
Get-WmiObject Win32_Process |
Select-Object Name, ProcessId, ParentProcessId, CommandLine, ExecutablePath |
Export-Csv "$OutputPath\processes_wmi.csv" -NoTypeInformation
# Network Connections with process info
Write-Host "[*] Collecting network connections..."
Get-NetTCPConnection | ForEach-Object {
$proc = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
[PSCustomObject]@{
LocalAddress = $_.LocalAddress
LocalPort = $_.LocalPort
RemoteAddress = $_.RemoteAddress
RemotePort = $_.RemotePort
State = $_.State
ProcessName = $proc.ProcessName
ProcessPath = $proc.Path
}
} | Export-Csv "$OutputPath\connections.csv" -NoTypeInformation
# Persistence Mechanisms
Write-Host "[*] Collecting persistence mechanisms..."
# Registry Run Keys
$runKeys = @(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run',
'HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce',
'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run',
'HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce'
)
$runKeys | ForEach-Object {
Get-ItemProperty -Path $_ 2>$null
} | Out-File "$OutputPath\run_keys.txt"
# Scheduled Tasks
Get-ScheduledTask | Where-Object { $_.State -eq 'Ready' } |
ForEach-Object {
[PSCustomObject]@{
Name = $_.TaskName
Path = $_.TaskPath
Action = ($_.Actions | ForEach-Object { $_.Execute + " " + $_.Arguments }) -join "; "
Trigger = ($_.Triggers | ForEach-Object { $_.ToString() }) -join "; "
}
} | Export-Csv "$OutputPath\scheduled_tasks.csv" -NoTypeInformation
# Services
Get-WmiObject Win32_Service |
Select-Object Name, DisplayName, State, StartMode, StartName, PathName |
Export-Csv "$OutputPath\services.csv" -NoTypeInformation
# Recent Security Events
Write-Host "[*] Collecting security events..."
Get-WinEvent -LogName Security -MaxEvents 5000 |
Select-Object TimeCreated, Id, LevelDisplayName, Message |
Export-Csv "$OutputPath\security_events.csv" -NoTypeInformation
# PowerShell Event Logs
Get-WinEvent -LogName 'Windows PowerShell' -MaxEvents 1000 |
Export-Csv "$OutputPath\powershell_events.csv" -NoTypeInformation
# DNS Cache
Get-DnsClientCache | Export-Csv "$OutputPath\dns_cache.csv" -NoTypeInformation
# ARP Cache
Get-NetNeighbor | Export-Csv "$OutputPath\arp_cache.csv" -NoTypeInformation
# Prefetch (evidence of execution)
Write-Host "[*] Collecting prefetch files..."
Get-ChildItem C:\Windows\Prefetch\*.pf -ErrorAction SilentlyContinue |
Select-Object Name, LastWriteTime, Length |
Export-Csv "$OutputPath\prefetch.csv" -NoTypeInformation
# Browser History (Chrome)
$chromeHistory = "$env:LOCALAPPDATA\Google\Chrome\User Data\Default\History"
if (Test-Path $chromeHistory) {
Copy-Item $chromeHistory "$OutputPath\chrome_history.sqlite" -Force
}
Write-Host "[+] IR collection complete. Results in $OutputPath" -ForegroundColor Green
Hands-On Labs
Lab 1: Bash Reconnaissance Script
Objective: Create a script that enumerates a target network.
# Create a file: lab1_recon.sh
# Requirements:
# 1. Accept target IP/range as argument
# 2. Perform ping sweep
# 3. Port scan live hosts
# 4. Save results to timestamped directory
# Starter code:
#!/bin/bash
TARGET=${1:?"Usage: $0 <target>"}
OUTPUT_DIR="recon_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTPUT_DIR"
# TODO: Implement ping sweep
# TODO: Implement port scan
# TODO: Generate summary report
Solution approach:
- Use
pingornmap -snfor host discovery - Use
nmapwith service detection - Parse and format results
Lab 2: PowerShell Event Log Parser
Objective: Create a script that finds suspicious Windows events.
# Create a file: Lab2-EventParser.ps1
# Requirements:
# 1. Find failed logons in last 24 hours
# 2. Group by source IP
# 3. Alert if any IP has > 10 failures
# 4. Export results
# Starter code:
param([int]$Threshold = 10)
$failedLogons = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4625
StartTime = (Get-Date).AddDays(-1)
}
# TODO: Extract source IPs
# TODO: Count per IP
# TODO: Alert on threshold
# TODO: Export report
Interview Questions & Answers
Basic Questions
Q1: Why is scripting important for security engineers?
Strong Answer: “Scripting is essential because security work involves repetitive tasks at scale. You might need to:
- Scan hundreds of hosts for vulnerabilities
- Parse gigabytes of logs for indicators of compromise
- Collect forensic artifacts from multiple systems
- Automate compliance checks across infrastructure
Manual execution is slow, error-prone, and doesn’t scale. A 4-hour manual task might take 5 minutes scripted. Additionally, scripts provide reproducibility and documentation of exactly what was done.”
Q2: When would you choose Bash over PowerShell?
Strong Answer: “Bash is my choice for:
- Linux/Unix server administration and security
- Quick one-liners and text processing with pipes
- Network reconnaissance using native tools
- Log parsing on Linux systems
PowerShell is better for:
- Windows endpoint investigation
- Active Directory enumeration and auditing
- Working with structured objects (not just text)
- Azure cloud automation
For cross-platform needs, Python might be the best choice.”
Intermediate Questions
Q3: How would you write a script to detect brute-force attacks?
Strong Answer: “I’d approach it differently for each OS:
Linux (Bash):
grep 'Failed password' /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | awk '$1 > 10 {print "ALERT:", $2, $1, "attempts"}'Windows (PowerShell):
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} | Group-Object {$_.Properties[19].Value} | Where-Object Count -gt 10 | Select-Object Count, NameThe key elements are: identify the right log source, extract the attacker IP, count occurrences, and alert on threshold.”
Q4: How do you handle errors in your security scripts?
Strong Answer: “Error handling is critical in security scripts because silent failures could mean missed threats.
Bash:
- Use
set -eto exit on error- Use
set -o pipefailto catch errors in pipelines- Check
$?after critical commands- Use
trapfor cleanup on exitPowerShell:
- Set
$ErrorActionPreference = 'Stop'for critical scripts- Use
try/catch/finallyblocks- Log errors with timestamps
- Validate inputs with parameter validation
I also ensure scripts fail loudly rather than silently continuing with incomplete data.”
Advanced Questions
Q5: Describe a complex automation task you’ve built.
Strong Answer: “I built an automated threat hunting framework that:
- Collected - Gathered process lists, network connections, and scheduled tasks from all domain workstations via PowerShell remoting
- Normalized - Standardized data into consistent CSV format
- Analyzed - Compared against known-good baselines and threat intel IOCs
- Alerted - Generated alerts for anomalies like unsigned executables, unusual network connections, or persistence mechanisms
- Reported - Created daily summary reports for the SOC
The challenge was handling thousands of endpoints efficiently. I used PowerShell jobs for parallelization and implemented error handling for offline or unreachable systems.”
Q6: How would you ensure your security scripts don’t become attack tools?
Strong Answer: “This is an important consideration. I implement several controls:
- Least privilege - Scripts run with minimum necessary permissions
- Logging - All script executions are logged with timestamp, user, and target
- Input validation - Sanitize all inputs to prevent injection
- Code signing - Sign scripts and enforce execution policy
- Access control - Store scripts in protected locations with limited access
- No hardcoded credentials - Use secure vaults or integrated authentication
- Review process - Peer review before deployment
The goal is that even if the script is obtained by an attacker, it’s less useful without the authorized context.”
Glossary
| Term | Definition |
|---|---|
| Shebang | #!/bin/bash - Specifies script interpreter |
| Pipeline | Connecting commands with | to pass output |
| Cmdlet | PowerShell’s native commands (Verb-Noun format) |
| PSObject | PowerShell’s structured data object |
| Regex | Regular expressions for pattern matching |
| STDIN/STDOUT | Standard input/output streams |
| Exit Code | Numeric return value (0 = success) |
| Here-String | Multi-line string (@" "@ in PS, <<EOF in Bash) |
What’s Next
Continue building your automation skills with:
- Git for Security Engineers - Version control for scripts
- Linux Hardening - Apply what you automate
- Detection Engineering Basics - Automate threat detection
Questions or feedback? Open an issue on GitHub.