Páginas

30 enero, 2019

Túnel SSH port forwarding: Local, remote y dynamic [Explicado]

¿Qué es SSH?

ssh-tunnelingSSH (Secure Shell) es un protocolo de comunicaciones seguras entre dos sistemas usando una arquitectura cliente/servidor que permite a los usuarios conectarse a un host remotamente para su posterior administración. A diferencia de otros protocolos de comunicación remota como FTP o Telnet (Telecommunication Network), SSH cifra la sesión de conexión y la comunicación ofreciendo también una infraestructura de autenticación PKI (Public Key Infrastructure) para la conexión con el host remoto.

Para poder establecer una conexión a un host que tenga implementado el rol de servidor SSH es necesario disponer de un cliente SSH. El puerto por defecto de escucha del servicio SSH es el 22.

Una vez se disponga de una comunicación establecida al servidor SSH se pueden usar los protocolos SFTP (SSH File Transfer Protocol) o SCP (Secure Copy) para la transferencia segura de ficheros entre cliente/servidor.

¿Qué es un tunel SSH? (SSH Tunneling)

Es una técnica que consiste en encapsular un protocolo de red sobre otro o un determinado tráfico de red. En el caso de usar conexión SSH se trata de realizar esta técnica de forma segura añadiendo una capa de seguridad en la que los datos viajan de forma cifrada a través del túnel SSH, realizando un reenvío o redirección de puertos (port forwarding) desde una máquina local a otra remota (o viceversa) para establecer una comunicación a un recurso o servicio accesible solamente desde uno de los extremos de la red.

Suele usarse para conectarse a un servicio remoto que solo se tiene acceso desde la red local remota. A través de un cliente SSH nos podemos conectar a un servidor SSH remoto que tenga acceso a la red remota a la que queremos acceder, especificar un reenvío de puertos para establecer las conexiones a ese servicio y así poder ejecutarlo de forma local desde la máquina que inició la conexión SSH. El método más habitual suele ser el reenvío de puertos local.

¿Tipos de reenvíos de puertos? (Port forwarding)

SSH Local port forwarding

Local (Redirección de puertos local): Reenvía un puerto local a un host remoto.

Si un servicio se ejecuta en la máquina remota en la que establecemos la conexión y queremos ejecutar este servicio en la máquina local que inicia la conexión, se puede acceder a este servicio de desde nuestra máquina local usando la dirección local de lookback (127.0.0.1 o localhost) haciendo referencia al puerto mapeado a través de la conexión de inicio de la sesión SSH.

Pongamos un escenario de ejemplo de una conexión local port forwarding de escritorio remoto RDP realizando pivoting a otro equipo dinstinto al servidor SSH.

Supongamos que estamos en una red A y queremos acceder por escritorio remoto a un equipo situado en una red B (192.168.0.10), pero que por restricción del Firewall de la red A solo podemos realizar solicitudes de conexión al puerto 22 de SSH y no al puerto 3389 del servicio RDP. Lo que podemos hacer es crear una conexión desde un cliente SSH desde la red A (172.16.0.20) a un servidor SSH situado en la red B (192.168.0.15), en esa conexión tendremos que especificar un port forwarding local en un puerto aleatorio (mayor del puerto 1024 para que esté fuera del rango de "puertos bien conocidos") por ejemplo el 9090 como puerto origen (puerto local) de la red A y la IP:3389 del equipo de la red B al que nos queremos conectar (192.168.0.10), después de establecer esta parametrización nos conectamos al servidor SSH de la red B para crear el túnel local.

En el host de la red A que estableció la conexión desde el cliente SSH (172.16.0.20) abrimos un cliente de RDP (mstsc Windows, rdesktop o Remmina en Linux) y nos conectamos a "localhost:9090". Esto redirigirá la petición del host localhost (172.16.0.20) del puerto 9090 al servidor SSH de la red B que a su vez este redirigirá la petición al host destino 192.168.0.10 hacia el puerto 3389 y así establecer la conexión RDP.

En el caso de querer conectarse a otro servicio o desde otro host que no sea el propio host que realiza conexión desde el cliente SSH se especificaría: "<host-remoto>:<puerto-remoto>".

Desde una terminal se usa el parámtro -L para port forwarding local.
ssh -L <puerto-local-escucha>:<host-remoto>:<puerto-remoto> <servidor-ssh>
ssh -L 9090:192.168.0.10:3389 mi.servidorssh.com

Si el servidor remoto SSH al que nos conectamos para realizar el pivoting del primer salto (mi.servidorssh.com) está expuesto por otro puerto que no sea el 22 por defecto, podemos especificarlo con el parámetro "-p <puerto-servidor-ssh>".

