一、先明确什么是ssti漏洞
服务器端模板注入(Server - Side Template Injection,SSTI)漏洞是一种严重的安全漏洞,它允许攻击者在服务器端注入恶意的模板代码,从而控制服务器或获取敏感信息。
它本质上就是通过设计者留下来的漏洞,及没有完整的过滤和验证造成的。导致的数据的丢失及系统的瘫痪,敏感信息的泄露。
二、如何检验是否有ssti漏洞
试试输入?name={{7*7}}是否会输出49,如果输出就一定有ssti漏洞,如果没有看看用其他的方法如{%%}看看有没有输出。
三、ssti常见的类和方法
__class__用来查看变量所属的类
__bases__用来查看类的基类,就是父类(或者__base__)
__mro__:显示类和基类
__subclasses__():查看当前类的子类
__getitem__:对数组字典的内容提取
__init__ : 初始化类,返回的类型是function
__globals__:查看全局变量,有哪些可用的函数方法等,然后再搜索popen,eval等
__builtins__:提供对Python的所有"内置"标识符的直接访问,即先加载内嵌函数再调用
__import__ : 动态加载类和函数,用于导入模块,经常用于导入os模块(例如__import__('os').popen('ls').read())
url_for :flask的方法,可以用于得到__builtins__
lipsum :flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}}
config:当前application的所有配置。
popen():执行一个 shell 以运行命令来开启一个进程
request.args.key:获取get传入的key的值
四、基本的过程
先确定有没有ssti漏洞 ->进入类-》进入基本类-》获取基本的子类-》利用命令的方法进行攻击(cat)(注意在打靶场是利用cat命令时,需要空一格再输入/flag,在 cat /flag
中,cat
是 Linux 系统中的一个命令,用于查看文件内容 ,而 /flag
是要查看的文件路径。中间加空格是因为在 Linux 命令行语法规则中,命令和其参数之间需要用空格分隔。
五、各种的绕过
这借鉴的是ctfshow的东西
web365过滤[],可以考虑用其他的方法进行攻击,
?name{{().__class__.__base__.__subclasses__().pop(290).__init__.__globals__.pop(request.cookies.m1).popen(request.cookies.m2).read()}}
cookie:m1=os;m2=cat /flag
例如就行这个一样,连续使用了两次cookies的方法进行操作
搜了一下也可以考虑使用__getitem__进行操作
六、最重要的东西
在 SSTI(服务器端模板注入)漏洞场景下,os.popen
常被攻击者利用来执行恶意系统命令,进而控制服务器或获取敏感信息
一般情况下是我们要求尽可能多的对paload进行os.popen的拼接,特别是要考虑调用__globals__
在函数内部,__globals__
属性是一个字典,它包含了函数所在模块的全局变量。这意味着通过 __globals__
,函数可以访问和修改模块级别的变量,即使这些变量在函数定义之外。
- 在存在服务器端模板注入(SSTI)漏洞的情况下,攻击者就是利用
__globals__
能访问到已导入模块这一特性。假设在一个有漏洞的 Flask 模板环境中,攻击者输入恶意代码{{ __import__('os').__globals__['os'].popen('恶意命令').read() }}
(实际攻击中可能结合更隐蔽的方式),先通过__import__('os')
导入os
模块,然后利用模块的__globals__
再次获取os
模块对象(这里有点冗余,但为了说明原理),进而调用os.popen
执行恶意命令。 - 这凸显了在安全敏感场景下,对
__globals__
访问进行严格控制的重要性,以防止恶意利用来执行危险的系统命令。
七、补充
“lipsum|attr”的作用
在 Flask 应用的模板注入(SSTI)场景下,lipsum|attr
组合是攻击者可能利用的一种危险构造。这里的 lipsum
通常来自 flask - faker
扩展,用于生成假文本,而 attr
是 Jinja2 模板引擎中的一个过滤器。
举一个例子:
{{ lipsum|attr('__globals__')['os'].popen('id').read() }}
就像这行代码。利用了”lipsum|attr“,它是在设计者不让用下划线的情况下使用的。
lipsum|attr('__globals__')
:通过attr
过滤器获取lipsum
对象的__globals__
属性,这将返回全局符号表字典。['os']
:从全局符号表字典中获取os
模块对象。在 Python 中,os
模块提供了与操作系统交互的功能。.popen('id').read()
:调用os
模块的popen
函数执行系统命令id
(在 Linux 系统中,id
命令用于显示当前用户的身份信息),并读取命令的输出结果。这样攻击者就可以通过模板注入执行任意系统命令,获取敏感信息或者控制服务器。