Skip to content
TheoSecLABS
All labs
Super easyWeb Exploitation (OSWE)

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.

Description

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. Somewhere in this tidy little app is a clean path from anonymous visitor to full control of the server, and your job is to read the code, find it, and prove it with a script.

Difficulty vs OSWE: Well below the OSWE exam. Simmer is a warm-up — the gentlest introduction to white-box web hacking and to writing your first unauthenticated-to-RCE exploit end to end. If you’re new to source review, start here.

Setup

  1. Download the Simmer OVA from Theosec Labs.
  2. Import into VirtualBox — File → Import Appliance, select the .ova, and import. Make sure the VM and your host can reach each other both ways (you’ll need that for the reverse shell).
  3. Start the VM. At the console login, sign in and find its IP:
    • Username: student · Password: simmer
    • 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: simmer — there is no username.
    • Open Folder → choose the folder named simmer.
    • 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 web server 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

Phase From → To Class Location
1 unauth → admin SQL injection (auth bypass) app.py → login()
2 admin → RCE Server-side template injection (Jinja2) app.py → admin_settings() / index()

Phase 1 — SQLi auth bypass

login() builds the authentication query by string-formatting the username and the MD5 of the password directly into the SQL:

query = ("SELECT id, username, role FROM users "
         "WHERE username = '%s' AND password_hash = '%s'" % (username, pw_hash))
row = db.execute(query).fetchone()

Submitting the username admin'-- comments out the password check and returns the first matching row (the admin account). The session is then populated from that row, so the attacker is now an administrator. No password or hash cracking is required. (SQLite’s execute() runs a single statement, so stacked-query tricks do not apply — this is a straight boolean/comment bypass.)

  • Real admin password (unused by the intended path): S1mmer-K1tchen-2019!
  • Passwords are unsalted MD5 — a deliberate secondary “smell,” but not needed.

Phase 2 — SSTI to RCE

The home-page announcement is admin-controlled (/admin/settings) and rendered with render_template_string() in both admin_settings() (preview) and index() (public banner):

banner = render_template_string(announcement, site_name=SITE_NAME, current_user=current_user())

The default announcement already uses {{ site_name }}, signalling that the field is evaluated as a template. Setting it to {{7*7}} renders 49. From there, a standard Jinja2 breakout reaches os:

{{ cycler.__init__.__globals__.os.popen("id").read() }}

The rendered output appears in the banner on / (and in the settings preview). The reference exploit base64-wraps the command to avoid quoting issues and reads the result back from the home page.

More labs

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
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.