技术社区
安全培训
技术社群
积分商城
先知平台
漏洞库
历史记录
清空历史记录
相关的动态
相关的文章
相关的用户
相关的圈子
相关的话题
注册
登录
记一次bottle框架的渲染标识符挖掘
fp00cwin
历史精选
233浏览 · 2025-03-23 11:02
返回文档
记一次bottle框架的渲染标识符挖掘
前言
最近打了一个nctf的题,题目源代码是一个pydash原型链污染以及一个模板渲染的操作,这里简单给出一些源代码:
Plain Text
复制代码
删掉了一些waf,具体代码加了waf的代码可以查看nctf2024的
ez_dash_revenge
。
这里本地下载pydash的版本为5.1.2即可。
从代码中可以看出,这里的
setValue
路由是存在原型链污染的,然后这里的
render
路由是存在ssti漏洞的。但是这里的
render
路由是过滤了
{
和
}
的,结合到之前python原型链污染学的污染jiaja2标识符,这里自然而然就想到了挖掘这个点来进行利用。
下面来看一下怎么挖掘。
挖掘分析
在代码中可以将模板渲染的代码的waf给去掉,再精简一下代码,可以得到如下内容:
Plain Text
复制代码
现在就用这个代码来进行一下演示。
可以先看一下这里的正常的模板渲染效果:
其实就是和正常学的flask框架的ssti漏洞是一样的。
这里需要知道一个知识点,翻看
bottle官方文档
,可以知道这里是bottle框架是可以在模板中嵌入python代码的:
具体的利用可以看GHCTF2025的Message in a Bottle。这里提到了
%
和
<%
与
%>
几个标识符,这里就是可以执行python代码,所以同样是存在漏洞的,具体看nctf2024的ez_dash非预期题解。
既然这里都说了是挖掘模板渲染标识符的,先说一下我的
基本想法
,既然题目中过滤了
{}
,那么这里是否可以进行尝试污染标识符为
[[]]
,从而来进行ssti漏洞利用。
想要污染,那么肯定是需要先找到在bottle框架中的标识符的定义,问了一下gpt,如下:
这里我们可以知道了是定位在bottle.py文件中,跟随一下,发现确实如上所述:
并且可以知道是定义在StplParser类中的。
那么其实在这里就可以进行一次简单的利用了,位置以及地方都找到了,需要先找到这个类,如果name没过滤
bottle
的话,其实直接如下就能找到:
但是是没法的,这里就只能使用
__loader
或
__spec__
来找sys模块再加载这个类了,结合题目中导入了
pydash
这个模块,经测试如下就可以找到指定变量:
那么这里其实就已经可以尝试来改变一下这个变量的值了,在这里我是想当然地直接修改,为了方便查看,这里简单改一点源码:
pydash污染的话就如下传参就行了:
在控制台可以看到成功污染掉:
再尝试进行模板渲染:
报错了,并且在控制台上也是标明了报错点:
其实这里的报错点非常重要,但是最开始挖的时候没注意到,还是纪录一下最开始的流程,到时候回过来看这里也就比较好理解了。
————————
所以还是需要调试一下过程,目的还是寻找模板渲染的点。在
bottle.template
处打一个断点,然后传参
{{7*7}}
来进行调试分析:
跟进这个templates()函数:
然后符合那个elif条件,这里应该是尝试获取到模板,继续往下调试,会进入到模板引擎类的初始化:
翻看bottle官方文档,可以知道是符合的:
同时从代码逻辑中也是能看出来的,adapter值的定义就是将其定义为了SimpleTemplate类,而BaseTemplate类是SimpleTemplate类的父类:
所以一切都是合乎道理的。
再看前面调试分析部分,注意看这个类的注释,也标注出来了,可以这个类就是用来获取到相关模板的,然后看lookup形参的传递,指向的是
./views/
,也就是在这个目录下寻找以
tpl
、
html
等为后缀的文件,但是很明显我这里是并没有传参文件名,也就是并没有渲染到一个文件中,所以这里的值为None,我这里的源代码逻辑就是直接渲染然后回显到前端,继续调试,然后会调用到prepare()函数:
这里跟完也没啥,不用太管,上面的操作大概就是寻找模板。
回到
template()
函数的调用,然后就会调用到模板的render()来渲染:
跟进一下,然后会调用execute()方法:
跟进这个方法:
可以看到这里是进行了环境的定义,也就是一些bottle框架自带的模板函数,可以看一下官方文档,也有如下说明:
再回到调试,这一部分的重点都已经在图中标注出来了,当定义完了模板函数,然后会调用
exec()
函数,这个函数非常有说法,当调用了这个
exec()
函数结束后,我们可以看到如下内容:
变量
_stdout
变成了渲染后的49,那么这里肯定是与这个exec()函数有关了,在这个exec()函数中,是调用了
self.co
和
env
,可以看一下变量的定义:
●
env
:
没啥好利用的。
●
self.co
:
可以看到主要的点还是在这个
self.co
变量中,但是在前面的代码中是没有看到哪里有对这个变量的定义的,直接跟进一下,发现是通过方法来获取的:
这里利用到了
@cached_property
装饰器,这个装饰器用于将类的方法转换为一个属性,就是看成一个运行后返回的值就是一个属性。
然后可以看到这里调用了
self.code
,这个变量的定义同样是一个方法来动态定义的:
我们现在在
exec()
以及
co()
方法处打断点调试一下。会先进入cached_property类的初始:
不用管,没啥用,到下一步,会调用到
code()
方法,这里都获取
self.code
的值了,那么肯定会调用这个方法的呀:
可以看到这里是有初始化
StplParser
类的,这个类就是我们前面找到的定义标识符变量的类,跟进一下:
然后跟进这个
set_syntax()
方法:
重点也标注出来了,在这里可以看到定义了几个names,其实我刚开始挖找标识符定义的时候就注意到了这个,但是当时没看懂在干嘛。在这里就可以看出来了,在调用了
names.split()
所在代码后,可以看到此时的变量的定义变成了如下:
block_start
、
block_close
、
inline_end
、
inline_start
等,这样一匹配下来,就可以知道这里就是代表的标识符分割,那么我这里在污染值时应该也是需要符合这个逻辑的,尝试一下,那么语句就需要修改为:
具体效果如下,污染:
可以看到控制台污染成功:
然后再进行ssti:
发现报错了,但是看控制台的报错:
大概就可以知道是因为templates()函数进入到了else语句中:
导致并没有按照我们原先的走,但是在这里,注意看elif语句,可以看到这里时调用的or,然后还存在一个
$
,只要传的参数有这个符号,据可以按照原先预计的走了,那么就需要如下传参:
成功进行ssti ,可以利用。
再回看原先的报错,就是因为我直接将所有的值全改成只有
[[ ]]
,导致了匹配不均,报错KeyError。
——————
大概就是这样了,也许else语句中还可以利用,但这里就不多说了。
参考文章:
https://tttang.com/archive/1876/#toc__got_first_request
0
人收藏
0
人喜欢
转载
分享
0
条评论
某人
表情
可输入
255
字
评论
发布投稿
热门文章
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
近期热点
一周
月份
季度
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
暂无相关信息
暂无相关信息
优秀作者
1
T0daySeeker
贡献值:38700
2
一天
贡献值:24800
3
Yale
贡献值:18000
4
1674701160110592
贡献值:18000
5
1174735059082055
贡献值:16000
6
Loora1N
贡献值:13000
7
bkbqwq
贡献值:12800
8
手术刀
贡献值:11000
9
lufei
贡献值:11000
10
xsran
贡献值:10600
目录
记一次bottle框架的渲染标识符挖掘
前言
挖掘分析
转载
标题
作者:
你好
http://www.a.com/asdsabdas
文章
转载
自
复制到剪贴板