zer0pts CTF 2022

Writeup for the zer0pts CTF 2022

Updated:

Web

GitFile Explorer

77 points 181 solves

Read /flag.txt on the server.

The source code revealed that in order to trigger the file_get_contents function, the input must match the defined expression.

First, github or gitlab or bitbucket must exist in the service parameter to get a crafted URL, which for github it will concatenate with the other parameters with a / in between.

Then, the crafted URL has to begin with http, followed by any characters then //, any characters then either github or gitlab or bitbucket. The regex applies for multiline input.

<?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);
    }
}
?>

The function file_get_contents can also read local files when the protocol is not recognised, which https//, without the colon :, is used to match the regex but an invalid protocol.

The remaining was pretty straightforward, by using github to match the regex but will be ignored as not found.

The flag is located at /flag.txt which should be able to access by ../../../../../flag.txt. The other parameters were given .. as it will be concatenated as ../, and the last parameter was given ../../flag.txt to finish the path.

The full request was service=https//github&owner=..&repo=..&branch=..&file=../../flag.txt and the flag was read successfully.

zer0pts-ctf-2022-gitfile.png

Flag: zer0pts{foo/bar/../../../../../directory/traversal}


Comments