iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 13
0
Security

資訊安全的美味雜炊系列 第 13

[Day13] - SSTI (Server-side template injection)

Day13 - SSTI (Server-side template injection) (1)

前言

  • 之前在寫web專題的時候,使用了Python-jinja2作為模板引擎,當時還不知道這種模板引擎有注入的風險。後來研究才知道有 SSTI 這個東西,然後當時都沒做防禦XD

模板引擎的優點

  • 能夠有效的把前端的 User Interface 與後端給的數據做分離
  • 模板可以讓code更為整潔,能夠將重複或類似的區塊使用繼承的方式,加速開發的速度,可讀性也比較高
  • 成熟的模板引擎有很高的機率有做基本的字元過濾,或是格式化日期

模板引擎的缺點

  • 安全性的問題,嚴重可能造成 RCE (Remote Code Execution)
  • 很容易使開發者過度使用,反而很有可能破壞MVC的架構

SSTI (Server-Side Template Injection)

  • 注入 (Injection)

    • 當用戶輸入數據沒有適當的處理或過濾,就有可能把插入的字串變成 code 的一部分,進而改變程式的運作邏輯
    • 像是我們文中前面學的 SQL Injection 就是經典的例子
  • 接下來我們看怎麼讓模板引擎該怎麼注入

Example

  • 這是一段經典的 SSTI,漏洞是因為使用了 render_template_string() 使用了"%s"來替換字串
  • 我們知道 Jinja2 渲染資訊到前端時,會將 {{ }} 裡面的內容作解析,
  • 而 flask 使用了 Jinja2 作為模板渲染引擎,當駭客輸入將 {{ 7+7 }} 時,就會被解析成 14
from flask import Flask, render_template, request, render_template_string

app = Flask(__name__)
@app.route('/',methods=['GET'])
def index():
    name = request.args.get('name', 'roy')
    template = '''
    <div class="center-content error">
        <h1>Hello</h1>
        <h3>{}</h3>
    </div>
    '''.format(name)
    return render_template_string(template)

if __name__ == '__main__':
    app.run(debug=True)

各種不同模板引擎的 tags 如下

沙箱逃逸/跳脫 - 試著從 Python 環境下跳到主機的 shell

  • 既然能夠注入程式碼給模板引擎解析,就試試看用語法湊湊 Payload 囉
  • 必須繞過種種的黑名單,想辦法 getshell
  • 接下來舉例跟示範我們使用pythonFlask/Jinja2作為示範

介紹Python的內建函數

  • Python中的 dir() 可查詢物件全部屬性
    • 例如dir(str), dir(list) ...
    • 如果甚麼都不掛dir(),執行結果就會用最大限度的範圍,列出變數、方法和屬性

__builtins__

  • 他儲存了python的內建函數,當python的interpreter被打開(也就是你再terminal或cmd打python3),自動會import進來的內建函數

  • 也就是為甚麼有些type或function我們可以直接打在interpreter裡,不須從外部import進來

  • 我們可以透過 __builtins__配上__dict__ 來使用其他function

    • __builtins__.__dict__['exec']("print('ok')")
    • __builtins__.__dict__['__import__']('os').system('whoami')

魔法函數

  • 我們還能透過一些魔術函數,將我們所需的lib引入
    • 透過可以存取繼承的一些function,湊出payload
    • 以下可能要有點物件導向的概念才知道我在講甚麼
__class__
  • 能透過object,找出base class是誰
class A():
    pass


a = A()
print(a.__class__)  #<class '__main__.A'>

__mro__
  • 從最底層的 subclass,一直找到 base class
    • 像是一顆樹
class A:
    pass
class B(A):
    pass
class C(A):
    pass
class D(B, C):
    pass
print(D.__mro__) #(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

__subclasses__
  • 從base class找出底下繼承他的class
    • 反過來,變成找小孩
class A(object):
    pass
class B(A):
    pass
class C(A):
    pass
print(A.__subclasses__()) #[<class '__main__.B'>, <class '__main__.C'>]
__bases__
  • 找出該個class有繼承的base class
class A(object):
    pass
class B(object):
    pass
class C(A,B):
    pass

print(C.__bases__)
__init__
  • 初始化class,以C或java來比喻就是constructer(建構子)
class A:
    def __init__(self):
        print('ok')
a = A()  # print ok
__globals__
  • 找出function中所在的namespace裡的所有變數
class A(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
a.__init__.__globals__
# {'A': <class '__main__.A'>, 'a': <__main__.A object at 0x0000000001692390>, 'importlib': <module 'importlib' from 'D:\anaconda\lib\importlib\__init__.pyc'>, '__builtins__': <module '__builtin__' (built-in)>, 'pattern': <_sre.SRE_Pattern object at 0x0000000001695030>, 'base64': <module 'base64' from 'D:\anaconda\lib\base64.pyc'>, 'sys': <module 'sys' (built-in)>, 'flag': <module 'os' from 'D:\anaconda\lib\os.pyc'>, '__package__': None, 'os': <module 'os' from 'D:\anaconda\lib\os.pyc'>, '__doc__': None, 'match': <_sre.SRE_Match object at 0x00000000039A9B28>}
__getattribute__, __getattr__
  • __getattribute__
    • 當class被呼叫時,無條件的進入這個 __getattribute__,不管該個data member是否存在
class A:
    def __init__(self):
        self.name = "Bob"
    def __getattribute__(self,item):
        print("ok")
a = A()
a.name # ok
a.age # ok
  • __getattr__
    • 當class被呼叫時,若該個data member不存在,則會進入 __getattr__
class A:
    def __init__(self):
        self.name = "Bob"
    def __getattr__(self,item):
        print("No attribute")
a = A()

a.age # No attribute

今天先到這,東西有點多


上一篇
[Day12] - SSRF(Server-Side Request Forgery)(2)
下一篇
[Day14] - SSTI(Server-side template injection)(2)
系列文
資訊安全的美味雜炊30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Troy2000
iT邦新手 5 級 ‧ 2021-05-20 05:20:46

上面應該是
模板引擎的"缺點"吧

已更正,謝謝您的留言

我要留言

立即登入留言