2 puntos por GN⁺ 2025-04-30 | 1 comentarios | Compartir por WhatsApp
  • Un operador de blog personal envía una Zip Bomb basada en gzip como respuesta HTTP a bots maliciosos para reducir el escaneo de vulnerabilidades, el spam y el scraping de contenido
  • Aprovecha el flujo de Accept-Encoding: gzip, deflate que usan los navegadores y crawlers legítimos, y devuelve 200 OK junto con Content-Encoding: gzip a las solicitudes sospechosas
  • Un archivo gzip de 1 MB se expande a unos 1 GB al descomprimirse, y uno de 10 MB a unos 10 GB, por lo que muchos bots agotan la memoria o abandonan la solicitud
  • El middleware del servidor revisa IPs en lista negra y patrones de spam, y si se cumple la condición envía un archivo Zip Bomb pregenerado y termina de procesar la solicitud
  • No es una defensa completa porque puede detectarse y evitarse con facilidad, pero es suficiente para frenar bots simples que entorpecen el servidor con crawling indiscriminado

Tráfico de bots y contexto del uso de Zip Bombs

  • La mayor parte del tráfico web proviene de bots, y algunos tienen usos legítimos como los lectores RSS, los crawlers de motores de búsqueda y los bots de IA que buscan contenido nuevo
  • El problema son los bots maliciosos operados por spammers, scrapers de contenido y hackers
    • En un trabajo anterior, bots encontraron vulnerabilidades de WordPress e insertaron scripts maliciosos en el servidor
    • Ese servidor terminó siendo parte de una botnet usada para DDoS
    • Uno de sus primeros sitios web fue completamente excluido de las búsquedas de Google por el spam generado por bots
  • Después de esas experiencias, empezó a usar Zip Bombs para proteger el servidor de bots maliciosos

Cómo convertir la compresión gzip en un mecanismo de defensa

  • Una Zip Bomb es un archivo comprimido pequeño que durante la descompresión se expande hasta convertirse en un archivo muy grande y carga la máquina
  • En los inicios de la web, la compresión gzip se introdujo para reducir la cantidad de datos transferidos en conexiones lentas
    • Si un archivo HTML de 50 KB se reducía a 10 KB, se ahorraban 40 KB de transferencia
    • En internet por marcación telefónica, eso podía bajar el tiempo de descarga de una página de 12 a 3 segundos
  • Al hacer una solicitud, el navegador informa mediante headers qué métodos de compresión soporta
Accept-Encoding: gzip, deflate
  • Si el servidor también soporta compresión, devuelve una versión comprimida de los datos esperados
  • Los bots de web crawling también soportan compresión como gzip para recopilar grandes volúmenes de datos, y esa característica se aprovecha como defensa

Respuesta enviada a solicitudes maliciosas

  • En el blog aparecen con frecuencia bots que escanean vulnerabilidades de seguridad, y la mayoría se ignoran
  • Pero si una solicitud parece intentar inyectar entradas maliciosas o explorar respuestas, se devuelve una respuesta gzip junto con 200 OK
Content-Encoding: gzip
  • El tamaño del archivo enviado varía entre 1 MB y 10 MB según la situación
    • Un archivo de 1 MB se expande a unos 1 GB al descomprimirse
    • Un archivo de 10 MB se expande a unos 10 GB al descomprimirse
  • El bot ve el header, determina que es un archivo comprimido e intenta descomprimirlo para buscar el contenido
  • A medida que el archivo sigue expandiéndose, agota la memoria y el servidor o script puede colapsar
  • Para scripts persistentes a los que no les basta un archivo de 1 MB, se envía uno de 10 MB, y se afirma que en ese caso el script termina de inmediato

Ejemplo de creación de una Zip Bomb y aplicación en el servidor

  • Al crear una Zip Bomb hay que asumir el riesgo, porque puede colapsar o dañar tu propio dispositivo
  • Un archivo gzip que se descomprime hasta 10 GB se genera con el siguiente comando
dd if=/dev/zero bs=1G count=10 | gzip -c > 10GB.gz
  • La composición del comando es la siguiente
    • dd: comando para copiar o transformar datos
    • if=/dev/zero: usa como entrada un archivo especial que genera un flujo infinito de bytes en 0
    • bs=1G: establece el tamaño de bloque en 1 GB
    • count=10: procesa 10 bloques de 1 GB para generar 10 GB de datos en 0
    • gzip -c > 10GB.gz: comprime los datos de salida con gzip y los guarda en el archivo 10GB.gz
  • En este caso, el archivo resultante mide alrededor de 10 MB
  • En el servidor se agrega actualmente un middleware que verifica si la solicitud es maliciosa
    • Se mantiene una lista negra de IPs que escanean repetidamente todo el sitio
    • También se usan para la detección patrones en los que dejan spam y luego vuelven a comprobar si ese spam apareció en la página
