Исполнение произвольного кода
— уязвимость в программной системе, когда злонамеренный пользователь (
хакер
) может заставить её исполнять любой
машинный код
, какой захочет. Если можно заставить машину исполнять произвольный код по сети, это иногда называется
удалённое исполнение кода
. Это самая опасная из программных уязвимостей — вредоносный код внедряется через внешне безобидные действия (например, загрузку файла данных), и может делать что угодно в пределах привилегий программы: извлекать информацию из памяти программы, пересылать её по сети, читать, писать и модифицировать файлы…
Аналогичная уязвимость для веба называется
межсайтовый скриптинг
— но поскольку
JavaScript
сам по себе ограничен в возможностях, то и урона от него обычно меньше, в основном утечки данных. Аналогичная уязвимость для SQL называется
внедрение SQL-кода
, и чревата она всем тем, что может SQL — утечками, подменами и потерями данных.
Причины
Основные причины исполнения произвольного машинного кода:
Порча памяти
Пример:
переполнением буфера
перезаписываем указатель возврата (в
x86
стек растёт вниз, и указатель после
стекового фрейма
). Как только программе потребуется закончить подпрограмму, процессор извлекает из стека этот адрес и переходит туда — на хакерскую подпрограмму.
Чтобы была больше вероятность перейти на вредоносную подпрограмму, используется техника
heap spraying
— в динамической памяти создаётся много небольших объектов, и каждый содержит подпрограмму
.
Подтип порчи памяти: функция ожидает, например,
строковый тип
, а ей дают
целочисленную
переменную, и она это никак не проверяет. Дав интерпретатору специальным образом подобранные данные, можно испортить память
.
Часто в составе программы или системных библиотеках встречаются уязвимые классы, исполняющие код по ошибке, или системные, действительно способные исполнить что угодно. В некоторых языках (
Java
) принято передавать сложные объектные структуры через стандартную сериализацию — и если взломщик передаст команду создать подобный объект, можно будет исполнить произвольный код. Подобную уязвимость имели
WebSphere
и
Jenkins
.
Случайное исполнение кода в операциях над EXE и DLL, которые этого исполнения не подразумевают
Два примера: 1. В
Windows
загрузка иконки из DLL происходит через функцию
LoadLibrary
, которая, в числе прочего, исполняет и код инициализации DLL — таким образом, достаточно просмотреть
Проводником
каталог с «отравленным» DLL, чтобы исполнить зловредный код. Решено через дополнительный флаг
LOAD_LIBRARY_AS_DATAFILE
, не исполняющий кода. 2. В Unix-подобных ОС программа
ldd
, проверяющая зависимости программы, является несложным скриптом, исполняющим ELF-файл с определёнными настройками системы
. Не решено — просто запрещается запускать ldd на непроверенных файлах.
В этом случае программа просто не сможет ничего записать в ту память, которую можно исполнять. Экстремальный вариант —
гарвардская архитектура
, распространённая в ограниченных машинах, в ней код и данные расположены в разных адресных пространствах. Недостаток: существуют
самомодифицирующийся код
, собственные загрузчики (сжатие исполняемых файлов, защита от копирования…),
JIT-компиляция
.
Работа программ с правами, которые не позволят нанести большой вред
Поскольку работа в ограниченном аккаунте довольно неудобна, Microsoft реализовал
контроль учётных записей пользователей
, не дающий программам работать с системными данными. В браузерах, как программах, принимающих на себя самые массовые хакерские атаки, есть работа вкладок в ограниченных процессах — впервые это реализовано в
Google Chrome
, а впоследствии — и в
Firefox
Quantum. Недостаток: сложность системы раздачи прав; в любом случае будут программы с широкими правами, и именно они станут основной мишенью хакеров.
Рандомизация адресного пространства программы (
ASLR
)
Из-за непостоянных адресов усложняется сборка действующего эксплойта. Недостаток: замедленная загрузка.
Расширенные самопроверки в библиотеках
Используются в критичном ПО, особо подверженном хакерским атакам (например, в сетевом). Например, в системе исполнения
Java
доступ к массиву или объекту всегда проверяется, из-за чего порча памяти затруднена. Недостаток: сниженная производительность.
Ограничения на стиль кода
Так, жёсткий стандарт кода
MISRA C
, принятый в автоиндустрии, призван снизить ошибкоопасность.
Использование ограниченных виртуальных машин и
скриптовых языков
, а не машинного кода
Если нужна программируемость, но недопустимы вредоносные программы, используют сильно ограниченный язык. Так работают
Java
,
JavaScript
, многие из смартфонных ОС, включая
Android
. Эта схема решает и другие вопросы — даёт независимость от архитектуры процессора, упрощает программирование, отказ программы не приводит к отказу всей системы. Недостаток: крайняя сложность системы и вытекающая из неё затруднённая проверка безопасности, низкая производительность.
Превращение сетевого ПО в многофункциональные «комбайны»
Как можно меньше сетевой работы отдаётся внешнему ПО: логично, что в браузере сильнее дисциплина программирования, чем в настольном просмотрщике PDF. К тому же браузер Chrome или Firefox исполнит код просмотра PDF в ограниченном процессе, а просмотрщик — в обычном.
Примечания
↑
(неопр.)
. Дата обращения: 18 июня 2023.
18 июня 2023 года.
(неопр.)
. Дата обращения: 31 августа 2022.
31 августа 2022 года.
(неопр.)
. Дата обращения: 31 августа 2022.
6 сентября 2022 года.