MAAS 2 // Notes Source was the same from MAAS 1 (and will be the same for MAAS 3). MAAS 2 involved the ’notes’ part of MAAS, where you are prompted to register a user and afterwards add key:val attributes to yourself, give yourself a bio, or transfer key:value attributes to another user.
The provided source has some interesting code:
notes/app.py
@app.route('/useraction', methods=["POST"]) def useraction(): mode = request.form.get("mode") username = request.form.get("username") if mode == "register": r = requests.get('http://redis_userdata:5000/adduser') port = int(r.text) red = redis.Redis(host="redis_users") red.set(username, port) return "" elif mode == "adddata": red = redis.Redis(host="redis_users") port = red.get(username).decode() requests.post(f"http://redis_userdata:5000/putuser/{port}", json={ request.form.get("key"): request.form.get("value") }) return "" elif mode == "getdata": red = redis.Redis(host="redis_users") port = red.get(username).decode() r = requests.get(f"http://redis_userdata:5000/getuser/{port}") return jsonify(r.json()) elif mode == "bioadd": bio = request.form.get("bio") bio.replace(".", "").replace("_", "").\ replace("{", "").replace("}", "").\ replace("(", "").replace(")", "").\ replace("|", "") bio = re.sub(r'\[\[([^\[\]]+)\]\]', r'{{data["\g<1>"]}}', bio) red = redis.Redis(host="redis_users") port = red.get(username).decode() requests.post(f"http://redis_userdata:5000/bio/{port}", json={ "bio": bio }) return "" elif mode == "bioget": red = redis.Redis(host="redis_users") port = red.get(username).decode() r = requests.get(f"http://redis_userdata:5000/bio/{port}") return r.text elif mode == "keytransfer": red = redis.Redis(host="redis_users") port = red.get(username).decode() red2 = redis.Redis(host="redis_userdata", port=int(port)) red2.migrate(request.form.get("host"), request.form.get("port"), [request.form.get("key")], 0, 1000, copy=True, replace=True) return "" @app.route("/render", methods=["POST"]) def render_bio(): data = request.json.get('data') if data is None: data = {} return render_template_string(request.json.get('bio'), data=data) The relevant parts are when mode is equal to bioadd. There’s a pretty hefty sanitizer in play that removes all relevant characters required for an SSTI. This is further supplemented by the endpoint to /render, which takes your input and passes it into render_template_string. TL;DR: Server-Side Template Injection involves injecting code into template expressions that are evaluated on the server. Essentially, if you have an app vulnerable to SSTI, then you should be able to inject any expression into {{double curly brackets}} and that expression would be evaluated.
...