当前位置: 首页 > news >正文

SSTI学习

1,什么是模板

        模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,利用模板引擎来生成前端的html代码,模板引擎会提供一套生成html代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板+用户数据的前端html页面,然后反馈给浏览器,呈现在用户面前。

2,什么是SSTI

        SSTI(Server-Side Template Injection)——服务器端模板注入。比如python中的flask、php的thinkphp、java的spring等框架一般都采用MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。

        漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。

        看了下例子,形式上有点像做题题型,根据题型去选择对应的方法。内容上感觉像是xss

先跟着wp做一题看看是什么情况

[HNCTF 2022 WEEK2]ez_SSTI

非常干净,源代码里也没有提示。但题目上给这题打的Flask框架 

尝试传参

用变量标识符包裹,发现可以识别 然后就是将payload中注入python函数

?name={{config.__class__.__init__.__globals__[%27os%27].popen(%27cat%20flag%27).read()}}

3,SSTI的攻击方式

SSTI由于不同的模板,其语法也会有所不同吗,后文以twig为例。

如果用此模板去攻击其他模板,通常是不行的。

1,检测是否存在SSTI

        如上面的例子一样,当我们传入正常的name参数时,整个网页会显示正常。看起来就像平常的get传参拼接一样,但是当我们用特定的模板语法构成的payload被成功解析时,那么就可以判断这里存在SSTI注入。如果没有可能就是其他模板或者不存在SSTI。

比如在源码中看到类似

<h1>hello {{name}}</h1>

之类的,传入一个name参数能被成显示,如果传入{{2*2}},能被成功解析为4,那八九不离十就是SSTI注入了

2,发起攻击

        在找到注入点后,就能像sql那样发起攻击了。原理就是利用该模板的函数进行文件的增删读改。然后因为模板会将盖变量输出,所以我们也就能够看见结果了。

        由于模板有多种,每种payload都是不同的。而且随着php版本不同,模板的更新,会出现新的方法,同时之前的旧方法可能会失效。需要在过程中不断积累。

4,Flask框架下的攻击

        由于有很多的模板,这里就以Python的Flask框架为例子,学习SSTI。

这种漏洞多半是由于字符转义不严格,代码直接将用户输入输出,通过构造恶意语句执行命令。

@app.route('/test2', defaults={'name': 'kobe'})
@app.route('/test2/<name>')#动态路由获取name参数
def test2(name):data='''<html><body>{{str}}</body></html>'''return render_template_string(data,str=name)

        以上述代码为例,创建了一个名为test2的路由,并且是动态路由,通过路由获取name的参数

在flask中,用{{}}来标识变量。然后返回重新渲染过的data数据,并标记变量str是name

因为渲染时,特殊字符会被转义,所以这样就不会被当作变量解析。

但如果我们直接将变量拼接到数据中就会造成恶意输入被解析

@app.route('/test1',methods=['GET','POST'])#get传参获取参数
def test1():name = request.args.get('name',default='kobe')data='''<html><head></head><body>hello {}</body></html>'''.format(name)return render_template_string(data)

比如我们用format格式化字符串 what_can_i_say!! 这样被成功解析后就能用继承关系找环境中的可以用魔术方法拿flag

__class__:查找当前类型所属对象

__base__:查找上一级父类

__mro__:查找当前类对象的所有继承类

__subclasses__():查找父类下的所有子类

__init__:查看类是否重载(程序在运行时就已经加载好了这个模块到内存中),如果出现wrapper说明没有重载

__globals__:函数会以字典的形式返回当前对象的全部全局变量

 主要流程时找os._wrap_close,然后再全局变量中找:

__buitins__:对所有内置标识符直接访问

eval():内置函数,计算字符串表达式的值

popen():执行一个shell以运行命令

先获取一个类 然后一直访问它的父类,也就是一直套__base__,知道object(object应该是所有类的父类,再访问object的所有子类就能找到有用的方法)

 然后把找到的所有类,用任何办法,找到os._wrap_close这个方法

然后以数组的形式访问 然后看查该方法是否重载,如果没有重载就需要换一个方法,因该是

只要返回出地址就代表已经重载了

然后再看查当前对象的全局变量 然后可以用浏览器的搜索框,看是否存在这三种全局变量

__buitins__,eval(),popen()

然后传入payload,就可以任意命令执行了

{{"".__class__.__base__.__subclasses__()[159].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}也可以直接用popen{{"".__class__.__base__.__subclasses__()[159].__init__.__globals__['popen']('ls').read()}}

 

当然SSTI还有很多模板,可以用如下图示判断是否是这几种主流模板之一

http://www.xdnf.cn/news/311059.html

相关文章:

  • 系统思考:选择大于努力
  • AI Agent(4):Agent核心技术栈
  • VTK|结合qt创建通用按钮控制显隐(边框、坐标轴、点线面)
  • 【原创】批量区分横屏竖屏照片
  • 云计算与大数据进阶 | 25、可扩展系统构建
  • Mybatis-核心源码相关
  • kaggle注册问题
  • 瑞克的CTF
  • vue3 报错
  • 高频工业RFID读写器-三格电子
  • 天线测试报告解读学习
  • 【爬虫】码上爬第6题-倚天剑
  • 【AI知识库云研发部署】RAGFlow + DeepSeek
  • 第九节:图像处理基础-图像几何变换 (缩放、旋转、平移、翻转)
  • 1999-2023年各数据/研发经费内部支出数据/RD经费内部支出数据
  • JavaScript性能优化实战:深入探讨性能瓶颈与优化技巧
  • NAND Flash存储器的错误管理导览
  • 超短波跳频电台靶标设备 智能超短波通信模拟系统技术解析“
  • Chat_TTSV3 本地版 Chat_TTS—UI本地版 免费分享
  • 算法每日一题 | 入门-顺序结构-三角形面积
  • 从单机到生产:Kubernetes 部署方案全解析
  • 删除排序链表中的重复元素:三种解法详解
  • 电子电器架构 --- 网关转发时延解析
  • PostgreSQL存储过程“多态“实现:同一方法名支持不同参数
  • 亚马逊Q1财报公布!营收增长9%至1557亿美元
  • QT Sqlite数据库-教程03 插入数据-下
  • 信息论05:信息论中的条件熵——从不确定性量化到机器学习实战
  • opencv实战:银行卡卡号识别
  • 效率提升利器:解锁图片处理新姿势
  • MySQL的内置函数与复杂查询