
Cosas divertidas contra el abuso de la reciente vulnerabilidad CVE-2021-44228 (Log4Shell) usando servidores web comunes.
Cosas divertidas contra el abuso de la reciente vulnerabilidad CVE-2021-44228 (Log4Shell) usando servidores web comunes.
Basado en el post de @shipilev (https://gist.github.com/shipilev/92e709a868f3d328b6636e1bfc21cf09) porté su ejemplo a Apache2. Un compañero de trabajo lo hizo para Lighttpd. Decidí hacer públicos nuestros ejemplos por conveniencia.
Hay pocas razones para poner la cadena "jndi:" en cabeceras de petición, User Agents o en cualquier otro sitio. Actualmente, solo conozco una única razón para hacerlo: la explotación de CVE-2021-44228. Mientras el mundo está, con suerte, ocupado parcheando todas las implementaciones de las versiones vulnerables de Log4j, podría ser razonable frenar a los atacantes tanto como sea posible. Entonces, ¿qué tal servirles algunos gigabytes de sinsentido mientras intentan explotar tus servicios?
Los siguientes fragmentos de código no protegen tus dispositivos y servicios contra el 0-Day de Log4Shell. ¡Actualiza el software vulnerable, usa log4j2.formatMsgNoLookups=true para deshabilitar las búsquedas jndi o ponlo fuera de línea hasta que haya un parche disponible! Usa esto solo en servidores sin servicios habilitados con Log4j. Más información sobre cómo mitigar CVE-2021-44228: https://research.hisolutions.com/log4shell
Esto tampoco cubrirá llamadas ofuscadas como ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://${hostName}.} ni cualquier otra cosa que intente ocultar la parte "jndi:". Como no hay una solución sencilla para eso, no cubriré técnicas de detección más avanzadas por ahora. Aún así creo que la mayoría de los ataques no usarán esas técnicas, por lo que todavía podemos molestar a la mayoría de los script kiddies. :)
En Linux, crea un archivo con algún mensaje HTML aleatorio. Por favor, no uses el LOL del ejemplo de abajo, ya que facilita que el atacante implemente un filtro genérico para evadirnos. Estamos usando la utilidad pv para mostrar el progreso de la creación del archivo; puede que tengas que instalarla con el gestor de paquetes de tu preferencia u omitirla simplemente.
$ awk 'BEGIN { for(c=0;c<10000000;c++) printf "<p>LOL</p>" }' > 100M.html
$ (for I in `seq 1 100`; do cat 100M.html; done) | pv | gzip -9 > 10G.boomgz
$ rm 100M.html
Asumiendo que tu servidor web se ejecuta como www-data, creemos un directorio propiedad de www-data para no tener que subir una copia en cada webroot que el servidor web pueda estar sirviendo:
mkdir /bombs
mv 10G.boomgz /bombs
chown -R www-data:www-data /bombs
Ahora viene la parte divertida...
Ver https://gist.github.com/shipilev/92e709a868f3d328b6636e1bfc21cf09
Todo el crédito es para @shipilev
Habilita los módulos necesarios
a2enmod rewrite headers ratelimit
Navega hasta /etc/apache2/sites-enabled. Abre cada archivo de configuración de host con tu editor favorito e inserta el siguiente fragmento de código justo encima de cada línea que contenga (puede haber más de una):
RewriteEngine On
RewriteCond %{THE_REQUEST} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{QUERY_STRING} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{REQUEST_URI} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{HTTP_COOKIE} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{HTTP_HOST} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{REMOTE_HOST} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{REMOTE_USER} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{HTTP_USER_AGENT} "^.*(\${jndi|\${\${).*$" [OR]
RewriteCond %{HTTP_REFERER} "^.*(\${jndi|\${\${).*$"
RewriteRule . /bombs/10G_lol.boomgz [L]
<Files ~ "\.boomgz$">
Header Set Expires "Sat, 1 Jan 2000 00:00:00 GMT"
Header Set Content-Encoding "gzip"
Header Set Content-Type "text/html"
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 100
</Files>
<Directory /bombs>
allow from allow
Require all granted
</Directory>
Puede que te preguntes por qué hay tantas variables más que en el ejemplo inicial de @shipilev. Decidí intentar cubrir tantas ubicaciones como fuera posible. Esto podría interrumpir servicios en algunos casos muy raros, así que si quieres usar el conjunto de comprobaciones original, simplemente comenta o elimina las primeras 7 líneas después de la declaración RewriteEngine On y quita las partes |\${\${ de las líneas restantes.
También puedes poner el código en un archivo nuevo, por ejemplo /etc/apache2/conf-available/anti-jndi.conf e incluirlo de esta manera:
Include /etc/apache2/conf-available/anti-jndi.conf
Ahora guarda los archivos y recarga la configuración de Apache2:
systemctl reload apache2
Si todo salió bien, no deberías recibir un mensaje de error.
Próximamente
Puedes comprobar si lo lograste conectándote a tu sitio web modificado mediante curl (recuerda reemplazar your-hostname por el nombre de host real de uno de los servicios que acabas de editar):
curl -s -L your-hostname -A "\${jndi:testing}" | pv > /dev/null
Deberías ver una barra de progreso que muestra una velocidad de descarga de alrededor de 100kb/s. Si no la cancelas, debería terminar después de algunos minutos, dependiendo de lo que hayas usado como cadena en el archivo HTML inicial. A mí me tomó alrededor de 5 minutos. Ahora comprueba qué está sucediendo en el lado del cliente:
curl -s --compressed -L your-hostname -A "\${jndi:testing}" | pv > /dev/null
¿Ves cómo ya no son 100kb/s? La compresión hace su magia: son algunos gigabytes en el lado del cliente. Así que después de descargar un montón de sinsentido durante algunos minutos, el atacante tiene algunos gigabytes por ahí, asumiendo que los datos se almacenan para su análisis. ¿Quién sabe? :)