Skip to content
TheoSecLABS
All labs
MediumWeb Exploitation (OSWE)

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

Description

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 is a short chain of its own.

Difficulty vs OSWE: Approaching OSWE, but still a step below the exam. This is the box where the OSWE mindset clicks: you stop looking for a single silver-bullet bug and start chaining several distinct weaknesses into one automated exploit.

Setup

  1. Download the Currents 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: student · Password: currents
    • Run ifconfig (or ip a) and note the address (e.g. 192.168.56.x).
  4. Open the in-browser debugger. Browse to http://<vm-ip>:8080 (code-server). Password: currents — there is no username.
    • Open Folder → choose the folder named currents.
    • Click the Run and Debug icon in the left sidebar.
    • Click the green ▶ Start Debugging button to launch a debug instance of the app.
    • Set breakpoints and step through the code as you investigate.
  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 app’s user.
  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

Each phase is a small chain of weaknesses that only add up to compromise together.

Phase 1 — unauth → admin (SSRF → internal service → privesc)

  1. Open registration (POST /register) → a normal member account + JWT cookie. Sessions carry only {uid}; the role is read from the store on every request (src/auth.js → loadUser), so changing a user’s role takes effect immediately.
  2. SSRF in add-feed (POST /api/feeds → src/feeds.js fetchFeed) — the server fetch()es any URL with no scheme/host restriction.
  3. Internal management API (server.js, internal.listen(9099, '127.0.0.1')) is unauthenticated because it is “only reachable from localhost”, and exposes a state-changing GET /grant?user=<id>&role=admin.

Chain: register → GET /api/me for your id → POST /api/feeds with {"url":"http://127.0.0.1:9099/grant?user=<id>"}. The server-side fetch hits the internal service from localhost and flips your role to admin. Re-read /api/me: you are admin. (The internal port 9099 is discoverable in the source.)

Phase 2 — admin → RCE (prototype pollution → EJS gadget)

  1. Prototype pollution in the settings deep-merge: PUT /api/admin/settings calls deepMerge(settings, req.body) (src/util.js), a recursive merge with no __proto__/constructor guard. Body {"__proto__":{"outputFunctionName":"<payload>"}} pollutes Object.prototype.
  2. EJS gadget: GET /admin/newsletter calls ejs.render(templateString, data). EJS 3.1.6 reads opts.outputFunctionName off a plain object (now inheriting the polluted value) and injects it into the compiled function as var <outputFunctionName> = __append; — so a payload like x=1; <js> ; x executes <js> at render time. (Fixed in EJS 3.1.7, which validates the identifier — the pinned ejs@3.1.6 in package.json is the bug.)

The reference exploit’s payload writes execSync(cmd) output into the app’s static public/ dir and reads it back over HTTP. It restores outputFunctionName to a harmless identifier afterwards so the app keeps working.

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
HardLinux · Java

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

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.