PuTTY - Local port forwarding SSH Tunneling.
Figura 1: PuTTY - Local port forwarding SSH Tunneling.
  • Cliente SSH (Red A): 172.16.0.20
  • Servidor SSH (Red B): 192.168.0.15
  • Host RDP (Red B): 192.168.0.10
Figura 2: SSH port forwarding - Túnel SSH local.

SSH Remote port forwarding

Remote (Reedirección de puertos inverso): Reenvía un puerto remoto a un host local.

Al contrario que una conexión de túnel local, si un servicio solo es accesible desde una máquina de la red local y se necesita tener conexión a el de forma remota. Se puede usar un puerto específico de escucha para conectarse a esa máquina remota y que esta nos proporcione el servicio a través de ella, pivotando posteriormente esa conexión a la máquina desde la que se inicia la sesión SSH.

Pongamos un ejemplo con los mismos hosts del escenario anterior de una conexión remote port forwarding de escritorio remoto RDP.

Supongamos que estamos en una red A y queremos ofrecer el servicio de escritorio remoto RDP situado en la red A (172.16.0.20), pero este servicio hacía este host solo solamente es accesible desde la red A y no desde otras redes externas. Lo que podemos hacer es crear una conexión con un cliente SSH desde el mismo host de la red A a un servidor SSH situado en la red B (192.168.0.15), en esa conexión tendremos que especificar un port forwarding remote en un puerto aleatorio (mayor del puerto 1024 para que esté fuera del rango de "puertos bien conocidos") por ejemplo el 9090 como puerto origen (puerto remoto) de la red B y la 172.16.0.20:3389 del equipo de la red A del que queremos ofrecer la conexión RDP (sería válido también localhost:3389 ya que se trata del mismo equipo local quien es el cliente SSH que establece la conexión), después de establecer esta parametrización nos conectamos al servidor SSH de la red B para crear el túnel remoto.

La idea es prácticamente la misma que el tunel local, la diferencia está en que la conexión se establece de forma inversa (reverse port forwarding)

En el host 192.168.0.10 de la red B abrimos un cliente de RDP (mstsc Windows, rdesktop o Remmina en Linux) y nos conectamos a "192.168.0.5:9090" (servidor SSH de la red A). Esto redirigirá la petición al puerto 9090 al host destino de la red B 172.16.0.20 hacia el puerto 3389 para establecer la conexión RDP.

En el caso de ofrecer otro servicio o desde otro host que no sea el propio host que realiza conexión desde el cliente SSH se especificaría: "<host-local>:<puerto-local>".

Directivas en el servidor SSH (/etc/ssh/sshd_config)

Para que el servidor SSH permita el conexiones de puertos de reenvío remoto es necesario habilitar principalmente la directiva GatewayPorts. Referencia: https://linux.die.net/man/5/sshd_config

AllowTcpForwarding

Especifica si se permite el reenvío de TCP, de forma predeterminada el valor está establecido a "yes".

GatewayPorts

Especifica si los hosts remotos pueden conectarse a los puertos reenviados para el cliente. De forma predeterminada, enlaza los reenvíos de puertos remotos a la dirección de loopback. Esto evita que otros hosts remotos se conecten a puertos reenviados. Por lo que para poder usarse para el reenvío de puertos remotos debe establecerse a "yes".

Desde una terminal se usa el parámtro -R para port forwarding remote.
ssh -R <puerto-remoto-escucha>:<host-local>:<puerto-local> <servidor-ssh>
ssh -R 9090:172.168.0.20:3389 mi.servidorssh.com
o también
ssh -R 9090:localhost:3389 mi.servidorssh.com

Si el servidor remoto SSH al que nos conectamos para realizar el pivoting del primer salto (mi.servidorssh.com) está expuesto por otro puerto que no sea el 22 por defecto, podemos especificarlo con el parámetro "-p <puerto-servidor-ssh>"

PuTTY - Remote port forwarding SSH Tunneling.
Figura 3: PuTTY - Remote port forwarding SSH Tunneling.
  • Cliente SSH y Host RDP (Red A): 172.16.0.20
  • Servidor SSH (Red B): 192.168.0.15
  • Client RDP (Red B): 192.168.0.10
Figura 4: SSH port forwarding - Túnel SSH remoto.

SSH Dynamic port forwarding

Dynamic (Redirección de puertos dínamico): Utiliza SOCKS.

Se comporta como un proxy SOCKS, suele usarse si nos necesitamos conectar a un software que espera un reenvío de SOCKS.

