Artículo técnico

Análisis seguro de memoria de PDFs: Defendiendo contra documentos maliciosos

Los documentos PDF pueden hacer una gran cantidad de cosas, y esa flexibilidad conlleva riesgos de seguridad inherentes. Debido a que los PDF admiten archivos incrustados, JavaScript interactivo y secuencias binarias complejas, frecuentemente se utilizan como vectores para la entrega de malware. Desbordamientos de búfer (buffer overflows), lecturas fuera de límites y desbordamientos de enteros en analizadores sintácticos de PDF mal escritos pueden llevar a la ejecución remota de código (RCE)

Si está construyendo una aplicación en Delphi que acepta PDFs subidos por el usuario (por ejemplo, un portal de ingestión de documentos), asegurar un análisis de PDF seguro en memoria es un requisito de seguridad crítico

Vectores de ataque comunes en PDF

Los PDFs maliciosos normalmente apuntan a vulnerabilidades en el analizador en sí más que en el sistema operativo. Las técnicas comunes incluyen:

  • Tablas de referencias cruzadas (XRef) malformadas: Elaboración de desplazamientos de puntero que llevan fuera de límites, bloqueando el analizador o permitiendo la divulgación de memoria
  • Bucles infinitos: Creación de referencias circulares entre objetos PDF (por ej., el Objeto A hace referencia al Objeto B, el cual hace referencia al Objeto A) llevando al agotamiento de la pila
  • Descompresión explosiva (Bombas Zip): Secuencias FlateDecode que se descomprimen desde unos pocos kilobytes a gigabytes, agotando la memoria del sistema

Estrategias defensivas de análisis en Delphi

Cuando analice PDFs de forma nativa en Delphi, debe programar a la defensiva. No puede confiar en los metadatos proporcionados en los diccionarios PDF

1. Romper referencias circulares

Cuando recorra recursivamente un árbol de objetos PDF, debe mantener un historial de los objetos visitados para prevenir bucles infinitos

uses
  System.Generics.Collections, System.SysUtils;

// A safe recursive function to walk the PDF tree
procedure ParsePDFDictionary(DictObj: TPDFDictionary; Visited: TList<Integer>);
var
  ObjID: Integer;
begin
  ObjID := DictObj.ObjectID;
  
  if Visited.Contains(ObjID) then
  begin
    Writeln('Warning: Circular reference detected. Aborting branch.');
    Exit;
  end;
  
  Visited.Add(ObjID);
  
  try
    // Process child objects safely...
  finally
    // Allow siblings to traverse, but prevent vertical recursion loops
    Visited.Remove(ObjID);
  end;
end;

2. Protegerse contra las Bombas Zip

Cuando aplique el filtro FlateDecode para descomprimir una secuencia, debe limitar estrictamente el tamaño máximo de expansión. Nunca asigne memoria a ciegas basándose en la clave de diccionario /Length

const
  MAX_DECOMPRESSED_SIZE = 1024 * 1024 * 50; // 50 MB safety limit

procedure DecompressPDFStream(CompressedStream, OutputTarget: TStream);
var
  ZLibStream: TZDecompressionStream;
  Buffer: array[0..8191] of Byte;
  BytesRead, TotalRead: Integer;
begin
  ZLibStream := TZDecompressionStream.Create(CompressedStream);
  try
    TotalRead := 0;
    repeat
      BytesRead := ZLibStream.Read(Buffer[0], SizeOf(Buffer));
      if BytesRead > 0 then
      begin
        TotalRead := TotalRead + BytesRead;
        if TotalRead > MAX_DECOMPRESSED_SIZE then
          raise Exception.Create('Security Exception: Decompression bomb detected!');
          
        OutputTarget.WriteBuffer(Buffer[0], BytesRead);
      end;
    until BytesRead = 0;
  finally
    ZLibStream.Free;
  end;
end;

Aprovechar motores endurecidos y componentes seguros

Escribir un analizador de PDF completamente seguro desde cero es una tarea monumental. El enfoque estándar de la industria es utilizar un motor endurecido y fuertemente sometido a pruebas de fuzzing como PDFium, o apoyarse en bibliotecas nativas rigurosamente probadas

PDFium es el motor de renderizado central utilizado por Google Chrome. Debido a que Chrome procesa millones de PDFs no confiables diariamente, PDFium está sometido a pruebas de fuzzing continuas y agresivas a través de OSS-Fuzz y ClusterFuzz. Maneja de manera elegante XRefs malformadas, secuencias rotas y referencias cíclicas

De manera similar, los componentes nativos como HotPDF Component y Delphi PDF Library incorporan estrategias de análisis defensivo bien probadas de forma predeterminada. Implementan una verificación estricta de límites, limitadores de profundidad recursiva y mecanismos de prevención de fugas de memoria diseñenos específicamente para los entornos Delphi y C++Builder

Ya sea que elija consumir PDFium a través de un envoltorio de Delphi para el renderizado, o utilice componentes nativos como HotPDF para la generación y procesamiento de documentos, hereda un perímetro de seguridad de grado empresarial, protegiendo a sus usuarios y sus servidores de cargas maliciosas sin tener que escribir analizadores defensivos usted mismo

Nota: Las capacidades de análisis seguras y sometidas a fuzzing están disponibles en toda nuestra suite, incluyendo HotPDF Component, Delphi PDF Library, y PDFium Component