===== socat con HTTP/HTTPS: Redireccionar tráfico / Crear Tuneles / Cifrar tráfico HTTP =====
Socat es una herramienta muy popular y útil para crear túneles que permitan redireccionar tráfico de una IP/Puerto a otra IP/Puerto diferente, entre otras muchas cosas. También es usada para intermediar entre un protocolo no cifrado, por ejemplo HTTP y uno cifrado HTTPS. Hay entornos empresariales donde aplicaciones antediluvianas son un impedimento para poder desplegar protocolos de cifrado más modernos. Por ejemplo aplicaciones antiguas no suelen ser compatibles con TLS 1.3.
En este tipo de casos, gracias a socat, sería factible crear un túnel para que la aplicación envíe el tráfico sin cifrar a socat y este lo redirija de manera cifrada al destino. También es muy socorrido usarlo para soportar cifrados en protocolos / aplicaciones que no lo implementen de manera nativa o bien lo hacen pero de forma engorrosa.
En este artículo nos centraremos en el protocolo HTTP para los ejemplos y explicaremos los casos más comunes a la hora de querer tunelizar conexiones HTTP/S. Socat y los ejemplos aquí expuestos son igual de válidos para otros protocolos / puertos de red.
Para ver qué hace socat al tunelizar conexiones se pueden agregar las opciones informativas "-x", "-v" y "-d", las cuales pueden combinarse entre si.
-v Writes the transferred data not only to their target streams, but also to stderr. The output format is text with some conversions for readability, and prefixed with "> " or "< " indicating flow directions.
-x Writes the transferred data not only to their target streams, but also to stderr. The output format is hexadecimal, prefixed with "> " or "< " indicating flow directions. Can be combined with -v .
-xv Muestra el hexadecimal pero junto la represetacion ASCII (-v) a la derecha.
-d Without this option, only fatal and error messages are generated; applying this option also prints warning messages. See DIAGNOSTICS for more information.
-d -d Prints fatal, error, warning, and notice messages.
-d -d -d Prints fatal, error, warning, notice, and info messages.
-d -d -d -d Prints fatal, error, warning, notice, info, and debug messages.
==== HTTP > System ====
El tráfico entrante por localhost:8080 obtendrá como respuesta la salida de determinados comandos que se especifiquen en socat. Es muy útil cuando se necesita probar un software devolviendo una determinada respuesta a sus peticiones. Veamos un ejemplo devolviendo unas cabeceras "falsas" mediante HTTP.
socat TCP-LISTEN:8080,bind=127.0.0.1,crlf,reuseaddr,fork SYSTEM:"echo -e HTTP/4.0 200;echo -e Content-Type\: text/plain;echo 'Hola Caracola'"
# Si se escriben los comandos en un script este puede ser ejecutado de la siguiente forma.
socat TCP-LISTEN:8080,bind=127.0.0.1,crlf,reuseaddr,fork SYSTEM:"bash $HOME/script.sh.sh"
curl -v localhost:8080
* Trying ::1:8080...
* connect to ::1 port 8080 failed: Conexión rehusada
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.74.0
> Accept: */*
>
< HTTP/4.0 200
< Content-Type: text/plain
< Hola Caracola
* Connection #0 to host localhost left intact
==== HTTP > HTTP ====
Escuchar peticiones en un puerto determinado (8080) y que las peticiones entrantes a dicho puerto sean redirigidas al puerto 80 del host "dominio.com "
socat TCP-LISTEN:8080,fork,reuseaddr TCP:www.dominio.com:80
Por norma, las configuraciones de servidores web suelen permitir solicitudes con nombres de dominio que no tienen configurados de manera explicita. Por ejemplo en Nginx, si no se ha configurado un servidor predeterminado, el primer servidor (server_name) configurado es el que responderá las peticiones. Es decir, en el caso anterior, www.dominio.com:80 recibirá la cabecera "Host: localhost:8080". Socat simplemente redirecciona / tuneliza, no edita el tráfico (para ello hay otras aplicaciones). Pero si se quieren hacer peticiones indicando otro dominio/puerto en la cabecera "Host" de HTTP, puede usarse curl de la siguiente manera.
# Se enviará la cabecera "Host": "www.ejemplo.com" y además usa localhost como ip del dominio www.ejemplo.com
curl -vI --resolve www.ejemplo.com:8080:127.0.0.1 http://www.ejemplo.com:8080/bla/bla/page.php -H "Host: www.ejemplo.com"
NOTA: Si no se especifica la cabecera Host, al no usar el mismo puerto en local que en destino, la cabecera será "Host: www.ejemplo.com:8080". Esto no suele ser un problema para servidores web normales, pero servicios CDN como Akamai, Imperva, CloudFront, CloudFlare, etc lo requieren.
==== HTTP > HTTPS ====
Socat puede usarse para tunelizar conexiones HTTP a HTTPS, algo muy útil a la hora de auditar comunicaciones.
Supongamos que una aplicación unicamente puede hacer peticiones HTTP y no HTTPS, con socat se podría especificar un puerto (normalmente en local , pero podría ser remoto también) que solo use HTTP y redirija la comunicación a otro puerto HTTPS. De esta manera socat se encarga de realizar el Handshake y establecer la conversación cifrada HTTPS.
Aunque no sea la mejor herramienta para ello se podría usar para ataques SSL Strip. Editar el fichero /etc/hosts, registros DNS o simplemente crear un dominio muy similar al de una plataforma de compras en linea y servir una versión sin SSL de la misma para auditar las credenciales (SSL MITM).
Se debe tener en cuenta que al usar socat para conexiones SSL/TLS, este comprueba de manera predeterminada la validez (confiable, no revocado, etc) de los certificados con los que conecta.
# El puerto 8080 escucha peticiones no cifradas y las redirecciona usando SSL/TLS al puerto 443 de www.dominio.com.
socat TCP-LISTEN:8080,fork,reuseaddr SSL:www.dominio.com:443
# Si no se requiere que socat compruebe el certificado se puede usar verfy=0
socat TCP-LISTEN:8080,fork,reuseaddr SSL:XX.XX.XX.XX:443,verify=0
# Si se prefiere que socat compruebe el campo "commonname" del certificado para establecer el handshake.
socat TCP-LISTEN:8080,fork,reuseaddr SSL:XX.XX.XX.XX:443,commonname=www.dominio.com
==== IPv4 > IPv6 ====
No todas las aplicaciones que escuchan en un puerto tienen soporte para IPv6, esto es algo que se puede remediar con socat fácilmente.
# Redirige un puerto escuchando en las interfaces IPv6 a su análogo en IPv4
socat TCP6-LISTEN:2560,ipv6only=1,fork,reuseaddr TCP4:127.0.0.1:2560
NOTA: Hay otras opciones muy interesantes y se invita al lector a usar las págians del manual de socat.