🔒 Advanced Security and Sandboxing
Implement robust security measures and sandboxing techniques to protect shell scripts from malicious input, privilege escalation, and unauthorized access.
🧭 Security Fundamentals
Shell scripts face unique security challenges due to their system-level access and interpreted nature. Key threats include:
Attack Vectors
- Input Injection - Command, path, or code injection through user input
- Privilege Escalation - Exploiting elevated permissions
- Information Disclosure - Unauthorized access to sensitive data
- Denial of Service - Resource exhaustion attacks
- Side Channel Attacks - Timing or error-based information leakage
Security Principles
- Least Privilege - Run with minimal necessary permissions
- Input Validation - Sanitize all external data
- Defense in Depth - Multiple layers of protection
- Fail Secure - Default to safe failure modes
- Principle of Least Astonishment - Predictable, secure behavior
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 | # Comprehensive input validation framework
validate_input() {
local input_type="$1"
local input_value="$2"
case "$input_type" in
filename)
# Prevent path traversal and special characters
if echo "$input_value" | grep -E '[/\\.][/.]|^\.\.?$|[*?[]' >/dev/null; then
echo "Invalid filename: contains dangerous characters" >&2
return 1
fi
# Limit length
if [ ${#input_value} -gt 255 ]; then
echo "Invalid filename: too long" >&2
return 1
fi
# Check for allowed characters only
if echo "$input_value" | grep -E '[^a-zA-Z0-9._-]' >/dev/null; then
echo "Invalid filename: contains invalid characters" >&2
return 1
fi
;;
filepath)
# Validate absolute or relative paths
if echo "$input_value" | grep -E '(\.\./)|(\.\.\\)' >/dev/null; then
echo "Invalid filepath: path traversal attempt" >&2
return 1
fi
# Check components
IFS='/' read -ra components <<< "$input_value"
for component in "${components[@]}"; do
if [ -n "$component" ] && ! validate_input "filename" "$component"; then
return 1
fi
done
;;
alphanumeric)
if echo "$input_value" | grep -E '[^a-zA-Z0-9]' >/dev/null; then
echo "Invalid input: non-alphanumeric characters" >&2
return 1
fi
;;
numeric)
if ! echo "$input_value" | grep -E '^[0-9]+$' >/dev/null; then
echo "Invalid input: not a valid number" >&2
return 1
fi
# Check range if specified
local min="${3:-0}"
local max="${4:-999999999}"
if [ "$input_value" -lt "$min" ] || [ "$input_value" -gt "$max" ]; then
echo "Invalid input: number out of range [$min-$max]" >&2
return 1
fi
;;
url)
# Basic URL validation
if ! echo "$input_value" | grep -E '^https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9._-]*)*$' >/dev/null; then
echo "Invalid input: malformed URL" >&2
return 1
fi
;;
*)
echo "Unknown input type: $input_type" >&2
return 1
;;
esac
return 0
}
# Usage examples
# validate_input "filename" "config.txt" || exit 1
# validate_input "numeric" "42" 0 100 || exit 1
|
Safe Command Construction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | # Secure command building patterns
# ❌ Dangerous - direct variable interpolation
dangerous_command() {
local filename="$1"
rm -f /tmp/$filename # Vulnerable to path traversal
}
# ✅ Safe - input validation and quoting
safe_command() {
local filename="$1"
# Validate input
validate_input "filename" "$filename" || return 1
# Use full path and quote properly
local safe_path="/tmp/$filename"
rm -f "$safe_path"
}
# ✅ Even safer - whitelist approach
whitelist_command() {
local allowed_files="file1.txt file2.log config.ini"
local requested_file="$1"
# Check against whitelist
if ! echo " $allowed_files " | grep -F " $requested_file " >/dev/null; then
echo "File not in whitelist: $requested_file" >&2
return 1
fi
rm -f "/tmp/$requested_file"
}
|
🧠 Privilege Management
Dropping Privileges
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | # Secure privilege dropping pattern
drop_privileges() {
local target_user="${1:-nobody}"
local target_group="${2:-nogroup}"
# Only drop if running as root
if [ "$(id -u)" -ne 0 ]; then
echo "Not running as root, skipping privilege drop" >&2
return 0
fi
# Validate target user/group exist
if ! getent passwd "$target_user" >/dev/null 2>&1; then
echo "Target user does not exist: $target_user" >&2
return 1
fi
if ! getent group "$target_group" >/dev/null 2>&1; then
echo "Target group does not exist: $target_group" >&2
return 1
fi
# Drop privileges
echo "Dropping privileges to $target_user:$target_group" >&2
# Change directory to avoid permission issues
cd / || return 1
# Drop group first, then user
if ! exec sg "$target_group" -c "exec su -s /bin/sh '$target_user' -c 'exec \"$0\" \"\$@\"'" -- "$@"; then
echo "Failed to drop privileges" >&2
return 1
fi
}
# Usage at script start
# if [ "$(id -u)" -eq 0 ]; then
# drop_privileges "appuser" "appgroup"
# fi
|
Capability-Based Access Control
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 | # Fine-grained capability management
capability_manager() {
# Define required capabilities
local required_caps=""
# Check available capabilities
check_capabilities() {
if command -v capsh >/dev/null 2>&1; then
capsh --print | grep -E 'Current:|Bounding set:'
else
echo "Capability checking not available" >&2
fi
}
# Request specific capabilities
request_capability() {
local cap="$1"
local purpose="$2"
echo "Requesting capability: $cap ($purpose)" >&2
# Implementation depends on system (Linux capabilities, etc.)
case "$cap" in
net_bind_service)
# Check if we can bind to privileged ports
if [ "$(id -u)" -ne 0 ] && [ "${PORT:-8080}" -lt 1024 ]; then
echo "Need root privileges to bind to port ${PORT:-80}" >&2
return 1
fi
;;
dac_override)
# Check file access permissions
if [ ! -w "/etc" ]; then
echo "Insufficient file permissions" >&2
return 1
fi
;;
esac
}
}
|
🧪 Secure File Operations
Atomic File Operations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 | # Secure atomic file writing
atomic_write() {
local target_file="$1"
local content="$2"
local temp_file
local target_dir
# Validate target directory
target_dir=$(dirname "$target_file")
if [ ! -d "$target_dir" ] || [ ! -w "$target_dir" ]; then
echo "Cannot write to directory: $target_dir" >&2
return 1
fi
# Create temporary file in same directory
temp_file=$(mktemp "${target_file}_XXXXXX" 2>/dev/null)
if [ -z "$temp_file" ]; then
echo "Failed to create temporary file" >&2
return 1
fi
# Write content to temporary file
echo "$content" > "$temp_file" || {
rm -f "$temp_file"
echo "Failed to write to temporary file" >&2
return 1
}
# Atomically move to target location
if ! mv "$temp_file" "$target_file"; then
rm -f "$temp_file"
echo "Failed to move temporary file to target" >&2
return 1
fi
echo "Successfully wrote to $target_file" >&2
return 0
}
# Secure configuration file update
update_config_secure() {
local config_file="$1"
local new_setting="$2"
# Backup existing config
local backup_file="${config_file}.backup.$(date +%s)"
if [ -f "$config_file" ]; then
cp "$config_file" "$backup_file" || {
echo "Failed to create backup" >&2
return 1
}
fi
# Update configuration atomically
if ! atomic_write "$config_file" "$new_setting"; then
# Restore backup on failure
if [ -f "$backup_file" ]; then
mv "$backup_file" "$config_file"
fi
return 1
fi
# Remove backup on success
rm -f "$backup_file"
return 0
}
|
Secure Temporary Files
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 | # Secure temporary file management
secure_temp_manager() {
# Create secure temporary directory
create_secure_temp_dir() {
local base_dir="${TMPDIR:-/tmp}"
local temp_dir
temp_dir=$(mktemp -d "${base_dir}/XXXXXXXX" 2>/dev/null)
if [ -z "$temp_dir" ]; then
echo "Failed to create temporary directory" >&2
return 1
fi
# Set restrictive permissions
chmod 700 "$temp_dir" || {
rm -rf "$temp_dir"
echo "Failed to set permissions on temporary directory" >&2
return 1
}
echo "$temp_dir"
return 0
}
# Secure temporary file creation
create_secure_temp_file() {
local suffix="${1:-}"
local temp_file
temp_file=$(mktemp "${TMPDIR:-/tmp}/XXXXXXXX${suffix}" 2>/dev/null)
if [ -z "$temp_file" ]; then
echo "Failed to create temporary file" >&2
return 1
fi
# Set restrictive permissions
chmod 600 "$temp_file" || {
rm -f "$temp_file"
echo "Failed to set permissions on temporary file" >&2
return 1
}
echo "$temp_file"
return 0
}
# Cleanup function
cleanup_temp() {
local temp_path="$1"
if [ -n "$temp_path" ] && [ -e "$temp_path" ]; then
rm -rf "$temp_path"
fi
}
}
|
🧠 Sandboxing Techniques
Namespace Isolation (Linux)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 | # Linux namespace-based sandboxing
linux_sandbox() {
# Check if running in container/namespace
is_sandboxed() {
if [ -f /.dockerenv ] || [ -f /run/.containerenv ]; then
return 0
fi
# Check cgroup
if [ -f /proc/1/cgroup ]; then
if ! grep -q ':/docker/' /proc/1/cgroup 2>/dev/null; then
return 1
fi
fi
return 0
}
# Create network namespace
create_network_sandbox() {
if ! command -v unshare >/dev/null 2>&1; then
echo "unshare command not available" >&2
return 1
fi
# Create isolated network namespace
unshare -n -- sh -c '
# Bring up loopback interface
ip link set lo up 2>/dev/null || true
# Execute sandboxed command
exec "$@"
' -- "$@"
}
# Create mount namespace
create_mount_sandbox() {
unshare -m -- sh -c '
# Make mount point private
mount --make-rprivate /
# Create temporary overlay
local temp_dir=$(mktemp -d)
mkdir -p "$temp_dir/upper" "$temp_dir/work" "$temp_dir/merged"
# Mount overlayfs (if available)
if mount -t overlay overlay \
-o lowerdir=/,upperdir="$temp_dir/upper",workdir="$temp_dir/work" \
"$temp_dir/merged" 2>/dev/null; then
# Change root to overlay
cd "$temp_dir/merged"
pivot_root . old_root
exec chroot . "$@"
else
# Fallback: just run in separate mount namespace
exec "$@"
fi
' -- "$@"
}
}
|
Chroot Sandboxing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 | # Chroot-based sandboxing
chroot_sandbox() {
# Create minimal chroot environment
create_chroot_env() {
local chroot_dir="$1"
local required_bins="/bin/sh /bin/ls /usr/bin/id /bin/cat"
# Create directory structure
mkdir -p "$chroot_dir"/{bin,usr/bin,lib,lib64,etc,tmp,proc,dev}
# Copy required binaries and their dependencies
for bin in $required_bins; do
if [ -f "$bin" ]; then
# Copy binary
cp "$bin" "$chroot_dir$bin"
# Copy dependencies (simplified - real implementation needs ldd)
ldd "$bin" 2>/dev/null | grep -o '/[^ ]*' | while read -r lib; do
if [ -f "$lib" ]; then
local lib_dir
lib_dir=$(dirname "$lib")
mkdir -p "$chroot_dir$lib_dir"
cp "$lib" "$chroot_dir$lib"
fi
done
fi
done
# Create basic config files
echo "root:x:0:0:root:/root:/bin/sh" > "$chroot_dir/etc/passwd"
echo "root:x:0:" > "$chroot_dir/etc/group"
echo "Chroot environment created at $chroot_dir" >&2
}
# Execute in chroot
run_in_chroot() {
local chroot_dir="$1"
shift
# Validate chroot directory
if [ ! -d "$chroot_dir" ]; then
echo "Chroot directory does not exist: $chroot_dir" >&2
return 1
fi
# Execute in chroot
chroot "$chroot_dir" "$@"
}
}
|
🧪 Secure Communication
Encrypted Data Handling
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 | # Secure data encryption/decryption
secure_crypto() {
# Encrypt file with GPG
encrypt_file() {
local input_file="$1"
local output_file="${2:-$input_file.gpg}"
local recipient="$3"
# Validate inputs
if [ ! -f "$input_file" ]; then
echo "Input file not found: $input_file" >&2
return 1
fi
if [ -z "$recipient" ]; then
echo "Recipient not specified" >&2
return 1
fi
# Encrypt
if ! gpg --encrypt --recipient "$recipient" --output "$output_file" "$input_file"; then
echo "Encryption failed" >&2
return 1
fi
echo "File encrypted: $output_file" >&2
return 0
}
# Decrypt file with GPG
decrypt_file() {
local input_file="$1"
local output_file="${2:-${input_file%.gpg}}"
# Validate input
if [ ! -f "$input_file" ]; then
echo "Input file not found: $input_file" >&2
return 1
fi
# Decrypt
if ! gpg --decrypt --output "$output_file" "$input_file"; then
echo "Decryption failed" >&2
return 1
fi
echo "File decrypted: $output_file" >&2
return 0
}
# Secure password handling
get_secure_password() {
local prompt="${1:-Enter password:}"
# Use system password prompt if available
if command -v dialog >/dev/null 2>&1; then
dialog --passwordbox "$prompt" 8 40 2>/dev/null
elif command -v whiptail >/dev/null 2>&1; then
whiptail --passwordbox "$prompt" 8 40 3>&1 1>&2 2>&3
else
# Fallback to read with echo disabled
local password
trap 'stty echo' EXIT
stty -echo
printf "%s" "$prompt" >&2
read -r password
stty echo
echo >&2
echo "$password"
fi
}
}
|
Secure Network Operations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 | # Secure network communication
secure_network() {
# Download file with integrity verification
secure_download() {
local url="$1"
local output_file="$2"
local expected_hash="${3:-}"
# Validate URL
if ! echo "$url" | grep -E '^https://' >/dev/null; then
echo "Only HTTPS URLs are allowed" >&2
return 1
fi
# Download with curl
if ! curl -sfL --retry 3 --retry-delay 2 "$url" -o "$output_file"; then
echo "Download failed" >&2
return 1
fi
# Verify hash if provided
if [ -n "$expected_hash" ]; then
local actual_hash
actual_hash=$(sha256sum "$output_file" | cut -d' ' -f1)
if [ "$actual_hash" != "$expected_hash" ]; then
echo "Hash verification failed" >&2
echo "Expected: $expected_hash" >&2
echo "Actual: $actual_hash" >&2
rm -f "$output_file"
return 1
fi
fi
echo "Download completed successfully" >&2
return 0
}
# Secure API call with authentication
secure_api_call() {
local url="$1"
local api_key="$2"
local method="${3:-GET}"
# Validate inputs
if ! echo "$url" | grep -E '^https://' >/dev/null; then
echo "Only HTTPS URLs are allowed" >&2
return 1
fi
if [ -z "$api_key" ]; then
echo "API key required" >&2
return 1
fi
# Make API call
local response
response=$(curl -sf -X "$method" \
-H "Authorization: Bearer $api_key" \
-H "User-Agent: SecureClient/1.0" \
"$url")
local exit_code=$?
if [ $exit_code -ne 0 ]; then
echo "API call failed with code: $exit_code" >&2
return $exit_code
fi
echo "$response"
return 0
}
}
|
🧠 Security Auditing and Monitoring
Runtime Security Monitoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 | # Security monitoring framework
security_monitor() {
# Monitor file access
monitor_file_access() {
local target_dir="$1"
# Use inotify if available
if command -v inotifywait >/dev/null 2>&1; then
inotifywait -m -r -e access,modify,create,delete "$target_dir" 2>/dev/null | while read -r path action file; do
echo "SECURITY ALERT: $action on $path$file at $(date)" >&2
# Log to security log
logger -t "SECURITY" "File access: $action on $path$file"
done
else
echo "inotifywait not available for monitoring" >&2
fi
}
# Monitor process creation
monitor_processes() {
# Simple process monitoring
local baseline_pids
baseline_pids=$(pgrep -f "$$")
while true; do
local current_pids
current_pids=$(pgrep -f "$$")
# Check for new processes
for pid in $current_pids; do
if ! echo " $baseline_pids " | grep -F " $pid " >/dev/null; then
echo "SECURITY ALERT: New process created: $pid ($(ps -p $pid -o comm= 2>/dev/null))" >&2
logger -t "SECURITY" "New process: $pid"
fi
done
sleep 5
done
}
# Integrity checking
integrity_check() {
local target_file="$1"
local hash_file="${target_file}.hash"
# Create hash if it doesn't exist
if [ ! -f "$hash_file" ]; then
if [ -f "$target_file" ]; then
sha256sum "$target_file" > "$hash_file"
echo "Created integrity hash for $target_file" >&2
fi
return 0
fi
# Verify integrity
if [ -f "$target_file" ]; then
local current_hash
current_hash=$(sha256sum "$target_file" | cut -d' ' -f1)
local expected_hash
expected_hash=$(cut -d' ' -f1 "$hash_file")
if [ "$current_hash" != "$expected_hash" ]; then
echo "SECURITY ALERT: File integrity compromised: $target_file" >&2
logger -t "SECURITY" "Integrity violation: $target_file"
return 1
fi
fi
return 0
}
}
|
Security Logging
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 | # Secure logging system
secure_logging() {
# Structured security logging
security_log() {
local level="$1"
local message="$2"
shift 2
local timestamp
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
local log_entry
log_entry="{\"timestamp\":\"$timestamp\",\"level\":\"$level\",\"message\":\"$message\",\"pid\":$$,\"user\":\"$(whoami)\",\"host\":\"$(hostname)\"}"
# Log to secure facility
logger -p auth.notice -t "SECURITY" "$log_entry"
# Also log to stderr in development
if [ "${SECURITY_DEBUG:-false}" = true ]; then
echo "[SECURITY] $level: $message" >&2
fi
}
# Alert functions
security_alert() {
security_log "ALERT" "$@"
}
security_warning() {
security_log "WARNING" "$@"
}
security_info() {
security_log "INFO" "$@"
}
# Emergency response
security_emergency() {
local message="$1"
security_log "EMERGENCY" "$message"
# Send alert to administrators
if [ -n "${SECURITY_ALERT_EMAIL:-}" ]; then
echo "SECURITY EMERGENCY: $message" | mail -s "Security Alert" "$SECURITY_ALERT_EMAIL"
fi
# Execute emergency response script if defined
if [ -n "${SECURITY_EMERGENCY_SCRIPT:-}" ] && [ -x "$SECURITY_EMERGENCY_SCRIPT" ]; then
"$SECURITY_EMERGENCY_SCRIPT" "$message"
fi
}
}
|
🧾 Security Best Practices
Security Checklist
- Input Validation
- [ ] All external input is validated
- [ ] Path traversal prevented
- [ ] Command injection protected
-
[ ] SQL injection prevented
-
Privilege Management
- [ ] Run with least privileges
- [ ] Drop privileges when possible
- [ ] Validate user permissions
-
[ ] Use capability-based access
-
File Security
- [ ] Secure temporary file creation
- [ ] Atomic file operations
- [ ] Proper file permissions
-
[ ] Secure configuration handling
-
Communication Security
- [ ] Use HTTPS for network calls
- [ ] Validate SSL certificates
- [ ] Encrypt sensitive data
-
[ ] Secure credential storage
-
Monitoring and Auditing
- [ ] Log security events
- [ ] Monitor file access
- [ ] Verify file integrity
- [ ] Alert on suspicious activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | # Security scanning integration
security_scan() {
local target_dir="${1:-.}"
# ShellCheck for security issues
if command -v shellcheck >/dev/null 2>&1; then
echo "Running ShellCheck security scan..." >&2
shellcheck -x -f gcc "$target_dir"/*.sh
fi
# Bandit-like scanning for shell scripts
echo "Scanning for common security issues..." >&2
find "$target_dir" -name "*.sh" -type f | while read -r script; do
# Check for dangerous patterns
if grep -n "eval\|exec\|system" "$script"; then
echo "WARNING: Potentially dangerous functions in $script" >&2
fi
# Check for hardcoded credentials
if grep -n -i "password\|secret\|key" "$script" | grep -v "#.*\(password\|secret\|key\)"; then
echo "WARNING: Possible hardcoded credentials in $script" >&2
fi
done
}
|
🧾 Summary
Key Security Principles
- Defense in Depth - Multiple layers of protection
- Least Privilege - Minimal necessary permissions
- Fail Secure - Default to safe failure modes
- Input Sanitization - Validate all external data
- Secure Defaults - Safe configuration out of the box
Advanced Security Techniques
- Input validation frameworks - Comprehensive sanitization
- Privilege dropping - Reduce attack surface
- Atomic operations - Prevent partial updates
- Sandboxing - Isolate potentially dangerous code
- Secure communication - Encryption and authentication
- Runtime monitoring - Detect suspicious activity
- Integrity checking - Verify file authenticity
Security Anti-Patterns to Avoid
- Trusting external input without validation
- Running with excessive privileges
- Using weak or no authentication
- Storing credentials in plain text
- Ignoring security warnings
- Not logging security events
- Failing to monitor file access
- Using deprecated or insecure protocols
- ShellCheck - Static analysis for security issues
- Bandit - Security-oriented static analyzer
- ClamAV - Malware detection
- OpenSCAP - Security compliance checking
- SELinux/AppArmor - Mandatory access control
- Auditd - System call auditing
- Fail2ban - Intrusion prevention
- OSSEC - Host-based intrusion detection