En informática , un políglota es un programa o script informático (u otro archivo) escrito en una forma válida de múltiples lenguajes de programación o formatos de archivo . [1] El nombre fue acuñado por analogía con el multilingüismo . Un archivo políglota se compone combinando la sintaxis de dos o más formatos diferentes. [2]
Cuando los formatos de archivo se deben compilar o interpretar como código fuente , se puede decir que el archivo es un programa políglota , aunque los formatos de archivo y la sintaxis del código fuente son fundamentalmente flujos de bytes, y explotar esta característica común es clave para el desarrollo de políglotas. [3] Los archivos políglotas tienen aplicaciones prácticas en compatibilidad , [4] pero también pueden presentar un riesgo de seguridad cuando se usan para eludir la validación o explotar una vulnerabilidad .
Los programas políglotas se han creado como desafíos y curiosidades en la cultura hacker desde al menos principios de los años 1990. Un ejemplo temprano notable, llamado simplemente rec.puzzles, polyglot
se publicó en el grupo Usenet en 1991, admitiendo 8 idiomas, aunque esto se inspiró en programas incluso anteriores. [5] En 2000, un programa políglota fue nombrado ganador en el Concurso Internacional de Código C Ofuscado . [6]
En el siglo XXI, los programas y archivos políglotas ganaron atención como un mecanismo de canal encubierto para la propagación de malware . [3] [7] Los archivos políglotas tienen aplicaciones prácticas en compatibilidad , [8]
Un políglota se compone de una combinación de sintaxis de dos o más formatos diferentes, aprovechando diversas construcciones sintácticas que son comunes entre los formatos o construcciones que son específicas del idioma pero que tienen un significado diferente en cada idioma. Un archivo es un políglota válido si puede ser interpretado correctamente por varios programas de interpretación. Por ejemplo, un políglota PDF-Zip puede abrirse como un documento PDF válido y descomprimirse como un archivo zip válido . Para mantener la validez en todos los programas de interpretación, uno debe asegurarse de que las construcciones específicas de un intérprete no sean interpretadas por otro, y viceversa. Esto se logra a menudo ocultando las construcciones específicas del idioma en segmentos interpretados como comentarios o texto sin formato del otro formato. [1]
Dos técnicas que se utilizan habitualmente para construir un programa políglota son utilizar lenguajes que utilizan caracteres diferentes para los comentarios y redefinir varios tokens como otros en distintos lenguajes. Estas técnicas se demuestran en este programa políglota de dominio público escrito en ANSI C , PHP y bash :
Destacado para Bash
#define a /* #<?php echo "\010¡Hola, mundo!\n" ; // 2 > /dev/null > /dev/null \ ; // 2 > /dev/null ; x = a ; $x = 5 ; // 2 > /dev/null \ ; if (( $x )) // 2 > /dev/null ; then return 0 ; // 2 > /dev/null ; fi #define e ?> #define b */ #include <stdio.h> #define main() int main(void) #define printf printf( #define true ) #define function function main () { printf "Hola, mundo!\n" true/* 2 > /dev/null | grep -v true*/ ; return 0 ; } #define c /* main #*/
Destacado para PHP
#define a /* # <?php echo " \010 ¡Hola, mundo! \n " ; // 2> /dev/null > /dev/null \ ; // 2> /dev/null; x=a; $x = 5 ; // 2> /dev/null \ ; if (( $x )) // 2> /dev/null; then return 0 ; // 2> /dev/null; fi #define e ?> #define b */ #include <stdio.h> #define main() int main(void) #define printf printf( #define true ) #define function function main () { printf "Hola, mundo! \n " true /* 2> /dev/null | grep -v true*/ ; return 0 ; } #define c /* main #*/
Destacado para C
#define a /* #<?php echo "\010¡Hola, mundo!\n";// 2> /dev/null > /dev/null \ ; // 2> /dev/null; x=a; $x=5; // 2> /dev/null \ ; if (($x)) // 2> /dev/null; then return 0; // 2> /dev/null; fi #define e ?> #define b */ #include <stdio.h> #define main() int main(void) #define printf printf( #define true ) #define function function main () { printf "Hola, mundo! \n " true /* 2> /dev/null | grep -v true*/ ; return 0 ; } #define c /* main #*/
Tenga en cuenta lo siguiente:
<?php
" y " ?>
" todavía tienen efecto.function main()
" es válida tanto en PHP como en bash; se utilizan #defines de C para convertirla en " int main(void)
" en tiempo de compilación.if (($x))
" es una declaración válida tanto en bash como en PHP.printf
es una función incorporada del shell bash que es idéntica a printf de C excepto por la omisión de corchetes (que el preprocesador de C agrega si se compila con un compilador de C ).main
función. En PHP, la main
función se define pero no se llama y en C no es necesario llamarla explícitamente main
.Lo siguiente está escrito simultáneamente en SNOBOL 4, Win32Forth , PureBasicv 4.x y REBOL :
Destacado para SNOBOL
* BUFFER : AA ; .( ¡Hola, mundo !) @ Para incluir? Macro SkipThis ; OUTPUT = Char ( 10 ) "¡Hola, mundo !" ; OneKeyInput Input ( 'Char' , 1 , '[-f2-q1]' ) ; Char End ; SNOBOL4 + PureBASIC + Win32Forth + REBOL = < 3 EndMacro : OpenConsole() : PrintN("¡Hola, mundo !") Repeat : Until Inkey() : Macro S omeDummyMacroHere REBOL [ Título : "'¡Hola, mundo !' en 4 idiomas" CopyLeft : "Desarrollado en 2010 por Society " ] Imprimir "¡Hola, mundo !" EndMacro : func [][] set-modes system / ports / input [ binary : true] Input set-modes system / ports / input [ binary : false] NOP:: EndMacro ; ¿ Desea refinarlo con un nuevo lenguaje ? ¡ Adelante !
Destacado para Forth
*BUFFER : AA ; . ( ¡Hola, mundo !) @ Para incluir? Macro SkipThis; OUTPUT = Char(10) "¡Hola, mundo !" ;OneKeyInput Input('Char', 1 , '[-f2-q1]') ; Char End; SNOBOL4 + PureBASIC + Win32Forth + REBOL = <3 EndMacro: OpenConsole() : PrintN("¡Hola, mundo !") Repeat : Until Inkey() : Macro SomeDummyMacroHere REBOL [ Título: "'¡Hola, mundo !' en 4 idiomas" CopyLeft: "Desarrollado en 2010 por Society" ] Print "¡Hola, mundo !" EndMacro: func [][] set-modes system/ports/input [binary: true] Input set-modes system/ports/input [binary: false] NOP:: EndMacro ; ¿ Desea refinarlo con un nuevo idioma ? Seguir !
Destacado para BASIC
* BUFFER : A . A ; . ( Hola , mundo ! ) @ Para Incluir ? Macro SkipThis ; OUTPUT = Char ( 10 ) "¡Hola, mundo !" ; OneKeyInput Input ( 'Char', 1, '[-f2-q1]') ; Char End ; SNOBOL4 + PureBASIC + Win32Forth + REBOL = < 3 EndMacro: OpenConsole () : PrintN ( "¡Hola, mundo !" ) Repeat : Until Inkey () : Macro SomeDummyMacroHere REBOL [ Título: "'¡Hola, mundo !' en 4 idiomas" CopyLeft: "Desarrollado en 2010 por Society" ] Print "¡Hola, mundo !" EndMacro: func [][] set - modos sistema / puertos / entrada [ binario: verdadero ] Input set - modos sistema / puertos / entrada [ binario: falso ] NOP: : EndMacro ; ¿ Quieres perfeccionarlo con un nuevo lenguaje ? ¡ Adelante !
Destacado para REBOL
*BUFFER : AA ; .( ¡Hola, mundo !) @ Para Incluir? Macro SkipThis; OUTPUT = Char ( 10 ) "¡Hola, mundo !" ;OneKeyInput Input('Char', 1, '[-f2-q1]') ; Char End; SNOBOL4 + PureBASIC + Win32Forth + REBOL = <3 EndMacro: OpenConsole () : PrintN ( "¡Hola, mundo !" ) Repeat : Until Inkey () : Macro SomeDummyMacroHere REBOL [ Título: "'¡Hola, mundo !' en 4 idiomas" CopyLeft: "Desarrollado en 2010 por Society" ] Print "¡Hola, mundo !" EndMacro: func [][] set-modes system /ports/input [ binary: true ] Input set-modes system /ports/input [ binary: false ] NOP:: EndMacro ; ¿Quieres perfeccionarlo con un nuevo lenguaje? ¡Adelante!
El siguiente archivo se ejecuta como un archivo por lotes de DOS y luego se vuelve a ejecutar en Perl :
Destacado para lotes DOS
@ rem = ' --PERL-- @ echo desactivado perl " %~dpnx0 " %* ir al final de perl @ rem '; #!perl imprimir "Hola, mundo!\n" ; __FIN__ : fin de perl
Destacado para Perl
@rem = ' --PERL-- @echo off perl "%~dpnx0" %* goto endofperl @rem ' ; #!perl print "Hola, mundo!\n" ; __END__ :endofperl
Esto permite crear scripts de Perl que se pueden ejecutar en sistemas DOS con un mínimo esfuerzo. Tenga en cuenta que no es necesario que un archivo realice exactamente la misma función en los distintos intérpretes.
Los tipos políglotas incluyen: [3]
Se ha propuesto el marcado políglota como una combinación útil de los beneficios de HTML5 y XHTML . [9] Dichos documentos se pueden analizar como HTML (que es compatible con SGML ) o XML , y producirán la misma estructura DOM de cualquier manera. Por ejemplo, para que un documento HTML5 cumpla con estos criterios, los dos requisitos son que debe tener un doctype HTML5 y estar escrito en XHTML bien formado. El mismo documento se puede servir como HTML o XHTML, según la compatibilidad del navegador y el tipo MIME.
Como se expresa en la recomendación html-polyglot [9] , para escribir un documento HTML5 políglota se deben tener en cuenta los siguientes puntos clave:
El documento de marcado políglota más básico posible se vería así: [9]
<!DOCTYPE html> < html xmlns = "http://www.w3.org/1999/xhtml" lang = "" xml:lang = "" > < head > < title > El elemento de título no debe estar vacío. </ title > </ head > < body > </ body > </ html >
En un documento de marcado políglota, los elementos no nulos (como script
, p
, div
) no pueden cerrarse automáticamente incluso si están vacíos, ya que esto no es HTML válido. [10] Por ejemplo, para agregar un área de texto vacía a una página, no se puede usar <textarea/>
, sino que se debe usar <textarea></textarea>
en su lugar.
El formato de imágenes médicas DICOM fue diseñado para permitir la poliglotización con archivos TIFF , lo que permite el almacenamiento eficiente de los mismos datos de imagen en un archivo que puede ser interpretado por visores DICOM o TIFF. [11]
Los lenguajes de programación Python 2 y Python 3 no fueron diseñados para ser compatibles entre sí, pero hay suficiente sintaxis en común para que se pueda escribir un programa políglota en Python que se ejecute en ambas versiones. [12]
Un políglota de dos formatos puede componer esteganográficamente una carga maliciosa dentro de un formato de envoltura aparentemente benigno y ampliamente aceptado, como un archivo JPEG que permite datos arbitrarios en su campo de comentarios. Un renderizador JPEG vulnerable podría entonces verse obligado a ejecutar la carga, cediendo el control al atacante. La falta de correspondencia entre lo que el programa de interpretación espera y lo que el archivo realmente contiene es la causa principal de la vulnerabilidad. [1]
La inyección SQL es una forma trivial de políglota, donde un servidor espera ingenuamente que la entrada controlada por el usuario se ajuste a una determinada restricción, pero el usuario proporciona una sintaxis que se interpreta como código SQL.
Tenga en cuenta que, en un contexto de seguridad, no existe ningún requisito de que un archivo políglota sea estrictamente válido en múltiples formatos; es suficiente con que el archivo desencadene un comportamiento no deseado al ser interpretado por su intérprete principal.
Los formatos de archivo altamente flexibles o extensibles tienen un mayor alcance para la poliglotización y, por lo tanto, una interpretación más restringida ofrece cierta mitigación contra los ataques que utilizan técnicas políglotas. Por ejemplo, el formato de archivo PDF requiere que el número mágico %PDF
aparezca en el byte de desplazamiento cero, pero muchos intérpretes PDF renuncian a esta restricción y aceptan el archivo como PDF válido siempre que la cadena aparezca dentro de los primeros 1024 bytes. Esto crea una ventana de oportunidad para que los archivos PDF políglotas introduzcan contenido que no sea PDF en el encabezado del archivo. [3] El formato PDF ha sido descrito como "diverso y vago", y debido a la variación significativa del comportamiento entre los diferentes motores de análisis de PDF, es posible crear un PDF-PDF políglota que se represente como dos documentos completamente diferentes en dos lectores PDF diferentes. [13]
La detección de malware oculto en archivos políglotas requiere un análisis más sofisticado que el que se basa en utilidades de identificación de tipo de archivo, como file . En 2019, una evaluación de software antimalware comercial determinó que varios de esos paquetes no pudieron detectar ninguno de los programas maliciosos políglotas que se estaban probando. [3] [2]
En 2019, se descubrió que el formato de archivo de imágenes médicas DICOM era vulnerable a la inyección de malware mediante una técnica políglota PE -DICOM. [14] La naturaleza políglota del ataque, combinada con consideraciones regulatorias, generó complicaciones de desinfección: debido a que "el malware está esencialmente fusionado con archivos de imágenes legítimos", "los equipos de respuesta a incidentes y el software A/V no pueden eliminar el archivo de malware ya que contiene información de salud protegida del paciente". [15]
Un archivo Java de formato de intercambio de gráficos ( GIFAR ) es un archivo políglota que está simultáneamente en formato de archivo GIF y JAR . [16] Esta técnica se puede utilizar para explotar vulnerabilidades de seguridad, por ejemplo, mediante la carga de un GIFAR a un sitio web que permite la carga de imágenes (ya que es un archivo GIF válido) y luego hacer que la parte Java del GIFAR se ejecute como si fuera parte del código previsto del sitio web, siendo entregado al navegador desde el mismo origen . [17] Java fue parcheado en JRE 6 Update 11, con un CVE publicado en diciembre de 2008. [18] [19]
Los GIFAR son posibles porque las imágenes GIF almacenan su encabezado al principio del archivo, y los archivos JAR (como cualquier formato basado en archivos ZIP) almacenan sus datos al final. [20]