if (ipIsBlackListed() || isMalicious()) {
    header("Content-Encoding: gzip");
    header("Content-Length: ". filesize(ZIP_BOMB_FILE_10G)); // 10 MB
    readfile(ZIP_BOMB_FILE_10G);
    exit;
}
  • El costo es que, en ciertas situaciones, el servidor debe transferir un archivo de 10 MB
  • Cuando una publicación se vuelve viral, se reduce a un archivo de 1 MB, que según el autor también funciona

Límites y alcance de uso

  • Una Zip Bomb no es una defensa completa
    • Puede detectarse fácilmente
    • Puede evitarse
    • El cliente podría leer solo parte del contenido
  • Aun así, es suficiente como herramienta para frenar bots poco sofisticados que rastrean la web sin criterio y entorpecen el servidor
  • Se puede ver un ejemplo de funcionamiento en una reproducción de logs del servidor: this replay of my server logs

1 comentarios

 
GN⁺ 2025-04-30
Opiniones de Hacker News
  • Alrededor de 2001 hubo una época en la que tenía una línea fija en casa y alojaba varias cosas en una máquina Linux doméstica.
    Por una actualización de Windows NT, muchos sistemas activaron una función de cifrado oportunista que intentaba conectarse primero a cierto puerto para negociar s/wan y luego enviar tráfico TCP, y como veía seguido ese tráfico en el firewall no le di mucha importancia.
    Pero había una máquina en particular que seguía intentando conectarse cada pocos segundos y era muy molesta; intenté contactar al administrador, pero no pude.
    Al final avisé algo como “estoy por iniciar un nuevo servicio en ese puerto, espero que no cause problemas”, y como no hubo respuesta, levanté en ese puerto un servidor que leía de /dev/urandom y tenía activado TCP_NODELAY, entre otras cosas, para empujar datos aleatorios lo más rápido posible.
    La máquina NT mal configurada se conectaba, se tragaba datos aleatorios durante unos 5 segundos y desaparecía; 5 minutos después volvía, tomaba otra dosis de desbordamiento de búfer y desaparecía otra vez. Repitió ese patrón durante semanas hasta que desapareció por completo de Internet.
    Suelo imaginar a algún administrador rascándose la cabeza, preguntándose por qué la máquina NT no dejaba de reiniciarse.

    • Si eres programador, siempre debes poner un límite máximo a la cantidad de datos que recibes de otros.
      Toda solicitud debería tener tanto un límite de tiempo como un límite en la cantidad de datos que consumirá.
    • Por una época similar, una empresa mandaba fax spam todos los viernes, e ignoró varios mensajes de voz educados que les dejé.
      Así que hice un PDF de 100 páginas donde cada página era un gran rectángulo negro y lo mandé por una pasarela de email a fax, que en ese entonces era algo nuevo; en menos de una hora recibí una llamada furiosa, y los faxes se detuvieron.
    • Me da curiosidad cómo solían encontrar en esa época los datos de contacto del administrador de un cliente cualquiera.
      La parte de “intenté contactar al administrador de la máquina, y eso era algo común” me parece especialmente interesante.
    • Una vez hice un arreglo bastante improvisado para detectar caídas en mi servidor RPi doméstico: le hacía ping a un dominio que poseía y, si fallaba, asumía que se había caído la red y reiniciaba.
      Después dejé vencer el dominio y esa RPi se moría cada 5 minutos; pensé que era un problema de energía, hasta que más tarde recordé esa tarea CRON.
    • Quizá te sorprendería saber que, en esa época, la mayoría de las instalaciones NT que prestaban servicios casi no tenían administradores capaces de darse cuenta de qué estaba pasando.
      En miles de casos, la razón misma para correr este tipo de servicios en una máquina NT era “para no necesitar un administrador”, y no hay que subestimarlo.
      En los 90 y principios de los 2000 puse muchos servidores en Internet, y la práctica estándar en toda la industria era usar NT para no tener administrador.
  • Cuando era chico, hice una tontería a modo de broma en mi página web: ln -s /dev/zero index.html.
    Los navegadores de la época no lo manejaban bien y casi se colgaban; a veces incluso tumbaban también el sistema del cliente.
    Creo que más tarde los navegadores empezaron a revisar el contenido real y a cortar ese tipo de solicitudes.

    • Una vez alimenté un encoder una y otra vez con la misma fila de macrobloques y creé un JPEG de 64k×64k.
      Recién varios años después pude abrirlo finalmente.
    • Me pregunto si sería posible crear un archivo HTML de 500 TB sobre squashfs, con encabezados adecuados y contenido interminable sin etiquetas de cierre, y hacer que el servidor no informe el tamaño del archivo antes de la descarga.
      ¿Alguna idea?
    • Me recuerda a aquel favicon.ico que mataba navegadores.
      Creo que quizá era este: https://freedomhacker.net/annoying-favicon-crash-bug-firefox...
    • Espero que no haya sido una situación en la que te cobraban el ancho de banda por KiB.
    • Tal vez ya sea hora de crear un dispositivo /dev/zipbomb.
  • Hoy casi todos los navegadores aceptan zstd y brotli, así que este tipo de bombas podría ser aún más efectivo ahora.
    Este comentario antiguo mostraba una impresionante relación de compresión de 1.2M:1, y zstd parece estar haciéndolo todavía mejor.
    Aunque puede que los bots no soporten estándares de compresión modernos.
    Por otro lado, eso podría ser una buena forma de bloquear bots: como todos los navegadores modernos soportan zstd, si lo aplicas de forma forzada a agentes de navegador que no estén en una lista permitida, puedes confundir automáticamente a los scrapers.

    • De hecho, en mi demo de Datastar de one million checkboxes[1] estoy filtrando bots mediante compresión.
      Depende en gran medida de transmitir la vista completa del usuario en cada interacción, y usando brotli sobre SSE se obtienen fácilmente relaciones de compresión de 200:1[2].
      El problema es que un actor malicioso puede pedir un stream sin compresión.
      Como brotli está soportado por el 98% de los navegadores, no envío datos a clientes que no soporten compresión brotli, y como muchos scrapers y bots tampoco la soportan, funciona bastante bien.
      [1] demo de checkboxes
      https://checkboxes.andersmurphy.com
      [2] artículo sobre brotli SSE
      https://andersmurphy.com/2025/04/15/why-you-should-use-brotl...
    • Si anidas gzip dentro de otro gzip, se vuelve todavía más pequeño.
      Es porque, en gzip de primera generación, el propio bloque de datos 0 comprimidos tiene baja entropía, y zst anidado reduce un archivo de 10G a 99 bytes.
    • Me pregunto cómo reaccionaría mi navegador si recibiera una bomba así.
      No quiero probarlo personalmente.
    • gzip está en todas partes y puede fastidiar a todos los crawlers
  • Aunque se sale un poco del tema, me pareció divertido lo de que, en un trabajo anterior, un bot encontró una vulnerabilidad de WordPress y metió un script malicioso en el servidor
    Me dio cierta tranquilidad saber que no soy el único al que, apenas 1 hora después de instalar WordPress, se le despliega mágicamente una shell PHP en el servidor

    • Cuando recibes el sitio WordPress de un cliente, termina siendo: “ah, aquí hay 3 shells PHP con nombres de cadenas aleatorias”
      Nunca hay menos de 3; siempre está garantizado
    • Si quieres conservar la cordura, no deberías autohospedar WordPress
      Aunque no sea en la primera hora, en algún momento olvidarás aplicar un parche y acabará explotando
    • Nunca he alojado WordPress, pero en cuanto expones un servidor HTTP a Internet empiezan a llegar solicitudes como /wp-login
      También sirve como buena forma de encontrar bots: si veo una IP pidiendo rutas relacionadas con CMS conocidos, la mando directo a un agujero de iptables
    • WordPress es una excelente puerta trasera, y además trae funciones de CMS integradas
    • Una vez usé esto al enseñar DevOps
      Les decía “desplieguen su primer servidor hello world con nginx” y enseguida empezaban a verse solicitudes raras en los logs
  • Hice algo parecido con ssh: encontré una forma de matar al cliente ssh que estaba intentando adivinar la contraseña de root
    A cambio, varios script kiddies lanzaron DDoS contra mi pequeño servidor, así que terminé cambiando a identificar a los actores que claramente estaban haciendo cosas malas y bloquear sus IP con reglas de firewall
    Aunque en IPv6 esto se está volviendo más difícil
    Si alguien hace sus propias páginas web, también podría poner una zip bomb en la página mediante un enlace invisible para el ojo humano
    Algo como texto blanco sobre fondo blanco, un anchor sin resaltado al hacer hover/click; el bot lo descarga y lo revisa, y lo mismo harían los crawlers y scrapers de IA

    • Usé una variante de esto en el formulario de solicitud de cuenta de mi servidor del fediverso
      El problema eran bots muy simples que recorrían la web y enviaban spam burdo a cualquier formulario que pareciera publicarse
      Al principio agregué un CAPTCHA simple con caracteres distorsionados, y eso bloqueó a muchos bots, pero no a todos
      Al revisar los logs del servidor, vi que estos bots solo hacían tres solicitudes rápidas: la página con el formulario, la imagen del CAPTCHA y el POST de los datos del formulario; no cargaban nada de CSS ni JS
      Así que agregué algunos campos más al formulario, los oculté con CSS y, si enviaban cualquier cosa en esos campos, hacía fallar la solicitud y bloqueaba la sesión
      Además, hice que la imagen del CAPTCHA fuera un fondo CSS y cambié el src por una imagen transparente; el spam se detuvo por completo y los usuarios reales no notaron nada
    • Si quieres frenar ese comportamiento, vale la pena revisar esto
      https://github.com/skeeto/endlessh
    • Me preocupa qué pasaría con los usuarios de lectores de pantalla si el enlace es invisible para el ojo humano
    • No entiendo por qué bloquear con firewall es más difícil en IPv6
      Entre los dos, más bien parece más fácil
    • Ese tipo de enlaces puede ser visible para personas que usan navegadores de texto, lectores de pantalla, bookmarklets que listan los enlaces de una página, etc.
  • Las zip bombs son divertidas
    Una vez encontré una vulnerabilidad en un producto de seguridad: no hacía bien el análisis de malware si era un archivo zip por encima de cierto tamaño, o si el archivo contenía uno
    En la práctica, si metías una zip bomb dentro de un documento Office XML, el producto podía dejar pasar el archivo OOXML aunque contuviera malware fácilmente identificable

    • El problema del tamaño de archivo todavía persiste en muchos EDR conocidos
  • Probé desplegar esto en lugar del script de honeypot que usaba normalmente, pero no parece funcionar bien
    En los logs del servidor web veo que los bots no descargan completo el veneno de 10 MB, sino que cortan en distintas longitudes
    Hasta ahora no he visto que se lleven más de unos 1.5 MB
    ¿O quizá sí está funcionando? Tal vez mueren al decodificar sobre la marcha como stream
    Por ejemplo, si queda registrado que leyeron 1.5 MB, quizá al decodificarlos al vuelo en memoria hasta 1.5 GB terminan crasheando
    No hay forma de comprobarlo

    • Valdría la pena intentar un laberinto de contenido
      Algo como contenido generado infinitamente, con montones de referencias a otras páginas generadas
      Puede ayudar contra wget simple y contra bots hasta que se adapten
      Dicho sea de paso, yo estoy del lado de los bots, pero no me molesta ayudar
    • Tal vez habría que aleatorizar a medias el tamaño del archivo
      Sospecho que algunos bots tienen un límite duro para el tamaño de los recursos que descargan
      Como muchos son molestos bots de entrenamiento/scraping para LLM, incluso si enviar una zip bomb de 800 KB no los mata, al menos puede desperdiciar sus recursos de cómputo
    • Si vuelve, significa que lo detectó y lo evitó; si no vuelve, crasheó, así que misión cumplida
  • Vale la pena señalar que esto no es un archivo zip clásico, sino una gzip bomb
    No es el método de tumbar antivirus con zips anidados, sino que se comporta como una página web normal comprimida

  • Hace poco, parte de la infraestructura de elusión de censura de Tor Project se ejecutaba en el mismo sitio que una publicación de blog sobre zip bombs[0]
    Uno de esos archivos zip fue rastreado por Google y terminó en una lista de dominios maliciosos, lo que rompió una parte bastante importante de la herramienta Snowflake de Tor
    Tardaron semanas en resolverlo[1]
    [0] https://www.bamsoftware.com/hacks/zipbomb/
    [1] https://www.bamsoftware.com/hacks/zipbomb/#safebrowsing

  • Para proteger las cargas de mi aplicación, creaba particiones temporales de disco de tamaño fijo de unos 10 MB cada una y descomprimía ahí
    Si alguien subía algo demasiado grande, el daño quedaba contenido ahí dentro

    • unzip -p | head -c 10MB
    • ¿O sea que particionaste el disco cuando bastaba con no descomprimir archivos absurdamente grandes?