La idea es igual que cuando se establece un túnel local SSH. La diferencia es que los datos se enviarían a todos los destinos remotos. Para utilizar este tipo de conexión es necesario que la aplicación del cliente que se conecta al puerto local debe enviar tráfico mediante el protoclo SOCKS. En el lado del túnel del cliente se crearía un porxy SOCKS y la aplicación (por ejemplo un navegador web) utiliza el protocolo SOCKS para especificar donde debe enviarse el tráfico cuando sale del otro extremo del túnel SSH.

SSH creará un proxy SOCKS que escuchará las conexiones en el puerto 9090, al recibir una solicitud enrutará el tráfico a través del canal SSH establecido entre la red A (172.16.0.20) y la red B (192.168.0.15). Para ello, es necesario configurar la aplicación (navegador web) del host de la red A para que apunte al proxy SOCKS en el puerto 9090 en localhost. De ese modo estaremos saliendo con la conexión pública (si el mecanismo NAT está habilitado) a través de este navegador web como si estuviésemos en la red B.

Si en vez usar la dirección de loopback 127.0.0.1 refiriéndose a la dirección local, se usa una dirección de red no enrutable como 0.0.0.0 (indicando desde "cualquier lugar" -anywhere-) y especificando un puerto concreto, podemos indicar que se configure un Proxy SOCKS en el navegador web de cualquier máquina remota y así desde cualquier máquina de la red se establezca un túnel directo a nuestra máquina y que este tunelice el tráfico web recibido, bypaseando el tráfico restringido por los firewalls internos de la empresa.

Ejecutándolo desde un cliente SSH desde la red A. Desde una terminal se usa el parámtro -D para port forwarding dynamic.
ssh -D <puerto-origen-dinámico-escucha> <servidor-ssh>
ssh -D 9090 mi.servidorssh.com

Si el servidor remoto SSH al que nos conectamos para realizar el pivoting del primer salto (mi.servidorssh.com) está expuesto por otro puerto que no sea el 22 por defecto, podemos especificarlo con el parámetro "-p <puerto-servidor-ssh>"

PuTTY - Dynamic port forwarding SSH Tunneling.
Figura 5: PuTTY - Dynamic port forwarding SSH Tunneling.

Proxy SOCKS navegador web.
Figura 6: Proxy SOCKS navegador web.
  • Cliente SSH (Red A): 172.16.0.20
  • Servidor SSH (Red B): 192.168.0.15
SSH port forwarding - Túnel SSH dinámico.
Figura 7: SSH port forwarding - Túnel SSH dinámico.

Repositorio Github: https://github.com/adrianlois/SSH-Tunnel-Port-forwarding

Saludos!

18 enero, 2019

Cifrar passwords con PowerShell

Con PowerShell podemos generar o almacenar contraseñas simétricas, secretos (tipo API Key o Access Token) o simplemente cadenas de texto y guardarlas cifradas de forma segura en ficheros de scripts Powershell.

En un caso práctico este método lo llevo utilizando ya un tiempo para almacenar las contraseñas necesarias que se usan en scripts automatizados para realizar en este caso copias de seguridad.

Crear passwords cifradas con PowerShell para usar desde el mismo usuario

Cuando establecemos una password en Powershell y la volcamos en un fichero, el fichero que contiene la password cifrada solo sería se podría usar desde el mismo usuario que la estableció.

Para establecer una password con Powershell y volcarla a un fichero de forma cifrada convirtiendo la cadena de texto claro establecida a una cadena cifrada segura (ConvertFrom-SecureString).
Read-Host -AsSecureString "Password fichero" | ConvertFrom-SecureString | Set-Content "C:\Passwords\fichero-passwd-cifrada"
Llamar al fichero con la password cifrada almacenada en un script Powershell, convertir la cadena cifrada en texto claro (ConvertTo-SecureString).
Get-Content "C:\Passwords\fichero-passwd-cifrada" | ConvertTo-SecureString
Repositorio donde se muestra este método y un video demo PoC.

Crear passwords cifradas con PowerShell generando un keyfile portable para usar desde cualquier usuario o máquina

Otra forma de cifrar la passwords en Powershell sería generar un keyfile (fichero llave único para descifrarlas). De ese modo teniendo el keyfile y referenciándolo en el script de Powershell se pueden cifrar con el keyfile y posteriormente descifrar las password establecida volcada en el fichero.

La ventaja respecto al método anterior, es que se pueden descifrar los ficheros que almacenan las passwords cifradas desde cualquier usuario de la misma máquina o cualquier usuario de otra máquina distinta. Pudiendo así transportar los ficheros de passwords y keyfile para ser utilizados de una forma portable por otros usuarios o máquinas.

