Кен Томпсон Хак (1984)
Кен Томпсон описал метод повреждения двоичного файла компилятора (и другого скомпилированного программного обеспечения, такого как сценарий входа в систему * nix) в 1984 году. Мне было любопытно узнать, устраняет ли современная компиляция этот недостаток безопасности или нет.
Краткое описание:
Переписать код компилятора, чтобы он содержал 2 ошибки:
- При компиляции своего двоичного файла компилятор должен компилировать эти недостатки
- При компиляции какого-либо другого предварительно выбранного кода (функция входа в систему) он должен скомпилировать какой-нибудь произвольный бэкдор
Таким образом, компилятор работает нормально - когда он компилирует скрипт входа в систему или аналогичный, он может создать бэкдор безопасности, и когда он компилирует более новые версии себя в будущем, он сохраняет предыдущие недостатки - и недостатки будут существовать только в компиляторе двоичный файл, поэтому его крайне сложно обнаружить.
Вопросов:
Я не смог найти ответы на эти вопросы в Интернете:
- Какое отношение это имеет к своевременной компиляции?
- Скомпилированы ли функции, подобные программе, обрабатывающей логины в системе * nix, при их запуске?
- Является ли это все еще действительной угрозой или с 1984 года произошли изменения в безопасности компиляции, которые мешают этому стать серьезной проблемой?
- Это влияет на все языки?
Почему я хочу знать?
Я сталкивался с этим, выполняя домашнюю работу, и это показалось мне интересным, но у меня недостаточно опыта, чтобы конкретным образом понять, является ли это текущей проблемой или решенной.
Ответы:
Этот взлом должен быть понят в контексте. Он был опубликован в то время и в той культуре, где Unix, работавший на различном оборудовании, был доминирующей системой.
Что сделало нападение так страшно было , что C компилятор центральной части программного обеспечения для этих систем. Почти все в системе прошло через компилятор, когда он был впервые установлен (двоичные дистрибутивы были редки из-за разнородного оборудования). Все собирали вещи все время. Люди регулярно проверяли исходный код (им часто приходилось вносить коррективы, чтобы заставить его компилироваться вообще), поэтому использование закулисного входа компилятором казалось своего рода «совершенным преступлением», когда вас не поймали.
В настоящее время аппаратное обеспечение гораздо более совместимо, и поэтому компиляторы играют гораздо меньшую роль в повседневной работе системы. Скомпрометированный компилятор больше не самый страшный сценарий - руткиты и скомпрометированный BIOS еще сложнее обнаружить и избавиться от них.
источник
Целью этого выступления не было подчеркнуть уязвимость, которую необходимо устранить, или даже предложить теоретическую уязвимость, о которой нам необходимо знать.
Цель состояла в том, чтобы, когда речь заходит о безопасности, нам не хотелось бы никому доверять, но, к сожалению, это невозможно. Вы всегда должны доверять кому-то (отсюда и название: «Размышления о доверии»)
Даже если вы параноик, который шифрует свой настольный жесткий диск и отказывается запускать любое программное обеспечение, которое вы сами не компилировали, вам все равно нужно доверять своей операционной системе. И даже если вы сами компилируете операционную систему, вам все равно нужно доверять используемому вами компилятору. И даже если вы компилируете свой собственный компилятор, вы все равно должны доверять этому компилятору! И это даже не говоря о производителях оборудования!
Вы просто не можете сойти с рук, не доверяя никому . Это точка, которую он пытался донести.
источник
нет
Атака, как первоначально описано, никогда не была угрозой. Хотя компилятор теоретически мог бы сделать это, для того, чтобы осуществить атаку, потребовалось бы запрограммировать компилятор на
Это влечет за собой выяснение того, как компилятор работает из своего исходного кода, чтобы он мог изменить его без поломок.
Например, представьте, что формат связывания хранит длины данных или смещение скомпилированного машинного кода где-то в исполняемом файле. Компилятор должен сам определить, какие из них необходимо обновить и где, при вставке полезной нагрузки эксплойта. Последующие версии компилятора (безобидная версия) могут произвольно изменять этот формат, поэтому код эксплойта должен эффективно понимать эти концепции.
Это высокоуровневое самонаправленное программирование, сложная проблема ИИ (в прошлом я проверял, что на современном уровне техники генерируется код, который практически определяется его типами). Посмотрите: немногие люди могут даже сделать это; Вы должны были бы изучить язык программирования и понять основы кода в первую очередь.
Даже если проблема ИИ будет решена, люди заметят, если компиляция их крошечного компилятора приведет к созданию двоичного файла с огромной связанной библиотекой ИИ.
Аналогичная атака: начальное доверие
Однако обобщение атаки актуально. Основная проблема заключается в том, что ваша цепочка доверия должна начинаться где-то, и во многих доменах ее происхождение может подорвать всю цепочку труднообнаружимым способом.
Пример, который можно легко осуществить в реальной жизни
Ваша операционная система, скажем Ubuntu Linux, обеспечивает безопасность (целостность) обновлений, сверяя загруженные пакеты обновлений с ключом подписи репозитория (используя криптографию с открытым ключом). Но это гарантирует подлинность обновлений только в том случае, если вы можете доказать, что ключ подписи принадлежит законному источнику.
Где вы взяли ключ подписи? Когда вы впервые загрузили дистрибутив операционной системы.
Вы должны верить, что источник вашей цепочки доверия, этот ключ подписи, не является злом.
Любой, кто может MiTM подключения к Интернету между вами и загрузкой Ubuntu сервером-это может быть ваш ISP, правительство , которое контролирует доступ в Интернете (например , Китай), или хостинг в Ubuntu провайдер может угнал этот процесс:
Отныне вы будете получать свои обновления надежно с сервера злоумышленника. Обновления запускаются с правами root, поэтому злоумышленник имеет полный контроль.
Вы можете предотвратить атаку, убедившись в подлинности оригинала. Но для этого необходимо проверить загруженный образ компакт-диска с помощью хэша (на самом деле это делают немногие ), а сам хеш должен быть загружен безопасно, например, по протоколу HTTPS. И если ваш злоумышленник может добавить сертификат на ваш компьютер (обычно в корпоративной среде) или контролирует центр сертификации (например, Китай), даже HTTPS не обеспечивает защиту.
источник
Во-первых, моя любимая статья об этом хаке называется Strange Loops .
Этот конкретный взлом может, безусловно, (*) быть осуществлен сегодня в любом из основных проектов ОС с открытым исходным кодом, в частности, в Linux, * BSD и т.п. Я ожидаю, что это будет работать почти одинаково. Например, вы загружаете копию FreeBSD с эксплуатируемым компилятором для изменения openssh. С тех пор каждый раз, когда вы обновляете openssh или компилятор по источнику, вы продолжаете проблему. Предполагая, что злоумышленник воспользовался системой, использовавшейся для упаковки FreeBSD, в первую очередь (вероятно, поскольку само изображение повреждено или злоумышленник фактически является упаковщиком), то каждый раз, когда система перестраивает двоичные файлы FreeBSD, он будет снова сталкиваться с проблемой. Есть много способов, чтобы эта атака провалилась, но они принципиально не отличаются от того, как атака Кена могла быть неудачной (**). Мир действительно не сильно изменился.
Конечно, аналогичные атаки могут быть столь же легко (или более легко) внедрены их владельцами в системы, такие как Java, iOS SDK, Windows или любая другая система. Определенные виды недостатков безопасности могут быть даже встроены в аппаратное обеспечение (особенно ослабление генерации случайных чисел).
(*) Но под «конечно» я подразумеваю «в принципе». Стоит ли ожидать, что такая дыра существует в какой-то конкретной системе? Нет. Я бы посчитал это маловероятным по разным практическим причинам. Со временем, по мере того, как код меняется и изменяется, вероятность того, что этот вид взлома вызовет странные ошибки, возрастает. И это повышает вероятность того, что это будет обнаружено. Менее изобретательные бэкдоры потребовали бы заговоров для поддержания. Конечно, мы точно знаем, что бэкдоры с «законным перехватом» были установлены в различных телекоммуникационных и сетевых системах, поэтому во многих случаях подобный сложный хак не нужен. Взлом установлен открыто.
Так что всегда глубоко в обороне.
(**) Предполагая, что атака Кена вообще когда-либо существовала. Он просто обсудил, как это можно сделать. Он не сказал, что на самом деле сделал это, насколько я знаю.
источник
Это влияет на все языки?
Эта атака в основном затрагивает языки, которые являются хостингом. Это языки, на которых компилятор написан на самом языке. C, Squeak Smalltalk и интерпретатор PyPy Python будут затронуты этим. Perl, JavaScript и интерпретатор CPython Python не будут.
Какое отношение это имеет к своевременной компиляции?
Не очень много. Это самодостаточный характер компилятора, который позволяет хаку быть скрытым. Я не знаю ни одного JIT-компилятора. (Может быть LLVM?)
Скомпилированы ли функции, подобные программе, обрабатывающей логины в системе * nix, при их запуске?
Как правило, не. Но вопрос не в том, когда он компилируется, а в том , каким компилятором . Если программа входа в систему скомпилирована испорченным компилятором, она будет испорчена. Если он скомпилирован чистым компилятором, он будет чистым.
Является ли это все еще действительной угрозой или с 1984 года произошли изменения в безопасности компиляции, которые мешают этому стать серьезной проблемой?
Это все еще теоретическая угроза, но не очень вероятно.
Одна вещь, которую вы могли бы сделать, чтобы смягчить это, это использовать несколько компиляторов. Например, компилятор LLVM, который сам скомпилирован GCC, не пройдет через черный ход. Точно так же GCC, скомпилированный LLVM, не пройдет через черный ход. Так что, если вы беспокоитесь о такого рода атаках, то вы можете скомпилировать свой компилятор с другим типом компилятора. Это означает, что злой хакер (у вашего поставщика ОС?) Должен будет испортить оба компилятора, чтобы узнать друг друга; Гораздо более сложная проблема.
источник
Для этого есть теоретический шанс. Однако существует способ проверить, не был ли скомпрометирован конкретный компилятор (с доступным исходным кодом), посредством двойной компиляции Дэвида А. Уилера .
По сути, используйте как предполагаемый компилятор, так и другой независимо разработанный компилятор для компиляции источника подозрительного компилятора. Это дает SC SC и SC T . Теперь скомпилируйте подозрительный источник, используя оба этих двоичных файла. Если получающиеся двоичные файлы идентичны (за исключением множества вещей, которые могут вполне законно меняться, например, разные метки времени), подозрительный компилятор фактически не злоупотребляет доверием.
источник
Как специфическая атака, это такая же угроза, какой она была когда-либо, и которая почти не представляет угрозы.
Не уверен, что вы подразумеваете под этим. Является ли JITter невосприимчивым к этому? Нет. Это более уязвимо? На самом деле, нет. Как разработчик, ВАШЕ приложение более уязвимо просто потому, что вы не можете подтвердить, что оно не было сделано. Обратите внимание, что ваше еще не разработанное приложение в основном защищено от этого и от всех практических вариантов, вам нужно беспокоиться только о компиляторе, который новее вашего кода.
Это не совсем актуально.
Там нет реальной безопасности компиляции, и не может быть. Это был действительно смысл его разговора, что в какой-то момент вам нужно кому-то доверять.
Да. По сути, в какой-то момент ваши инструкции должны быть превращены во что-то, что компьютер отменяет, и этот перевод может быть выполнен неправильно.
источник
У Дэвида Уилера есть хорошая статья: http://www.dwheeler.com/trusting-trust/
Меня больше волнуют аппаратные атаки. Я думаю, что нам нужен полностью инструментарий проектирования VLSI с исходным кодом FLOSS, который мы можем модифицировать и скомпилировать самостоятельно, который позволит нам создать микропроцессор, в который не будут вставлены бэкдоры. Инструменты должны также позволить нам понять назначение любого транзистора на чипе. Затем мы можем открыть образец готовых чипов и осмотреть их под микроскопом, убедившись, что они имеют ту же схему, что и инструменты, которые, как они сказали, должны были иметь.
источник
Системы, в которых конечные пользователи имеют доступ к исходному коду, являются теми, для которых вам придется скрывать этот тип атаки. Это были бы системы с открытым исходным кодом в современном мире. Проблема в том, что, хотя существует зависимость от одного компилятора для всех систем Linux, атака должна была попасть на серверы сборки для всех основных дистрибутивов Linux. Поскольку они не загружают двоичные файлы компилятора непосредственно для каждого выпуска компилятора, источник атаки должен был быть на их серверах сборки по крайней мере в одном предыдущем выпуске компилятора. Либо та, либо самая первая версия компилятора, которую они загрузили в виде двоичного файла, должны были быть скомпрометированы.
источник
Если у кого-то есть исходный код для системы компилятора / сборки, вывод которой не должен зависеть ни от чего, кроме содержимого предоставленных исходных файлов, и если у вас есть несколько других компиляторов, и он знает, что они не все содержат одинаковый хак компилятора, можно убедитесь, что вы получаете исполняемый файл, который не зависит ни от чего, кроме исходного кода.
Предположим, что у каждого есть исходный код для пакета компилятора / компоновщика (скажем, Groucho Suite), написанного таким образом, что его вывод не будет зависеть ни от каких-либо неопределенных поведений, ни от чего-либо, кроме содержимого входных исходных файлов, и один компилирует / связывает этот код с различными независимо создаваемыми пакетами компиляторов / компоновщиков (например, Harpo Suite, Chico Suite и Zeppo Suite), получая различный набор execctable для каждого (назовите их G-Harpo, G-Chico и G-Zeppo). Для этих исполняемых файлов не должно быть неожиданным, что они содержат разные последовательности инструкций, но они должны быть функционально идентичными. Однако доказать, что они функционально идентичны во всех случаях, было бы неразрешимой проблемой.
К счастью, в таком доказательстве нет необходимости, если использовать полученные исполняемые файлы только для одной цели: снова скомпилировать пакет Groucho. Если кто-то компилирует пакет Groucho, используя G-Harpo (получая GG-Harpo), G-Chico (GG-Chico) и G-Zeppo (GG-Zeppo), то все три результирующих файла, GG-Harpo, GG-Chico и GG-Zeppo, все байты должны быть идентичны. Если файлы совпадают, это будет означать, что любой «вирус компилятора», который существует в любом из них, должен существовать одинаково во всех из них (поскольку все три файла являются побайтовыми, они не могут отличаться в любом поведении. путь).
В зависимости от возраста и происхождения других компиляторов, возможно, будет возможно гарантировать, что такой вирус не может правдоподобно существовать в них. Например, если использовать старый Macintosh для загрузки компилятора, который был написан с нуля в 2007 году, через версию MPW, написанную в 1980-х годах, компиляторы 1980-х не знали бы, куда вставить вирус в компилятор 2007 года. Возможно, сегодня компилятор может выполнить достаточно сложный анализ кода, чтобы понять это, но уровень вычислений, требуемый для такого анализа, намного превысил бы уровень вычислений, необходимых для простой компиляции кода, и не мог бы остаться незамеченным на рынке, где скорость компиляции была основным пунктом продажи.
Я бы сказал, что если кто-то работает с инструментами компиляции, где байты в исполняемом файле, который должен быть создан, не должны зависеть ни от чего, кроме содержимого представленных исходных файлов, то можно добиться достаточно хорошего иммунитета от Томпсона. Вирус К сожалению, по какой-то причине недетерминизм в компиляции представляется нормальным в некоторых средах. Я признаю, что в многопроцессорной системе компилятор может работать быстрее, если ему разрешено варьировать определенные аспекты генерации кода в зависимости от того, какой из двух потоков завершает часть работы первым.
С другой стороны, я не уверен, что вижу причину, по которой компиляторы / компоновщики не должны предоставлять режим «канонического вывода», где вывод зависит только от исходных файлов и «даты компиляции», которая может быть переопределена пользователем , Даже если компиляция кода в таком режиме занимает вдвое больше времени, чем обычная компиляция, я бы предположил, что было бы весьма полезно иметь возможность воссоздать любую «релизную сборку», байт за байтом, полностью из исходных материалов, даже если это означало, что сборка релиза займет больше времени, чем «нормальная сборка».
источник