D3CTF2025 - d3model

import keras
from flask import Flask, request, jsonify
import os


def is_valid_model(modelname):
try:
keras.models.load_model(modelname)
except:
return False
return True

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
return open('index.html').read()


@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400

file = request.files['file']

if file.filename == '':
return jsonify({'error': 'No selected file'}), 400

MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB
file.seek(0, os.SEEK_END)
file_size = file.tell()
file.seek(0)

if file_size > MAX_FILE_SIZE:
return jsonify({'error': 'File size exceeds 50MB limit'}), 400

filepath = os.path.join('./', 'test.keras')
if os.path.exists(filepath):
os.remove(filepath)
file.save(filepath)

if is_valid_model(filepath):
return jsonify({'message': 'Model is valid'}), 200
else:
return jsonify({'error': 'Invalid model file'}), 400

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

这题很明显,唯一的漏洞利用点在is_valid_model()函数,搜索keras.models.load_model()漏洞,发现了最近的CVE-2025-1550,找到了攻击参考博客

然后比赛的时候没打出来。。。
赛后发现是,对python的subprocess模块了解还是不够深入(上次记录过一次,但还是忘了,emmm)

需要修改的地方为"inbound_nodes": [{"args": [["env >> index.html"]], "kwargs": {"bufsize": -1, "shell": True}}]
json文件也相对应做修改,不然的话,命令无法通过shell执行。。。

如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的。

还有就是这题貌似是不出网的,但docker文件里面告诉了我们flag环境变量中,并且只有index.html可写。。。

最简单的题没打出来……