В информатике полиглот — это компьютерная программа или скрипт (или другой файл), написанный в допустимой форме нескольких языков программирования или форматов файлов . [1] Название было придумано по аналогии с многоязычием . Файл полиглота составляется путем объединения синтаксиса из двух или более различных форматов. [2]
Когда форматы файлов должны быть скомпилированы или интерпретированы как исходный код , можно сказать, что файл является программой-полиглотом , хотя форматы файлов и синтаксис исходного кода по сути являются потоками байтов, и использование этой общности является ключом к развитию полиглотов. [3] Файлы-полиглоты имеют практическое применение в обеспечении совместимости , [4] но также могут представлять угрозу безопасности , если используются для обхода проверки или эксплуатации уязвимости .
Полиглотные программы создавались как вызовы и диковинки в хакерской культуре по крайней мере с начала 1990-х годов. Известный ранний пример, названный просто, polyglot
был опубликован в группе Usenet rec.puzzles в 1991 году, поддерживая 8 языков, хотя это было вдохновлено еще более ранними программами. [5] В 2000 году полиглотная программа была названа победителем Международного конкурса запутанного кода на языке C. [ 6]
В 21 веке программы и файлы-полиглоты привлекли внимание как механизм скрытого канала для распространения вредоносных программ . [3] [7] Файлы-полиглоты имеют практическое применение в области совместимости , [8]
Полиглот состоит из объединения синтаксиса из двух или более различных форматов, используя различные синтаксические конструкции, которые являются общими для форматов или конструкции, специфичные для языка, но несущие разное значение в каждом языке. Файл является допустимым полиглотом, если он может быть успешно интерпретирован несколькими программами интерпретации. Например, полиглот PDF-Zip может быть открыт как допустимый документ PDF и распакован как допустимый архив zip . Чтобы поддерживать валидность в программах интерпретации, необходимо гарантировать, что конструкции, специфичные для одного интерпретатора, не будут интерпретироваться другим, и наоборот. Это часто достигается путем сокрытия языковых конструкций в сегментах, интерпретируемых как комментарии или простой текст другого формата. [1]
Два часто используемых метода построения полиглот-программы — это использование языков, которые используют разные символы для комментариев , и переопределение различных токенов как других в разных языках. Они продемонстрированы в этом общедоступном полиглоте, написанном на ANSI C , PHP и bash :
Выделено для Bash
#define a /* #<?php echo "\010Привет, мир!\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 "Привет, мир!\n" true/* 2 > /dev/null | grep -v true*/ ; return 0 ; } #define c /* main #*/
Выделено для PHP
#define a /* # <?php echo " \010 Привет, мир! \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 "Привет, мир! \n " true /* 2> /dev/null | grep -v true*/ ; return 0 ; } #define c /* main #*/
Выделено для C
#define a /* #<?php echo "\010Привет, мир!\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 "Привет, мир! \n " true /* 2> /dev/null | grep -v true*/ ; return 0 ; } #define c /* main #*/
Обратите внимание на следующее:
<?php
" и " ?>
" по-прежнему действуют.function main()
" действителен как в PHP, так и в bash; для преобразования его в " int main(void)
" во время компиляции используются определения C #.if (($x))
» является допустимым оператором как в bash, так и в PHP.printf
— встроенная функция оболочки bash , которая идентична функции printf языка C, за исключением отсутствия скобок (которые препроцессор C добавляет, если она скомпилирована с помощью компилятора C ).main
функции. В PHP main
функция определена, но не вызывается, а в C нет необходимости явно вызывать функцию main
.Следующий код написан одновременно на SNOBOL 4, Win32Forth , PureBasicv 4.x и REBOL :
Выделено для SNOBOL
* БУФЕР : AA ; .( Привет, мир !) @ Включить ? Макрос SkipThis ; ВЫХОД = Char ( 10 ) "Привет, мир !" ; OneKeyInput Input ( 'Char' , 1 , '[-f2-q1]' ) ; Char End ; SNOBOL4 + PureBASIC + Win32Forth + REBOL = < 3 EndMacro : OpenConsole() : PrintN("Привет, мир !") Повторить : Пока Inkey() : Макрос SomeDummyMacroHere REBOL [ Заголовок : "'Привет, мир !' на 4 языках " CopyLeft : "Разработано в 2010 году компанией S ociety" ] Печать "Привет, мир !" EndMacro : func [ ][] set-modes system / ports / input [ binary : true] Input set-modes system / ports / input [ binary : false ] NOP:: EndMacro ; Хотите усовершенствовать его с помощью нового языка ? Продолжайте !
Выделено для Forth
*БУФЕР : AA ; . ( Привет, мир !) @ Включить ? Макрос SkipThis; ВЫХОД = Char(10) "Привет, мир !" ;OneKeyInput Input('Char', 1 , '[-f2-q1]') ; Char End; SNOBOL4 + PureBASIC + Win32Forth + REBOL = <3 EndMacro: OpenConsole() : PrintN("Привет, мир !") Повторить : До Inkey() : Макрос SomeDummyMacroHere REBOL [ Заголовок: "'Привет, мир !' на 4 языках" CopyLeft: "Разработано в 2010 году компанией Society" ] Печать "Привет, мир !" EndMacro: func [][] set-modes system/ports/input [двоичный: true] Вход set-modes system/ports/input [двоичный: false] NOP:: EndMacro ; Хотите дополнить его новым языком ? Продолжайте !
Выделено для BASIC
* БУФЕР : A . A ; . ( Привет , мир ! ) @ Включая ? Макрос SkipThis ; ВЫХОД = Char ( 10 ) " Привет, мир !" ; OneKeyInput Input ( 'Char' , 1, '[-f2-q1]') ; Конец символа ; SNOBOL4 + PureBASIC + Win32Forth + REBOL = < 3 EndMacro: OpenConsole () : PrintN ( " Привет, мир !" ) Повторить : До Inkey () : Макрос SomeDummyMacroHere REBOL [ Заголовок: " ' Привет, мир !' на 4 языках" CopyLeft: " Разработано в 2010 году компанией Society" ] Печать " Привет, мир !" EndMacro: func [][] set - modes system / ports / input [ binary : true ] Input set - modes system / ports / input [ binary : false ] NOP: : EndMacro ; Хотите усовершенствовать его с помощью нового языка ? Продолжайте !
Выделено для REBOL
*БУФЕР : AA ; .(Привет, мир !) @ Включить? Макрос SkipThis; ВЫХОД = Char ( 10 ) "Привет, мир !" ;OneKeyInput Input('Char', 1, '[-f2-q1]') ; Конец символа; SNOBOL4 + PureBASIC + Win32Forth + REBOL = <3 EndMacro: OpenConsole () : PrintN ( "Привет, мир !" ) Повторить : До Inkey () : Макрос SomeDummyMacroHere REBOL [ Заголовок: "'Привет, мир !' на 4 языках" CopyLeft: "Разработано в 2010 году компанией Society" ] Печать "Привет, мир !" EndMacro: func [][] set-modes system /ports/input [ binary: true ] Input set-modes system /ports/input [ binary: false ] NOP:: EndMacro ; Хотите усовершенствовать его с помощью нового языка? Продолжайте!
Следующий файл запускается как пакетный файл DOS , а затем повторно запускается в Perl :
Выделено для пакета DOS
@ rem = ' --PERL-- @ echo off perl " %~dpnx0 " %* goto endofperl @ rem '; #!perl распечатать "Привет, мир!\n" ; __КОНЕЦ__ : endofperl
Выделено для Perl
@rem = ' --PERL-- @echo off perl "%~dpnx0" %* goto endofperl @rem ' ; #!perl print "Привет, мир!\n" ; __END__ :endofperl
Это позволяет создавать скрипты Perl, которые можно запускать в системах DOS с минимальными усилиями. Обратите внимание, что нет необходимости в том, чтобы файл выполнял одну и ту же функцию в разных интерпретаторах.
К полиглотическим типам относятся: [3]
Разметка полиглотов была предложена как полезное сочетание преимуществ HTML5 и XHTML . [9] Такие документы могут быть проанализированы как HTML (который совместим с SGML ) или XML , и в любом случае будет создана та же структура DOM . Например, для того, чтобы документ HTML5 соответствовал этим критериям, два требования заключаются в том, что он должен иметь тип документа HTML5 и быть написанным на правильно сформированном XHTML. Затем один и тот же документ может быть представлен как HTML или XHTML, в зависимости от поддержки браузера и типа MIME.
Как указано в рекомендации html-polyglot [9] , для написания полиглотного документа HTML5 необходимо соблюдать следующие ключевые моменты:
Таким образом, наиболее простой возможный документ полиглотной разметки будет выглядеть следующим образом: [9]
<!DOCTYPE html> < html xmlns = "http://www.w3.org/1999/xhtml" lang = "" xml:lang = "" > < head > < title > Элемент title не должен быть пустым. </ title > </ head > < body > </ body > </ html >
В документе полиглотной разметки непустые элементы (такие как script
, p
, div
) не могут быть самозакрывающимися, даже если они пустые, поскольку это недопустимый HTML. [10] Например, чтобы добавить пустую текстовую область на страницу, нельзя использовать <textarea/>
, вместо этого нужно использовать <textarea></textarea>
.
Формат медицинских изображений DICOM был разработан для обеспечения возможности многоязычного использования файлов TIFF , что позволяет эффективно хранить одни и те же данные изображения в файле, который может быть интерпретирован как средствами просмотра DICOM, так и средствами просмотра TIFF. [11]
Языки программирования Python 2 и Python 3 не были разработаны для обеспечения совместимости друг с другом, но у них достаточно общего синтаксиса, чтобы можно было написать многоязычную программу на Python, которая будет работать в обеих версиях. [12]
Полиглот двух форматов может стеганографически составить вредоносную полезную нагрузку внутри якобы безвредного и широко распространенного формата-оболочки, такого как файл JPEG, который допускает произвольные данные в своем поле комментариев. Уязвимый рендерер JPEG затем может быть принужден к выполнению полезной нагрузки, передавая управление злоумышленнику. Несоответствие между тем, что ожидает интерпретирующая программа, и тем, что на самом деле содержит файл, является основной причиной уязвимости. [1]
SQL-инъекция — это тривиальная форма полиглота, при которой сервер наивно ожидает, что вводимые пользователем данные будут соответствовать определенным ограничениям, но пользователь предоставляет синтаксис, который интерпретируется как код SQL.
Обратите внимание, что в контексте безопасности не существует требования, чтобы файл-полиглот был строго допустим в нескольких форматах; достаточно, чтобы файл вызывал непреднамеренное поведение при интерпретации его основным интерпретатором.
Очень гибкие или расширяемые форматы файлов имеют больше возможностей для полиглоттинга, и поэтому более жестко ограниченная интерпретация предлагает некоторое смягчение против атак с использованием полиглоттинговых методов. Например, формат файла PDF требует, чтобы магическое число %PDF
появлялось в байтовом смещении ноль, но многие интерпретаторы PDF отказываются от этого ограничения и принимают файл как действительный PDF, пока строка появляется в пределах первых 1024 байт. Это создает окно возможностей для полиглоттинговых файлов PDF для контрабанды не-PDF-контента в заголовке файла. [3] Формат PDF был описан как «разнообразный и неопределенный», и из-за значительно различающегося поведения между различными механизмами синтаксического анализа PDF можно создать полиглотт PDF-PDF, который отображается как два совершенно разных документа в двух разных программах для чтения PDF. [13]
Обнаружение вредоносного ПО, скрытого в файлах-полиглотах, требует более сложного анализа, чем использование утилит идентификации типа файла, таких как file . В 2019 году оценка коммерческого программного обеспечения для защиты от вредоносных программ показала, что несколько таких пакетов не смогли обнаружить ни одно из тестируемых вредоносных программ-полиглотов. [3] [2]
В 2019 году было обнаружено, что формат файла медицинской визуализации DICOM уязвим для внедрения вредоносного ПО с использованием полиглотной техники PE -DICOM. [14] Полиглотная природа атаки в сочетании с нормативными соображениями привела к осложнениям при дезинфекции: поскольку «вредоносное ПО по сути объединено с легитимными файлами изображений», «группы реагирования на инциденты и аудио- и видеопрограммы не могут удалить файл вредоносного ПО, поскольку он содержит защищенную информацию о состоянии здоровья пациента». [15]
Архивы формата обмена графикой Java ( GIFAR ) — это многоязычный файл, который одновременно находится в форматах GIF и JAR . [16] Этот метод может использоваться для эксплуатации уязвимостей безопасности, например, путем загрузки GIFAR на веб-сайт, который позволяет загружать изображения (поскольку это допустимый файл GIF), а затем путем выполнения части GIFAR Java, как если бы она была частью предполагаемого кода веб-сайта, доставляемого в браузер из того же источника . [17] Java была исправлена в JRE 6 Update 11, с CVE, опубликованным в декабре 2008 года. [18] [19]
GIFAR-файлы возможны, поскольку GIF-изображения хранят свои заголовки в начале файла, а файлы JAR (как и любой формат на основе ZIP-архива) хранят свои данные в конце. [20]