Generar el keyfile y establecer la password para volcarla a un fichero asociándola al keyfile (Read-Host -AsSecureString , ConvertFrom-SecureString -Key).
$CifradoKeyFile = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($CifradoKeyFile)
$CifradoKeyFile | Out-File "C:\Passwords\CifradoKeyFile.key"

Read-Host -AsSecureString "Establece una Password" | ConvertFrom-SecureString -Key (Get-Content "C:\Passwords\CifradoKeyFile.key") | Set-Content "C:\Passwords\fichero-passwd-cifrada"
Para descifrar y leer el contenido cifrado a través de un script Powershell se concatena el fichero de password cifrado y su keyfile (ConvertTo-SecureString -Key).
Get-Content "C:\Passwords\fichero-passwd-cifrada" | ConvertTo-SecureString -Key (Get-Content "C:\Passwords\CifradoKeyFile.key")

¿Cómo parametrizar usuario y password en un script Powershell sin establecer la password en texto claro?

Haciendo uso de lo anterior, usando un fichero key para que la password pueda ser leída desde cualquier usuario o máquina, un ejemplo podría ser el siguiente.
$password = Get-Content C:\Passwords\password.txt | ConvertTo-SecureString -Key (Get-Content C:\Passwords\aes.key)
$credential = New-Object System.Management.Automation.PsCredential("Username",$password)
Repositorio donde se muestra este método con generación de keyfile y un video demo PoC.

ConverTo-SecureString hace uso de DPAPI (Data Protection API) usando un algoritmo de cifrado AES256 en versiones modernas o 3DES en antiguas, crea un hash en base a la clave del usuario. Más info de como funciona el proceso de cifrado.

Liberar o eliminar las passwords almacenadas en un puntero de memoria

Cuando se crea una cadena tipo SecureString esta es almacenada en un espacio de memoria a parte, donde el recolector de basura de .NET de Powershell (CG - Garbage Collector) no puede acceder por lo que es recomendable vaciar este espacio de memoria que se asigna a un puntero.

ZeroFreeCoTaskMemUnicode: Libera un puntero a una cadena no administrada que se ha asignado con el método.

