
這題是ssti的基礎題,我當初就是都丟給ai解沒打好基礎所以現在過不了SSTI2回來補
參考文章:
1.https://portswigger.net/web-security/server-side-template-injection
2.https://portswigger.net/research/server-side-template-injection
下面這張圖是解題思路
1.確認是否能注入
2.我注入的伺服器是什麼型別
3.確認是否有黑名單(檔關鍵字)
4.在伺服器裡面晃晃
5.達成目標 執行動作(ex:拿ctf)
1+2:
如果輸入${7*7}輸出49 分支往上
反之伺服器看不懂分支往下
這邊直接用這題ctf舉例
分支往下
試{{7*7}}
這邊確定是jinja2這一派的了(本題實際是用jinja2)
ps:{{7*'7'}} 是區分 Jinja2 vs Twig
jinja2會輸出:7777777
Twig會輸出:49
3:
把可能被黑名單得關鍵字都試一遍
{{ config }}
{{ self }}
{{ request }}
{{ ''.class }}
->這題是EZ沒有檔等我們到ssti2就會用到這個技巧了
先整理思路:
我確認是 Jinja2 → 後端是 Python,而且 Jinja2 函式庫本身的原始碼就會 import os 之類的模組(這是模板引擎正常運作需要的)→ 我透過 self/lipsum 這些 Jinja2 暴露出來的函式物件,拿到它的 globals(也就是它定義時所在那個 module 的全域變數),直接借用 Jinja2 自己已經 import 好的東西,間接取得執行系統指令的能力
這邊插入claude code給的ssti指令結構模板:
self / lipsum / cycler:路怎麼走到 os 模組(固定的幾種鑰匙,試哪一把能開門)'id' / 'ls -la' / 'cat /challenge/flag':到了之後要做什麼(這是你自由決定的,跟前面的鑰匙無關)
題目到這邊就是開始閒逛了 就像小偷已經溜進關門得超市這樣
這裡我用口述:
往上兩層後有一個challenge資料夾進去有一個flag
5.完成目標:{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cd /challenge && cat flag').read() }}
我把flag base64放這:YWNhZGVteXtzNHJ2M3JfczFkM190M21wMTR0M18xbmozY3QxMG41XzRyM19jMDAxX2RlZTBhMWE2fQ==
題目講解到這
下面來小小補充一些SSTI得技巧:
參考:https://portswigger.net/research/server-side-template-injection
tips1:
丟無效語法,看錯誤訊息:很多引擎的報錯會直接洩漏引擎名稱甚至版本
tips2:
Read 文件
讀模板引擎的官方文件,學基本語法
特別去找文件裡的「Security」章節——很多引擎的官方文件會自己列出「這些功能很危險,別讓使用者碰」,這其實等於官方幫你列好的 cheat sheet
tips3:
就算打不出 RCE,SSTI 還是有價值
tips4:
偵測技巧:
先丟 ?greeting=data.username<tag> → 如果沒被當 HTML 解析(代表沒有單純 XSS)
再試著用模板語法「跳出」原本的運算式:?greeting=data.username}}<tag>
如果 被當成 HTML 渲染出來(代表你成功用 }} 提前結束了模板運算式),就確認是 SSTI
下面歡迎友善討論0.0