SSTI 就是服务器端模板注入(Server-Side Template Injection)

flask是用python编写的一个轻量web开发框架

漏洞成因

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

jinja2

Jinja2是一种面向Python的现代和设计友好的模板语言
Jinja2使用 {{name}}结构表示一个变量,它是一种特殊的占位符,告诉模版引擎这个位置的值从渲染模版时使用的数据中获取。

漏洞原因:

flask使用jinjia2渲染引擎进行网页渲染,当处理不得当,未进行语句过滤,用户输入,会导致渲染出恶意代码,形成注入。

主要是用了render_template_string这个函数,直接渲染执行了字符串

代码实现

代码实现简单的渲染,利用render_template函数渲染

app.py

from flask import Flask
from flask import render_template,request

app = Flask(__name__)

@app.route('/')
@app.route('/index')#我们访问/或者/index都会跳转
def index():
bai = request.args.get('bai')
return render_template('index.html',name=bai)


if __name__ == '__main__':
app.debug = True
app.run()

index.html

<html>
<head>
<title>小猪佩奇</title>
</head>
<body>
<h1>Hello, {{name}}!</h1>
</body>
</html>

运行起来后,访问127.0.0.1:5000

image-20231102133929813

通过输入参数可以进行简单的渲染,代码不能执行

`{{name}}`是被{{}}包起来的,会预先渲染转义,然后才输出,不会被渲染执行

利用render_template_string函数

app.py

from flask import Flask
from flask import render_template,request,render_template_string

app = Flask(__name__)

@app.route('/')
@app.route('/index')#我们访问/或者/index都会跳转
def index():
bai = request.args.get('bai')
str = '''
<html>
<head>
<title>小猪佩奇</title>
</head>
<body>
<h1>Hello, {}!</h1>
</body>
</html>
'''.format(bai)
return render_template_string(str)


if __name__ == '__main__':
app.debug = True
app.run()

image-20231102134006165

代码被成功执行,return render_template_string(str)会将{}里的字符串当成代码指令

flask相关知识

由于在jinja2中是可以直接访问python的一些对象及其方法的,所以可以通过构造继承链来执行一些操作,比如文件读取,命令执行等

魔术方法

__class__  :返回一个实例所属的类
__mro__   :返回当前类对象的所有继承类
__bases__  :以元组形式返回一个类直接所继承的类(可以理解为直接父类)__base__   :和上面的bases大概相同,都是返回当前类所继承的类,即基类,区别是base返回单个,bases返回是元组
// __base__和__mro__都是用来寻找基类的
__subclasses__  :以列表返回类的子类
__init__   :类的初始化方法
__globals__   :对包含函数全局变量的字典的引用
class A:pass
class B(A):pass
class C(B):pass
class D(B):pass
c = D()
print(c.__class__.__base__) # 返回D类上一个父类(B类)
print(c.__class__.__mro__) # 返回D类的所有父类
print(c.__class__.__mro__[2]) # 返回A类
print(c.__class__.__mro__[2].__subclasses__()) # 返回A类的子类
print(c.__class__.__base__.__subclasses__()) # 返回B类的子类
print(c.__class__.__base__.__subclasses__()[1]) # 返回D类
<class '__main__.B'>
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
<class '__main__.A'>
[<class '__main__.B'>]
[<class '__main__.C'>, <class '__main__.D'>]
<class '__main__.D'>

绕过姿势

绕过姿势

以后再写吧,看大佬的吧