Исполнение произвольного кода
Исполнение произвольного кода — уязвимость в программной системе, когда злонамеренный пользователь (хакер), имеющий доступ к её простейшим функциям вроде ввода данных, может передать в этих данных машинный или интерпретируемый код, и заставить систему исполнить его[1]. Если можно заставить машину исполнять произвольный код по сети, это иногда называется удалённое исполнение кода. Это самая опасная из программных уязвимостей — вредоносный код внедряется через внешне безобидные действия (например, загрузку файла данных), и может делать что угодно в пределах привилегий программы: извлекать информацию из памяти программы, пересылать её по сети, читать, писать и модифицировать файлы…
Несмотря на то, что эта конкретная уязвимость может не представлять реальной угрозы, исследователи обсуждают, указывает ли она на естественную склонность компьютеров к наличию уязвимостей, допускающих несанкционированное выполнение кода[1]. Марвин Мински в 1967 году создал универсальную машину Тьюринга (эмулятор машины Тьюринга, написанный на машине Тьюринга), и в ней оказался эксплойт — когда хакер имеет доступ к данным, но не коду, он может специально подобранными данными заставить эту машину исполнить свой код[1].
Аналогичная уязвимость для веба называется межсайтовый скриптинг — но поскольку JavaScript сам по себе ограничен в возможностях, то и урона от него обычно меньше, в основном утечки данных. Аналогичная уязвимость для SQL называется внедрение SQL-кода, и чревата она всем тем, что может SQL — утечками, подменами и потерями данных.
Причины
Основные причины исполнения произвольного машинного кода:
- Порча памяти
- Пример: переполнением буфера перезаписываем указатель возврата (в x86 стек растёт вниз, и указатель после стекового фрейма). Как только программе потребуется закончить подпрограмму, процессор извлекает из стека этот адрес и переходит туда — на хакерскую подпрограмму.
- Чтобы была больше вероятность перейти на вредоносную подпрограмму, используется техника heap spraying — в динамической памяти создаётся много небольших объектов, и каждый содержит подпрограмму[2].
- Спутанные типы в интерпретаторах с динамической типизацией
- Подтип порчи памяти. Интерпретатор рано или поздно выполнит библиотечную функцию, написанную на машинном коде. Если функция ожидает, например, строковый тип, а ей дают целочисленную переменную, и она это никак не проверяет, можно испортить память[2][3].
- Автоматическая сериализация + излишнее доверие
- Часто в составе программы или системных библиотеках встречаются уязвимые классы, исполняющие код по ошибке, или системные, действительно способные исполнить что угодно. В некоторых языках (Java) принято передавать сложные объектные структуры через стандартную сериализацию — и если взломщик передаст команду создать подобный объект, можно будет исполнить произвольный код. Подобную уязвимость имели WebSphere и Jenkins[4][5].
- Случайное исполнение кода в операциях над EXE и DLL, которые этого исполнения не подразумевают
- Два примера: 1. В Windows загрузка иконки из DLL происходит через функцию
LoadLibrary, которая, в числе прочего, исполняет и код инициализации DLL — таким образом, достаточно просмотреть Проводником каталог с «отравленным» DLL, чтобы исполнить зловредный код. Решено ещё в 2000-е через дополнительный флагLOAD_LIBRARY_AS_DATAFILE, не исполняющий кода. 2. В Unix-подобных ОС программаldd, проверяющая зависимости программы, является несложным скриптом, исполняющим ELF-файл с определёнными настройками системы[6]. Не решено — просто запрещается запускать ldd на непроверенных файлах.
- Вайб-кодинг
- Не непосредственная причина, но набирающая важность. Разработчики, не способные сделать ревизию вывода ChatGPT, могут пропустить самые разные ошибки[7].
О причинах исполнения произвольного скриптового кода см. XSS, Внедрение SQL-кода.
Защита
Произвольное выполнение кода обычно достигается путем получения контроля над указателем инструкций (например, через команду перехода или ветвления) в работающем процессе. Указатель инструкций указывает на следующую команду в процессе, которая будет выполнена. Таким образом, контроль над значением указателя инструкций дает возможность управлять тем, какая команда будет выполнена следующей. Для выполнения произвольного кода многие эксплойты внедряют код в процесс (например, отправляя ему входные данные, которые сохраняются во входном буфере в оперативной памяти) и используют уязвимость для изменения указателя инструкций, чтобы он указывал на внедренный код. Внедренный код затем автоматически выполняется. Этот тип атаки использует тот факт, что большинство компьютеров (использующих архитектуру фон Неймана) не проводят четкого различия между кодом и данными[8][9], поэтому вредоносный код может маскироваться под безобидные входные данные. Многие современные процессоры имеют механизмы, затрудняющие это, например, бит "запрет выполнения"[10][11].
- Запрет на модификацию сегментов кода, и на исполнение сегментов данных
- В этом случае программа просто не сможет ничего записать в ту память, которую можно исполнять. Экстремальный вариант — гарвардская архитектура, распространённая в ограниченных машинах, в ней код и данные расположены в разных адресных пространствах. Недостаток: существуют самомодифицирующийся код, собственные загрузчики (сжатие исполняемых файлов, защита от копирования…), JIT-компиляция.
- Работа программ с правами, которые не позволят нанести большой вред
- Поскольку работа в ограниченном аккаунте довольно неудобна, Microsoft реализовал контроль учётных записей пользователей, не дающий программам работать с системными данными. Впоследствии Linux сделал аналогичное: большинство работы, даже в администраторских аккаунтах, идёт с пониженными правами, а команды, требующие полных прав, выполняются через sudo (сама программа существовала с 1980-х, но использовалась мало). В браузерах, как программах, принимающих на себя самые массовые хакерские атаки, есть работа вкладок в ограниченных процессах — впервые это реализовано в Google Chrome, а впоследствии — и в Firefox Quantum. Недостаток: сложность системы раздачи прав; в любом случае будут программы с широкими правами, и именно они станут основной мишенью хакеров.
- Рандомизация адресного пространства программы (ASLR)
- Из-за непостоянных адресов усложняется сборка действующего эксплойта. Недостаток: замедленная загрузка, принципиальные уязвимости.
Основной принцип данной технологии заключается в устранении заведомо известных атакующему адресов адресного пространства процесса. В частности, адресов, необходимых для того, чтобы:
- передать управление на исполняемый код;
- построить цепочку ROP-гаджетов (Возвратно-ориентированное программирование, англ. Return Oriented Programming);
- прочитать (перезаписать) важные значения в памяти.
Впервые технология была реализована для Linux в 2005 году. В Microsoft Windows и Mac OS реализация появилась в 2007 году[12].
Стоит отметить, что в разных ОС реализации ASLR очень сильно различаются и развиваются. Последние изменения связаны с работой Offset2lib, представленной в 2014 году. В ней были раскрыты слабости реализации, позволяющие обходить ASLR из-за близкого расположения всех библиотек к образу бинарного ELF-файла программы. В качестве решения было предложено выделить образ ELF-файла приложения в отдельный случайным образом выделенный регион[12].
- Расширенные самопроверки в библиотеках
- Используются в критичном ПО, особо подверженном хакерским атакам (например, в сетевом). Например, в системе исполнения Java доступ к массиву или объекту всегда проверяется, из-за чего порча памяти затруднена. Недостаток: сниженная производительность.
- Ограничения на стиль кода
- Так, жёсткий стандарт кода MISRA C, принятый в автоиндустрии, призван снизить ошибкоопасность[13].
В блоге компании PVS-Studio говорится[14]:
До 2018 мы позиционировали PVS-Studio как инструмент для выявления ошибок в коде. В 2018 мы поняли, что существенная часть ошибок, которые мы научились находить, одновременно является потенциальными уязвимостями[15]. Начиная с 2018 года, PVS-Studio является средством статического тестирования защищённости приложений (Static Application Security Testing, SAST). Тогда же мы начали классифицировать уже написанные и новые диагностики в соответствии с Common Weakness (CWE), SEI CERT Coding (CERT), MISRA C/C++. В 2021 году этот список пополнил AUTOSAR.
- Использование ограниченных виртуальных машин и скриптовых языков, а не машинного кода
- Если нужна программируемость, но недопустимы вредоносные программы, используют сильно ограниченный язык. Так работают Java, JavaScript, многие из смартфонных ОС, включая Android. Эта схема решает и другие вопросы — даёт независимость от архитектуры процессора, упрощает программирование, отказ программы не приводит к отказу всей системы. Недостаток: крайняя сложность системы и вытекающая из неё затруднённая проверка безопасности, низкая производительность.
- Превращение сетевого ПО в многофункциональные «комбайны»
- Как можно меньше сетевой работы отдаётся внешнему ПО: логично, что в браузере сильнее дисциплина программирования, чем в настольном просмотрщике PDF. К тому же браузер Chrome или Firefox исполнит код просмотра PDF в ограниченном процессе, а просмотрщик — в обычном.
Примеры
Любители ретроигр обнаружили уязвимости в классических видеоиграх, позволяющие им выполнять произвольный код. Обычно это достигается путем точной последовательности нажатий кнопок в "суперпрохождениях с помощью инструментов", что вызывает переполнение буфера и позволяет записывать данные в защищенную память. На фестивале Awesome Games Done Quick 2014 группа спидраннеров смогла написать и запустить версии игр Pong, Змейка и Super Mario Bros. на копии Super Mario World[16], используя чтение за пределами допустимых границ указателя функции, который ссылается на управляемый пользователем буфер, для выполнения произвольного кода.
12 июня 2018 года боснийский специалист по безопасности Жан-Ив Авенар из Mozilla обнаружил уязвимость ACE в Windows 10[17].
1 мая 2018 года специалист по безопасности обнаружил уязвимость ACE в архиваторе файлов 7-Zip[18].
PHP неоднократно становился объектом уязвимостей ACE[19][20][21].
9 декабря 2021 года в популярном фреймворке для логирования Log4j была обнаружена уязвимость удаленного выполнения кода (RCE), получившая название "Log4Shell". Она затронула множество сервисов, включая iCloud, Minecraft: Java Edition и Steam, и была охарактеризована как "самая значительная и критическая уязвимость последнего десятилетия"[22][23].
Примечания
- ↑ 1 2 3 Johnson, Pontus (2021). Intrinsic Propensity for Vulnerability in Computers? Arbitrary Code Execution in the Universal Turing Machine (Preprint). arXiv:2105.02124.
- ↑ 1 2 Understanding type confusion vulnerabilities: CVE-2015-0336 | Microsoft Security Blog. Дата обращения: 18 июня 2023. Архивировано 18 июня 2023 года.
- ↑ Deserialization of untrusted data. owasp.org.
- ↑ What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability. Дата обращения: 31 августа 2022. Архивировано 31 августа 2022 года.
- ↑ Ошибка в сносках?: Неверный тег
<ref>; для сносокDUDне указан текст - ↑ ldd arbitrary code execution. Дата обращения: 31 августа 2022. Архивировано 6 сентября 2022 года.
- ↑ Как vibe-кодинг ломает ваш проект, если вы не контролируете качество. SecurityLab.ru (28 июля 2025). Дата обращения: 21 ноября 2025.
- ↑ Gilreath, William F. Evolution of Instruction Sets // Computer Architecture: A Minimalist Perspective / William F. Gilreath, Phillip A. Laplante. — 2003. — P. 23–32. — ISBN 978-1-4613-4980-8. — doi:10.1007/978-1-4615-0237-1_4.
- ↑ Reilly, Edwin D. Milestones in Computer Science and Information Technology : [англ.]. — Greenwood Publishing Group, 2003. — P. 245. — ISBN 9781573565219.
- ↑ Tech Insight: Execute Disable Bit (XD-Bit). Toshiba Polska (2005). Дата обращения: 31 октября 2018. Архивировано из оригинала 31 октября 2018 года.
- ↑ AMD has you covered. AMD (2012). Архивировано из оригинала 5 марта 2019 года.
- ↑ 1 2 blackzert. Предсказание случайности. Изучаем ASLR в Linux и GNU libc, обходим защиту адресного пространства и stack canary (19 февраля 2018). Дата обращения: 21 ноября 2025.
- ↑ Будь строже к себе: как ограничения помогают сделать код лучше. Хабр. ZeBrains_team (26 сентября 2021). Дата обращения: 21 ноября 2125.
- ↑ {{cite web https://habr.com/ru/companies/pvs-studio/articles/579420/ |title=MISRA C: борьба за качество и безопасность кода |date=2021-09-22 |access-date=2025-11-21 |website=PVS-studio }}
- ↑ Потенциальная уязвимость. PVS-studio (27 мая 2024). Дата обращения: 21 ноября 2025.
- ↑ Orland, Kyle. How an emulator-fueled robot reprogrammed Super Mario World on the fly. Ars Technica (14 января 2014). Дата обращения: 27 июля 2016.
- ↑ Microsoft Windows CVE-2018-8213 Arbitrary Code Execution Vulnerability (англ.). Symantec. Дата обращения: 31 октября 2018. Архивировано 31 октября 2018 года.
- ↑ A Vulnerability in 7-Zip Could Allow for Arbitrary Code Execution (амер. англ.). New York State Office of Information Technology Services. Дата обращения: 31 октября 2018. Архивировано из оригинала 15 августа 2021 года.
- ↑ NVD - CVE-2017-12934. nvd.nist.gov. Дата обращения: 31 октября 2018.
- ↑ File Operation Induced Unserialization via the "phar://" Stream Wrapper. Secarma Labs (2018).
- ↑ NVD - CVE-2017-12933. nvd.nist.gov. Дата обращения: 31 октября 2018.
- ↑ Zeroday in ubiquitous Log4j tool poses a grave threat to the Internet. Ars Technica (9 декабря 2021). Дата обращения: 11 декабря 2021.
- ↑ Recently uncovered software flaw 'most critical vulnerability of the last decade'. The Guardian (11 декабря 2021). Дата обращения: 11 декабря 2021.