Skip to content
TheoSecLABS
All labs
HardWeb Exploitation (OSWE)

Vaultline

Vaultline is a small-team password manager — a legacy Java service that has been running, and being patched, for years. Members store logins and secrets; an admin manages users and can back up and restore the workspace. It's solid-looking enterprise software, and reaching code execution demands genu

Description

Vaultline is a small-team password manager — a legacy Java service that has been running, and being patched, for years. Members store logins and secrets; an admin manages users and can back up and restore the workspace. It’s solid-looking enterprise software, and reaching code execution demands genuine source review and a real, multi-link exploit chain rather than a lucky payload.

Difficulty vs OSWE: This is OSWE exam level. Vaultline is representative of the difficulty and style of the exam itself — a legacy codebase, a chain you have to construct, and a fully scripted exploit at the end. If you can own this box unaided and automate it cleanly, you’re in exam shape.

Setup

  1. Download the Vaultline OVA from Theosec Labs.
  2. Import into VirtualBox — File → Import Appliance, select the .ova, and import.
  3. Start the VM. At the console login, sign in and find its IP:
    • Username: dev · Password: vaultline (this account has full sudo)
    • Run ifconfig (or ip a) and note the address (e.g. 192.168.56.x).
  4. Open the in-browser IDE. Browse to http://<vm-ip>:8080 (code-server). Password: vaultline — there is no username.
    • Open Folder → choose the folder named vaultline to read the full source.
    • A Java debug configuration is provided under Run and Debug. Java debugging is attach-based: it connects to the running service (port 5005). You have full sudo on the box, so you can restart the app with the debug agent and step through requests if you want to. Reading the source is the main event.
  5. Read the source to find the vulnerabilities.
  6. Write your exploit. The target app is at http://<vm-ip>/ (port 80). Write a script (Python recommended) that automates the whole chain — unauthenticated → admin → remote code execution — and, at the RCE step, fires a reverse shell back to a nc -lvnp <port> listener on your machine. Running the script should catch you a shell as the application’s service account.
  7. Capture local.txt and proof.txt.

Solution

Finished the box?

Check your exploit against the reference solution, or read how the box is found and exploited end to end. Both contain full spoilers — they stay hidden until you open them.

Download solution
Reveal walkthroughSpoilers — how the box is found and exploited

Intended chain

Both phases are chains of several weaknesses that only add up together.

Phase 1 — unauth → admin (predictable time-bound reset token)

Small weaknesses:

  1. Insecure RNG as crypto — Security.Tokens uses one shared java.util.Random for every reset token. java.util.Random is a 48-bit LCG; observing one output recovers its internal state and predicts all future outputs.
  2. Self-token leak — /account displays the logged-in user’s own active recovery token (GET /account, shown in <pre class="code">).
  3. Shared, ordered generation — both POST /account/recovery and POST /forgot draw the next token from the same RNG.

Exploit: register + log in → POST /account/recovery and read your own 16-byte token off /account → recover the java.util.Random state (16-bit brute over the low bits, verified against the remaining outputs) → POST /forgot username=admin (admin’s token is the very next draw) → predict it → POST /reset for admin before the 20-minute expiry → log in as admin. See recover_random() in exploit.py.

Phase 2 — admin → RCE (filtered Java deserialization)

POST /admin/restore base64-decodes the “backup bundle” and reads it with SafeObjectInputStream (resolveClass blocklist). GET /admin/backup hands out a real serialized VaultBackup bundle, so the format (rO0... / \xac\xed) is discoverable.

  • Filtering: the blocklist rejects the CommonsCollections InvokerTransformer family (and Runtime/ProcessBuilder, LazyMap, TiedMapEntry, …), so the usual ysoserial CommonsCollections* payloads fail. The classpath ships the pre-hardening commons-collections 3.2.1, so those functors do serialize — the block is SafeObjectInputStream, not the library.
  • Verbose errors: /admin/restore echoes the exception message, so probing leaks the blocked class names (and classpath issues), guiding the bypass.
  • Bypass: CommonsBeanutils1 (BeanComparator + PriorityQueue + TemplatesImpl, from commons-beanutils 1.9.4) uses none of the blocked classes, so it passes the filter and executes bytecode via TemplatesImpl → RCE.

GadgetGen.java (this folder) builds that payload with Javassist. Students can use ysoserial CommonsBeanutils1 instead. Output is exfiltrated by writing to the app’s web/ static dir and reading it back at /static/<name>.

More labs

Super easyLinux · Python

Simmer

Simmer is a small community recipe box where home cooks publish recipes, leave comments, and keep a profile. It looks friendly and unremarkable — which is exactly the point.

Web Exploitation (OSWE)Open lab
EasyLinux · PHP

Craftly

Craftly is a boutique online marketplace for handmade goods — ceramics, textiles and woodwork sold by independent makers. It has customer accounts, product listings, reviews and an admin catalogue, and at a glance it all looks perfectly ordinary. The security is not as tidy as the storefront. Get in

Web Exploitation (OSWE)Open lab
MediumLinux · NodeJS

Currents

Currents is a self-hosted feed reader: add your blogs and news feeds and it pulls the articles into one clean stream. It has a personal dashboard, an admin area, and a small internal service it talks to behind the scenes. Neither getting in nor getting code execution is a one-shot affair here — each

Web Exploitation (OSWE)Open lab

→Next step

Break something on purpose.

Every lab ships as a VM you run on your own hardware — download it, read the source, and work the chain end to end. No account, no scoreboard, no catch.