En el siguiente ejemplo se muestra como se crea una cadena segura y se almacenada en un variable. Se convierte a texto claro gracias a que conocemos el indicador del puntero en memoria y finalmente liberamos ese puntero. Con esto evitará el almacenamiento en memoria de la credencial almacenada. 
PS C:\> $sec = Read-Host -AsSecureString
*******
PS C:\> $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
PS C:\> $ptr
114228428
PS C:\> $plaintext = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)
PS C:\> $plaintext
Abc123.
PS C:\> [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($ptr)
Saludos!

15 enero, 2019

Ejecutar WMIC en equipos remotos de la red local (Windows Management Instrumentation)

Si nos surgen problemas para la ejecución sentencias WMIC en máquinas o nodos remotos, mostraré los errores más comunes y como solucionarlos.

Un error puede ser que no esté habilitado las llamadas a procedimientos remotos (RPC).
Error:
Descripción = El servidor RPC no está disponible.
Error - "El servidor RPC no está disponible" (wmic)
Figura 1: Error - "El servidor RPC no está disponible" (wmic).

Otro error común podría ser la falta de permisos para ejecutar WMIC en nodos remotos.
Error:
Descripción = Acceso denegado.
Error - "El servidor RPC no está disponible" (wmic)
Figura 2: Error - "Acceso denegado" (wmic).

Comprobar que el servicio "Instrumental de administración de Windows" (Winmgmt) está habilitado en el tipo de inicio automático y esté en ejecución.

Servicios winmgmt (wmic) en Windows
Figura 3: Servicios winmgmt (wmic) en Windows.

Habilitar la regla por aplicaciones permitidas del firewal (WFAS) de Windows para permitir comunicaciones y llamadas RPC de WMI. Dependiendo cada caso si se trata de una red privada o de dominio.

Reglas del WFAS (Windows Firewall Advanced Security) permitir la comunicación para WMI
Figura 4: Reglas del WFAS (Windows Firewall Advanced Security) permitir la comunicación para WMI.

Verificar que el uso compartido de archivos e impresoras esté activado para el tipo de red según sea el caso. Por defecto en una red de dominio esta característica suele estar activada por defecto cuando un equipo cliente se uno al dominio.

Activar el uso de recurso compartido de archivos e impresoras
Figura 5: Activar el uso de recurso compartido de archivos e impresoras.

Comprobar que en la consola del equipo remoto haya permisos suficientes para el usuario que ejecutará wmic.

Esto se puede modificar en la consola de Microsoft "wmimgmt.msc", en la pestaña de seguridad, se modifican los permisos para permitir la "Llamada remota habilita" y "Ejecutar métodos".

Permisos de seguridad al Control WMI
Figura 6: Permisos de seguridad al Control WMI.

Por último, y algo fundamental según las pruebas que he realizado, es que independientemente de si el equipo cliente remoto en el que se quiere ejecutar WMI forme parte de una red de dominio o una red privada. Será necesario crear un valor en el registro de Windows "LocalAccountTokenFilterPolicy" algo ya comentado en este artículo.

Desde mi punto de vista esto no es aconsejable a métodos de seguridad, no es para nada una buena práctica, pero si se trata de casos puntuales en los que se necesita realizar una serie de acciones remotas simplemente, por seguridad aconsejo volver a eliminar este valor del registro.

Para poder ejecutar este valor en el registro podemos hacerlo ejecutando una CMD en el equipo remoto a través de PsExec (PsTools de Sysinternals). En este artículo se detalla como hacerlo.

El valor LocalAccountTokenFilterPolicy se trata básicamente de "deshabilitar" el UAC (User Account Control) para la ejecución de acciones remotas.

Para añadir el valor LocalAccountTokenFilterPolicy a través de una CMD:
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
Para posteriormente eliminar el valor LocalAccountTokenFilterPolicy a través de una CMD:
reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /f

En el siguiente ejemplo se puede ver como se ejecuta WMIC remotamente desde un equipo local a un equipo remoto usando "wmic /node", especificando la dirección IP local o el hostname del equipo remoto y un usuario/password con privilegios administrativos en la máquina remota.
wmic /node:ip_hostname /user:usuario /password:password bios get serialnumber
Ejecución remota de "wmic /node"
Figura 7: Ejecución remota de "wmic /node".

Saludos!

10 enero, 2019

Ejecutar una CMD en un equipo remoto con psexec

Esto es algo que suelo utilizar en muchos casos cuando los servicios para administraciones remotas que necesito en ese momento no están habilitados en el equipo remoto.

O bien me conecto con este tip para ejecutar una CMD en el equipo remoto y habilitar los servicios que sean necesarios para posteriormente administrar el equipo remoto de forma más cómoda a través del registro remoto (regedit) o los snap-ins MSC (administrador de dispositivos, impresoras, firewall, servicios, etc.) de administración remota añadidos a través de una MMC (Microsoft Management Console).

Como levantamos una CMD con privilegios administrativos ya sea de un administrador local o de dominio podemos ejecutar acciones remotas mediante la consola, "netsh" para la administración de redes o Firewall, "sc" para servicios, "reg" para la manipulación de entradas del registro, "wmic" instrumental de administración de Windows, etc. Aunque como comentaba anteriormente es más cómodo invocar las propias consolas de administración remotas MSC de Microsoft.

Para esto será necesario descargar psexec, parte de la colección de herramientas de Sysinternals de Microsoft.

Haciendo uso de PsExec ejecutamos lo siguiente en una CMD con privilegios de nuestro equipo local.
psexec \\EquipoRemoto -u UserAdmin -p Password cmd.exe
  • EquipoRemoto: nombre o IP del equipo remoto al que nos queremos conectar.
  • UserAdmin: usuario con privilegios de administrador local o de dominio sobre la máquina remota.
  • Password: Passoword del usuario establecido anteriormente.
  • Seguidamente indicamos la aplicación a ejecutar de forma remota, en este caso sería una CMD remota, por lo tanto "cmd.exe" o indicar la ruta absoluta para este binario o el que sea. "C:\Windows\System32\cmd.exe"
  • Con el parámetro psexec /i indicamos una interacción GUI con ventana del equipo remoto. "C:\Windows\regedit.exe", etc.
Podemos usar el parámetro -h para ejecutar el token de elevación si en el sistema remoto tiene habilitado el UAC. Y el parámetro -s cmd.exe para ejecutar el proceso remoto en la cuenta del sistema.

En la siguiente captura se puede ver un ejemplo y una comprobación consultando las IPs y un whoami de como realmente estamos estamos dentro del equipo remoto.
Ejecución de una CMD en un equipo remoto con psexec
Figura 1: Ejecución de una CMD en un equipo remoto con psexec.

En el caso de que obtengamos un error de acceso denegado, comparto el siguiente artículo como referencia para realizar la configuración previa WinRM.

Entradas Populares