Source: Jinja2 SSTI (render_template_string)

apps/ssti/labs/basic.py · view on GitHub

← back to lab

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
"""SSTI lab: basic — INTENTIONALLY VULNERABLE.

Textbook Jinja2 SSTI: a "greeting" feature renders user input as a Flask
template via render_template_string. Any expression the user submits is
evaluated by the Jinja2 environment, which in Flask has access to the
running app's `config`, `request`, etc., and which can be walked from
any string object to subprocess via __class__.__mro__[1].__subclasses__().

Marker for the lab being exploited: the Flask app config exposes a
per-lab flag string at config['VULNLAB_SSTI_BASIC']. The canonical
extraction is {{ config['VULNLAB_SSTI_BASIC'] }}.
"""
from __future__ import annotations

from pathlib import Path

from flask import Blueprint, render_template, render_template_string, request

bp = Blueprint("ssti_basic", __name__, url_prefix="/basic")

META = {
    "slug": "basic",
    "title": "Jinja2 SSTI (render_template_string)",
    "summary": "User input rendered as a Flask template. Full Jinja2 evaluation.",
    "hint": (
        "render_template_string runs your input through Flask's full Jinja2 "
        "environment. Try {{ 7*7 }} to confirm template evaluation, then "
        "{{ config['VULNLAB_SSTI_BASIC'] }} to read the lab flag, then walk "
        "''.__class__.__mro__[1].__subclasses__() for RCE."
    ),
    "sink": "flask.render_template_string",
    "source_path": str(Path(__file__).resolve()),
    "vulnerable": True,
}


@bp.route("/", methods=["GET"])
def lab():
    greeting = request.args.get("greeting", "")
    rendered = error = None
    if greeting:
        try:
            # INTENTIONAL: user input passed directly as a Jinja template.
            rendered = render_template_string(greeting)
        except Exception as e:
            error = f"{type(e).__name__}: {e}"
    return render_template("lab_basic.html", meta=META, greeting=greeting, rendered=rendered, error=error)