РЕЗЮМЕ
Сообщается, что уязвимость ядра DirtyPipe присутствует почти во всех версиях Linux, начиная с 5.8. Используя эту уязвимость, злоумышленник может выполнить эскалацию привилегий без срабатывания существующей защиты ядра и защиты от эксплойтов, что делает эту уязвимость особенно неприятной. Однако успех эксплуатации DirtyPipe во многом зависит от возможностей этой уязвимости (т. е. внедрения данных в произвольный файл через конвейеры Linux). Такая возможность редко используется для других уязвимостей ядра, что делает защиту относительно простой. Пока пользователи Linux устранят уязвимость, система может быть относительно безопасной.
В этой работе предлагается новый метод эксплуатации — DirtyCred — доведение других уязвимостей ядра Linux до уровня DirtyPipe. С технической точки зрения, учитывая уязвимость ядра Linux, наш метод эксплуатации меняет местами непривилегированные и привилегированные учетные данные ядра и, таким образом, обеспечивает возможность эксплуатации уязвимости, подобную DirtyPipe. Благодаря этой возможности злоумышленник может получить возможность повысить привилегии и даже сбежать из контейнера. Мы оценили этот подход к эксплуатации на 24 реальных уязвимостях ядра в полностью защищенной системе Linux. Мы обнаружили, что DirtyCred может продемонстрировать пригодность для эксплуатации на 16 уязвимостях, что указывает на серьезность безопасности DirtyCred. После оценки возможности использования в этой работе предлагается новый механизм защиты ядра. В отличие от существующих средств защиты ядра Linux, наша новая защита изолирует объекты учетных данных ядра в непересекающихся областях памяти на основе их собственных привилегий. Результат нашего эксперимента показывает, что новая защита в основном приводит к незначительным накладным расходам.
ВВЕДЕНИЕ
В настоящее время Linux стал популярной мишенью для киберпреступников из-за его популярности среди мобильных устройств, облачной инфраструктуры и веб-серверов. Чтобы обезопасить Linux, разработчики ядра и эксперты по безопасности вводят различные средства защиты ядра и используют методы защиты (например, KASLR [14] и CFI [19]), что делает эксплуатацию ядра беспрецедентно сложной. Чтобы успешно выполнить цель эксплуатации, современный злоумышленник должен идентифицировать эти мощные уязвимости ядра с возможностью отключения соответствующей защиты.
Тем не менее, недавняя уязвимость (обозначенная как CVE-2022-0847 [10]) и метод ее эксплуатации привлекают значительное внимание сообщества кибербезопасности. Из-за своей вредоносности и воздействия он даже получил прозвище — DirtyPipe [30]. В отличие от уязвимостей ядра без торговой марки, эксплуатация DirtyPipe обеспечивает повышение привилегий, не требуя отключения широко распространенной защиты ядра и устранения эксплойтов. Эта характеристика приводит к неэффективности существующих средств защиты Linux и, таким образом, ставит под угрозу многие системы, управляемые ядром Linux (например, устройства Android).
Несмотря на то, что DirtyPipe обладает мощными возможностями, возможности его использования тесно связаны с возможностями уязвимости (т. е. злоупотреблением механизмом канала ядра Linux для внедрения данных в произвольные файлы). Для других уязвимостей ядра Linux такая возможность злоупотребления каналом предоставляется редко. В результате действия, предпринятые сообществом Linux и производителями устройств (например, Google), заключаются в том, чтобы быстро выпустить исправление для исправления ошибки ядра и, таким образом, устранить поверхность атаки. Без этой поверхности для атаки эксплуатация полностью защищенного ядра Linux по-прежнему затруднительна. Что касается других уязвимостей ядра, по-прежнему сложно обеспечить такой же уровень воздействия на безопасность, как у DirtyPipe.
В этой работе мы представляем новый общий метод эксплуатации, с помощью которого даже обычные уязвимости ядра могут выполнять ту же цель эксплуатации, что и DirtyPipe. С технической точки зрения наш метод эксплуатации отличается от DirtyPipe. Он не зависит ни от конвейерного механизма Linux, ни от природы уязвимости CVE-2022-0847. Вместо этого он использует уязвимость, приводящую к повреждению памяти кучи, чтобы заменить объект учетных данных ядра с низким уровнем привилегий на объект с высоким уровнем привилегий. Эта практика сбивает с толку ядро Linux, заставляя его думать, что непривилегированный пользователь может получить разрешение на работу с файлами или процессами с высоким уровнем привилегий. Таким образом, мы назвали этот метод эксплуатации в честь DirtyCred.
При эксплуатации DirtyCred сталкивается с тремя критическими техническими проблемами. Во-первых, необходимо преобразовать возможность уязвимости в функцию, полезную для подкачки объектов учетных данных, поскольку уязвимости разных типов предоставляют разные возможности в повреждении памяти, что на первый взгляд может показаться недостаточным для подкачки объектов учетных данных. Во-вторых, DirtyCred необходимо строго контролировать временное окно для запуска обмена объектами. Как мы обсудим в разделе 3, ценное для DirtyCred временное окно короткое. Без практического механизма продления временного окна эксплуатация была бы нестабильной. В-третьих, DirtyCred необходимо найти эффективный механизм, который позволит непривилегированному пользователю выделять привилегированные учетные данные активным образом, потому что отсутствие этой возможности сделает обмен объектами учетных данных неэффективным.
Чтобы решить описанные выше технические проблемы, мы сначала представляем серию схем разворота уязвимостей, которые позволяют нам преобразовать любую уязвимость в куче в возможность освобождать объекты учетных данных недопустимым образом. Во-вторых, мы используем три различные функции ядра — userfaultfd [38], FUSE [37] и блокировку файловой системы — для увеличения временного окна, необходимого для подкачки объектов, и, таким образом, стабилизации эксплуатации. И последнее, но не менее важное: мы используем различные механизмы ядра для порождения потоков с высокими привилегиями как из пользовательского пространства, так и из пространства ядра и, таким образом, активно выделяем привилегированные объекты. В этой работе мы оцениваем возможности использования DirtyCred, используя 24 реальные уязвимости ядра. Мы неожиданно обнаружили, что DirtyCred может демонстрировать повышение привилегий на 16 уязвимостях и побег из контейнера. Мы поделились нашим недавно предложенным методом эксплуатации с программой вознаграждений за уязвимости Google (kCTF VRP [20]) и получили их признание и вознаграждение в размере 20 000 долларов США.
С убедительной демонстрацией возможности эксплуатации и отсутствием эффективной защиты мы считаем, что DirtyCred вскоре может стать серьезной угрозой для Linux, если сообщество не предпримет немедленных действий для изучения и развертывания нового механизма защиты. В результате, следуя нашему новому подходу к эксплуатации, мы также предложили новый механизм защиты ядра Linux. Основная идея этой защиты заключается в размещении объектов с высоким и низким уровнем привилегий в непересекающихся областях памяти. В этой работе мы делаем это, используя область vmalloc для хранения объектов с высокими привилегиями и обычную область для объектов с низкими привилегиями. Мы реализовали эту защиту в качестве прототипа ядра Linux и оценили ее производительность с помощью стандартного бенчмарка. Мы показываем, что наша защита в первую очередь вводит незначительные накладные расходы. Для некоторых операций, связанных с файловыми операциями, он демонстрирует лишь умеренные потери производительности.
По сравнению с существующими методами эксплуатации ядра Drity-Cred обладает многими уникальными характеристиками. Во-первых, это общий подход к эксплуатации, поскольку он позволяет повышать привилегии для произвольных уязвимостей в куче. Во-вторых, это могло бы значительно разгрузить бремя миграции эксплойтов, потому что, следуя DirtyCred, можно было бы создать эксплойт, который можно перенести с одной версии ядра или архитектуры на другую без каких-либо модификаций. В-третьих, он может обходить многие мощные средства защиты ядра и использовать механизмы защиты (например, CFI [15], KASLR [14], SMEP/SMAP [7, 29], KPTI [8] и т. д.). Наконец, это может выйти за рамки повышения привилегий, что приведет к более серьезным проблемам безопасности, таким какпоулчения рута на Android и выход из контейнера.
Подводя итог, в этой статье сделан следующий вклад.
- Мы предлагаем новый общий метод эксплуатации — DirtyCred — который может обойти широко распространенные средства защиты ядра и зашиты от эксплойтов и, таким образом, выполнить эскалацию привилегий в системе Linux.
- Мы демонстрируем, что DirtyCred может демонстрировать высокую эксплойтность на многих реальных уязвимостях ядра Linux. Мы также показываем, что эксплойтные объекты, полезные для DirtyCred, разнообразны и многочисленны.
- Мы анализируем существующие ограничения защиты ядра и предлагаем новый механизм защиты. Мы реализовали эту защиту в качестве прототипа в ядре Linux, показав, что она приводит к незначительным и умеренным потерям производительности.
Остальная часть этой статьи организована следующим образом. Раздел 2 знакомит с предпосылками, необходимыми для этого исследования, и обсуждает модель угроз. Раздел 3 представляет общую идею DirtyCred и обобщает технические проблемы, с которыми сталкивается DirtyCred. В разделах 4, 5 и 6 представлены различные методы решения технических проблем. В разделе 7 оценивается эффективность предлагаемого подхода к эксплуатации реальных уязвимостей ядра Linux. Раздел 8 представляется новый защитный механизм и оценивается его производительность на стандартных тестах. Раздел 9 содержит обсуждение соответствующей работы, за которой следует обсуждение некоторых связанных вопросов и будущей работы в Разделе 10. Наконец, мы завершаем работу в Разделе 11.
ПРЕДПОСЫЛКИ И МОДЕЛЬ УГРОЗ
В этом разделе представлены некоторые технические сведения, необходимые для понимания нашего недавно предложенного метода эксплуатации. Кроме того, мы обсуждаем нашу модель угроз и предположения.
2.1 Учетные данные в ядре Linux
Как определено в [26], учетные данные относятся к некоторым свойствам ядра, которые содержат информацию о привилегиях. Благодаря этим свойствам ядро Linux может проверять права доступа пользователей. В ядре Linux учетные данные реализованы как объекты ядра, несущие информацию о привилегиях. Насколько нам известно, эти объекты включают «cred», «file» и «inode». В этой статье мы разработали наши методы эксплуатации, используя только объекты «cred» и «file». Мы исключили объект «inode», поскольку он может быть выделен только при создании нового файла в файловой системе, что не обеспечивает достаточной гибкости для манипулирования памятью (критическая операция при успешной эксплуатации программы). Далее мы предоставляем некоторые необходимые сведения об объектах «cred», «file» и «inode».
Каждая задача Linux содержит указатель, ссылающийся на объект «cred». Объект «cred» содержит поле UID, указывающее привилегию задачи. Например, GLOBAL_ROOT_UID указывает, что у задачи есть привилегия root. Когда задача пытается получить доступ к ресурсу (например, к файлу), ядро проверяет UID в объекте «cred» задачи, определяя, можно ли предоставить доступ. В дополнение к UID объект «cred» также содержит возможности. Возможность указывает детальную привилегию задачи. Например, CAP_NET_BIND_SERVICE указывает, что задача может привязать сокет к привилегированному порту интернет-домена. Для каждой задачи их учетные данные настраиваются. При изменении учетных данных задачи ядро следует принципу копирования и замены. Сначала он копирует учетные данные. Во-вторых, он изменяет копию. Наконец, он изменяет этот указатель Cred в задаче на только что измененную копию. В Linux каждая задача может изменять только свои учетные данные.
В ядре Linux каждый файл имеет UID и GID своего владельца, права доступа и возможности других пользователей. Для исполняемых файлов у них также есть флаги SUID/SGID, указывающие на специальное разрешение, которое позволяет другим пользователям работать с привилегиями владельца. В реализации ядра Linux каждый файл привязан к объекту «inode», связанному с учетными данными. Когда задача пытается открыть файл, ядро вызывает функцию inode_permision, проверяя индекс и соответствующее разрешение перед предоставлением доступа к файлу. После открытия файла ядро удаляет учетные данные из объекта «inode» и прикрепляет их к объекту «файл». Помимо сохранения учетных данных, объект «файл» также содержит разрешение на чтение/запись файла. Через объект «файл» ядро может индексировать объект cred и, таким образом, проверять привилегию. Кроме того, он может проверять права на чтение/запись и тем самым гарантировать, что задача не записывает данные в файл, открытый в режиме только для чтения.
2.2 Управление памятью кучи ядра
Ядро Linux разрабатывает распределители памяти для управления выделением небольшой памяти для повышения производительности и предотвращения фрагментации. Хотя в ядре Linux есть три разных распределителя памяти, они следуют одному и тому же высокоуровневому дизайну. Чтобы быть точным, все они используют кеши для поддержания одинакового размера памяти. Для каждого кеша ядро выделяет страницы памяти и делит память на несколько частей одинакового размера, и каждая часть представляет собой слот памяти, используемый для размещения объекта. Когда страница памяти для кеша исчерпана, ядро выделяет новые страницы для кеша. Если кеш больше не использует страницу памяти, т. е. все объекты на странице памяти освобождены, ядро соответствующим образом перерабатывает страницу памяти. В ядре Linux есть два основных типа кешей, которые кратко описаны ниже.
Универсальные кэши. Ядро Linux имеет разные общие кеши для выделения памяти разного размера. При выделении памяти из общих кешей ядро сначала округляет запрошенный размер в большую сторону и находит кеш, соответствующий запросу размера. Затем он выделяет слот памяти из соответствующего кэша. В ядре Linux, если в запросе на выделение не указано, из каких типов кешей он выделяется, выделение по умолчанию происходит в универсальных кешах. Для выделений, которые попадают в один и тот же общий кэш, они могут совместно использовать один и тот же адрес памяти, поскольку они могут поддерживаться на одной и той же странице памяти.
Специальные кэши. Ядро Linux создает выделенные кэши для повышения производительности и безопасности. Поскольку некоторые объекты часто используются в ядре, выделение кэшей для этих объектов может сократить время, затрачиваемое на их выделение, и тем самым повысить производительность системы. Выделения, попадающие в выделенные кэши, не используют одну и ту же страницу памяти с общими выделениями. В результате объекты, размещенные в универсальном кэше, не соседствуют с объектами в выделенных кэшах. Это можно рассматривать как изоляцию на уровне кеша, которая снижает угрозу переполнения от объектов в обычных кешах.
В нашей модели угроз мы предполагаем, что непривилегированный пользователь имеет локальный доступ к системе Linux, стремясь использовать уязвимость в ядре, приводящую к повреждению динамической памяти, и, таким образом, повысить свои привилегии. Кроме того, мы предполагаем, что в Linux включены все механизмы предотвращения эксплойтов и защиты ядра, доступные в вышестоящем ядре (версия 5.15). К таким механизмам относятся KASLR, SMAP, SMEP, CFI [7, 14, 15, 29], KPTI [8] и т. д. Благодаря этим защитам и защите адрес ядра рандомизируется, ядро не может напрямую обращаться к памяти пользовательского пространства во время выполнения, и его целостность потока управления гарантируется. И последнее, но не менее важное: мы не предполагаем, что существует аппаратный побочный канал, который мог бы облегчить эксплуатацию ядра.
ТЕХНИЧЕСКИЙ ОБЗОР И ПРОБЛЕМЫ
В этом разделе мы впервые представим идею DirtyCred на примере из реальной жизни. Затем мы анализируем и обсуждаем технические проблемы, которые необходимо решить DirtyCred.
3.1 Обзор
Мы берем реальную уязвимость ядра Linux (CVE-2021-4154 [9]) в качестве примера, демонстрирующего, как DirtyCred работает на высоком уровне. CVE-2021-4154 возникает из-за ошибки смешения типов, когда на файловый объект неправильно ссылается исходное поле объекта fs_context. В ядре Linux время жизни файлового объекта поддерживается с помощью механизма подсчета ссылок. Файловый объект будет автоматически освобожден, когда счетчик ссылок станет равным нулю, что означает, что файловый объект больше не используется. Однако, активировав уязвимость, ядро недопустимо освободит файловый объект, даже если файл все еще используется.
Как показано на рис. 1, DirtyCred сначала открывает доступный для записи файл «/tmp/x», который выделяет доступный для записи файловый объект в ядре. Активировав уязвимость, указатель источника будет ссылаться на файловый объект в соответствующем кэше. Затем DirtyCred пытается записать содержимое в открытый файл «/tmp/x». Перед фактической записью содержимого ядро Linux проверяет, есть ли у текущего файла разрешение на запись, доступна ли позиция для записи и т. д. После прохождения проверки DirtyCred удерживает это фактическое действие записи файла и переходит ко второму шагу. На этом шаге DirtyCred запускает свободный участок объекта fs_context для освобождения файлового объекта, в результате чего файловый объект остается освобожденным местом в памяти.
Затем, на третьем этапе, DirtyCred открывает доступный только для чтения файл «/etc/-passwd», который запускает ядро для выделения файлового объекта для «/etc/passwd». Как показано на рис. 1, вновь выделенный файловый объект занимает освободившееся место. После этой настройки DirtyCred выполнит действие приостановки записи, и ядро выполнит фактическую запись содержимого. Поскольку файловый объект был заменен, содержимое на удержании будет перенаправлено в файл только для чтения «/etc/passwd». Предполагая, что содержимое, записанное в «/etc/password», является «hacker:x:0:0:root:/:/bin/sh», злоумышленник может использовать эту схему для внедрения привилегированной учетной записи и, таким образом, выполнить повышение привилегий.
Приведенный выше пример — просто демонстрация того, как Dirty-Cred использует файловые объекты для эксплуатации. Как упоминалось в разделе 2, в дополнение к объектам «файл», объекты «cred» также считаются объектами учетных данных. Подобно обмену файлами, показанному выше, злоумышленник также может использовать аналогичную идею для обмена объектами cred и, таким образом, выполнить эскалацию привилегий. В связи с ограничением места, мы не даем подробностей. Читатели, интересующиеся эксплуатацией объектов cred, могут обратиться к нашей демонстрации эксплуатации, опубликованной в [2].
Из реального примера, описанного выше, мы можем заметить, что DirtyCred не изменяет поток управления, а использует природу управления памятью ядра для манипулирования объектами в памяти. В результате многие существующие средства защиты, которые предотвращают подделку потока управления, не влияют на использование DirtyCred. В то время как некоторые недавние исследовательские работы обеспечивают защиту ядра путем перепроектирования управления памятью (например, AUTOSLAB [34]), они также неэффективны в блокировании DirtyCred. Как мы обсудим в разделе 8, недавно предложенные методы управления памятью все еще имеют грубую степень детализации, недостаточную для того, чтобы помешать нам манипулировать памятью.
3.2 Технические проблемы
Хотя приведенный выше пример иллюстрирует, как DirtyCred выполняет эксплуатацию и, таким образом, выполняет повышение привилегий, все еще есть много технических деталей, которые необходимо уточнить, и множество технических проблем, которые необходимо решить.
- Как упоминалось выше, DirtyCred нужна недействительная возможность для освобождения объекта с низкими привилегиями (например, файлового объекта с разрешением на запись), а затем перераспределения объекта с высокими привилегиями (например, файлового объекта с доступом только для чтения). На практике уязвимость ядра не всегда может предоставить нам такую возможность. Например, уязвимость может обеспечивать возможность перезаписи только за пределами сети, а не недействительную свободную запись непосредственно против объекта учетных данных. Таким образом, DirtyCred нужны соответствующие подходы для переноса возможностей уязвимости на уязвимости с разными возможностями. Поэтому в разделе 4 мы описываем, как менять возможности для различных типов уязвимостей ядра.
- Как описано в приведенном выше примере, DirtyCred необходимо удерживать фактическую запись файла после завершения проверки разрешений и до замены файловых объектов. Тем не менее, держаться за фактическое письмо сложно. В ядре Linux проверка разрешений и фактическая запись контента происходят быстро друг за другом. Без практической схемы точного контроля за подкачкой файловых объектов эксплуатация неизбежно будет нестабильной. В разделе 5 мы представляем ряд эффективных механизмов, гарантирующих, что обмен файловыми объектами может произойти в желаемое временное окно.
- Как обсуждалось выше, одним из наиболее важных шагов в DirtyCred является использование учетных данных с высокими привилегиями вместо учетных данных с низкими привилегиями. Для этого DirtyCred выделяет объекты с высокими привилегиями, занимая освободившееся место в памяти. Однако пользователю с низким уровнем привилегий сложно выделить учетные данные с высоким уровнем привилегий. Хотя простое ожидание действий от привилегированных пользователей потенциально может решить проблему, такая пассивная стратегия сильно влияет на стабильность эксплуатации. Во-первых, DirtyCred понятия не имеет, когда нужное место памяти может быть освобождено, и поэтому продолжает свою последовательную эксплуатацию. Во-вторых, DirtyCred не имеет контроля над вновь выделенными объектами. Поэтому возможно, что объект, занимающий желаемый слот памяти, не имеет ожидаемого уровня привилегий. В разделе 6 мы вводим механизм пользовательского пространства и схему пространства ядра для решения этой проблемы.
ВОЗМОЖНОСТЬ РАЗВОРОТА УЯЗВИМОСТИ
Как показано в примере, изображенном на рис. 1, уязвимость ядра, занесенная в каталог как CVE-2021-4154, дает DirtyCred возможность освободить файловый объект недопустимым образом. Однако на практике уязвимость может не демонстрировать такую возможность. Например, возможность двойного освобождения (DF) или использования после освобождения (UAF) может не быть напрямую связана с объектом учетных данных. Некоторые уязвимости, такие как внешний доступ (OOB), не имеют недопустимой возможности бесплатного доступа. Для этого DirtyCred необходимо изменить возможности уязвимости. Далее мы опишем, как мы разрабатываем DirtyCred для разворота.
4.1 Разворот OOB и UAF запись
Учитывая уязвимость OOB или уязвимость UAF с возможностью перезаписи данных в кэше, DirtyCred сначала идентифицирует объект (т. е. объект-жертву), который использует тот же кэш, и заключает указатель, ссылающийся на объект учетных данных. Затем он использует методы манипулирования кучей [6, 49] для размещения объекта в области памяти, где происходит перезапись. Как показано на рис. 2 (а), для разворота уязвимости OOB объект-жертва находится сразу после уязвимого объекта. Используя возможность перезаписи, DirtyCred дополнительно модифицирует указатель, заключенный в объект. В частности, DirtyCred использует возможность перезаписи для записи нуля в последние два байта указателя, ссылающегося на объект учетных данных (см. рис. 2(b)).
Напомним, что кэш организован на смежных страницах. В ядре Linux адрес страницы памяти всегда имеет формат, в котором последний байт равен нулю. При размещении объектов в новом кэше объект начинается с начала страницы памяти. В результате описанная выше перезапись нулевого байта заставит указатель ссылаться на начало страницы памяти. Например, как показано на рисунке 2(b), после обнуления двух последних байтов указателя, ссылающегося на объект учетных данных, указатель ссылается на начало страницы памяти, в которой находится другой объект учетных данных.
Как показано на рис. 2(б), после манипуляции с указателем Dirty-Cred получает дополнительную ссылку на первый объект страницы памяти. Мы утверждаем, что эта дополнительная ссылка на объект означает успех в повороте. Причина в том, что ядро могло нормально освободить объект, оставив указатель в объекте-жертве в виде висящего указателя. Затем, следуя аналогичной процедуре, описанной в разделе 3, DirtyCred может выполнить heap spray, занять освободившееся место объектом учетных данных с высокими привилегиями и, таким образом, выполнить повышение привилегий.
4.2 Разворот DF
В ядре Linux общие кеши (например, kmalloc-96) и выделенные кеши (например, cred_jar) изолированы. Объекты, заключенные в эти кэши, не имеют перекрытия. Однако в ядре Linux есть механизм рециркуляции. При уничтожении кеша памяти он повторно использует соответствующие неиспользуемые страницы памяти, а затем назначает повторно используемые страницы кешам, которым требуется больше места. Эта характеристика позволяет манипулировать памятью между кэшами, предоставляя DirtyCred возможность поворота для устранения уязвимостей с двойным освобождением.
На рис. 3 показана процедура преобразования DirtyCred возможности двойного освобождения в возможность, необходимую для обмена привилегированными объектами. Во-первых, DirtyCred выделяет множество объектов в кеше, где возникает уязвимость. Среди этих вновь выделенных объектов есть уязвимый объект. Используя два разных указателя, DirtyCred может дважды освободить уязвимый объект недопустимым образом. Поскольку количество выделений велико, DirtyCred может гарантировать, что кэш будет заполнен новыми выделенными объектами после массивного выделения объектов (см. рис. 3 (a)).
После массового выделения DirtyCred использует первый указатель для освобождения уязвимого объекта недопустимым образом, оставляя второй указатель позади (см. рис. 3(b)). Затем он перераспределяет уязвимый объект, занимая освободившееся место в памяти. Как показано на рисунке 3(c), после перераспределения остаются три указателя, ссылающиеся на уязвимый объект. Один из них — это указатель, оставленный первым уязвимым объектом. Два других связаны с возможностью двойного освобождения вновь выделенного уязвимого объекта.
Используя один из трех указателей, ссылающихся на уязвимый объект, DirtyCred дополнительно освобождает только что выделенный уязвимый объект, оставляя освобожденную область памяти, на которую ссылаются два оборванных указателя (см. рис. 3 (d)). Как упоминалось выше, ядро Linux перезапускает страницу памяти и назначает ее другому кешу, если в кеше нет выделенных объектов. Таким образом, после освобождения уязвимых
объект, DirtyCred дополнительно освобождает другие объекты в кэше и, таким образом, соответственно освобождает кэш (см. рисунок 3 (e)).
На странице переработанной памяти ядро создает новый кэш, в котором хранятся объекты учетных данных. Новый кеш делит память страниц на слоты. Как показано на рис. 3(f), если размер уязвимого объекта отличается от размера объекта учетных данных, адрес объекта учетных данных не будет совпадать с адресом уязвимого объекта, в результате чего два оставшихся указателя ссылаются середина объекта учетных данных. В этом состоянии памяти DirtyCred не может следовать процедуре эксплуатации, описанной в разделе 3, поскольку для успешной эксплуатации требуется возможность освободить объект учетных данных.
Чтобы решить эту проблему, DirtyCred сначала использует один из оставшихся указателей для освобождения объекта учетных данных в середине. Как показано на рис. 3(g), после освобождения памяти ядро создает свободное место в памяти. Это свободное место имеет размер как объект учетных данных. Поэтому, когда DirtyCred выделяет новый объект учетных данных, ядро заполняет освободившееся место новым объектом учетных данных. Как видно на рис. 3(h), после того, как освобожденное место занято, последний оставшийся указатель ссылается на вновь выделенный объект учетных данных. Это подразумевает успех разворота возможностей. Причина в том, что DirtyCred может использовать оставшийся указатель для освобождения объекта учетных данных недопустимым образом, а затем выполнить замену объекта для повышения привилегий.
5 ПРОДЛЕНИЕ ВРЕМЕННОГО ОКНА
Напомним, что ядру Linux необходимо проверять права доступа к файлу перед выполнением операции записи в файл. DirtyCred необходимо выполнить обмен файловыми объектами между проверкой разрешений и фактической записью файла. Однако это окно слишком короткое для успешной эксплуатации, поскольку подкачка должна активировать уязвимость и выполнить манипуляцию с расположением кучи, что может занять несколько секунд. Чтобы решить эту проблему, DirtyCred использует несколько методов для увеличения этого временного окна, чтобы гарантировать, что оно больше, чем время, затрачиваемое на процесс обмена. Здесь мы описываем эти методы и обсуждаем, как они могут облегчить эксплуатацию.
5.1 Использование Userfaultfd и FUSE
Userfaultfd [38] и FUSE [37] — две важные функции ядра Linux. Функция userfaultfd позволяет пользовательскому пространству обрабатывать ошибки страниц. Когда ошибка страницы инициируется в памяти, зарегистрированной в userfaultfd, зарегистрированный пользователем обработчик ошибки страницы получает уведомление для обработки ошибки страницы. В отличие от userfaultfd, FUSE представляет собой структуру файловой системы пользовательского пространства, позволяющую пользователям реализовать файловую систему пользовательского пространства. Пользователи могли зарегистрировать свой обработчик для реализованной файловой системы пользовательского пространства, чтобы указать, как отвечать на запросы операций с файлами. И userfaultfd, и FUSE могут быть использованы для приостановки выполнения ядра Linux на любое время, необходимое пользователю. Для userfaultfd злоумышленник может зарегистрировать обработчик ошибок страниц для страницы памяти. Когда ядро попытается получить доступ к этой памяти и вызовет отказ страницы, будет вызван зарегистрированный обработчик, позволяющий противнику приостановить выполнение ядра. Для FUSE злоумышленник может выделить память из файловой системы пользовательского пространства. Когда ядро обращается к этой памяти, оно вызывает предопределенный обработчик доступа к файлу и, таким образом, приостанавливает выполнение ядра.
В этой работе DirtyCred использует эти функции для приостановки выполнения ядра после завершения проверки прав доступа к файлу. Далее мы возьмем userfaultfd в качестве примера, чтобы описать, как DirtyCred выполняет паузу ядра и расширяет окно времени эксплуатации. Для FUSE процедура паузы ядра аналогична. Читатели могут обратиться к разработанному нами образцу эксплойта [2].
При записи файла DirtyCred вызывает syscallwritev, реализацию векторного ввода-вывода. В отличие от записи системного вызова, этот системный вызов использует структуру iovec для передачи данных из пространства пользователя в пространство ядра. Список 1 в строке 1~5 определяет структуру iovec. Как мы видим, он содержит адрес пользовательского пространства и поле размера, указывающее объем данных, которые будут переданы. В пространстве ядра Linux для копирования данных, заключенных в iovec, ядру необходимо сначала импортировать iovec в пространство ядра. Поэтому до версии ядра Linux версии 4.13, как показано в списке 1, реализация writev сначала проверяет файловый объект, гарантируя, что текущий файл находится в открытом состоянии и имеет разрешение на запись. После прохождения проверки он импортирует iovec из пользовательского пространства и записывает пользовательские данные в соответствующий файл. В этой реализации импорт ofiovec находится между проверкой разрешений и записью данных. DirtyCred может просто использовать вышеупомянутую функцию userfaultfd, чтобы приостановить выполнение ядра сразу после завершения проверки разрешений и, таким образом, выиграть достаточно времени для замены файлового объекта. Насколько нам известно, этот метод был впервые использован Янном Хорном в эксплойте для CVE-2016-4557 [25], но он больше не доступен после ядра версии 4.13.
5.2 Альтернативное использование Userfaultfd и FUSE
После версии ядра Linux версии 4.13 реализация ядра изменилась. Импорт iovec был перенесен перед проверкой разрешений (см. список 2). В этой новой реализации DirtyCred по-прежнему может использовать функцию userfaultfd для приостановки выполнения ядра на месте импорта iovec. Однако это больше не дает DirtyCred возможности увеличивать временной интервал между проверкой разрешений и фактической записью файла. Чтобы решить эту проблему, DirtyCred использует структуру файловой системы Linux.
В Linux структура файловой системы следует строгой иерархии, в которой высокоуровневый интерфейс является общим для операций записи файлов, тогда как низкоуровневый интерфейс различается в зависимости от файловой системы. При записи файла ядро сначала вызывает высокоуровневый интерфейс. Как показано в списке 3, generic_perform_write — это высокоуровневый интерфейс для операции записи в файл. Как мы видим, в строках 15-17 generic_perform_write вызывает операцию записи файловой системы и записывает данные в файл. Чтобы гарантировать производительность и совместимость, непосредственно перед операцией записи ядро вызывает отказ страницы для данных пользовательского пространства, заключенных в iovec. В результате, используя функцию userfaultfd в строке 10, DirtyCred может приостановить выполнение ядра до фактической записи файла и, таким образом, получить достаточное временное окно для замены привилегированных файловых объектов.
По сравнению с приостановкой выполнения ядра на месте импорта iovec, мы утверждаем, что использование структуры файловой системы является более сложной задачей для смягчения последствий. Во-первых, как описано в комментарии к коду Linux, удаление ошибки страницы в iovec потенциально может привести к взаимоблокировке (см. список 3). Некоторые файловые системы неизбежно столкнутся с проблемами, если страница не будет предварительно повреждена. Во-вторых, хотя перемещение ошибки страницы перед проверкой разрешений может потенциально решить проблему, эта прямая защитная реакция снижает производительность ядра и, что более важно, страдает от потенциального обхода. Например, DirtyCred может удалить страницу сразу после срабатывания ошибки первой страницы. Таким образом, ядро неизбежно снова вызывает отказ страницы и, таким образом, приостанавливает выполнение ядра сразу после проверки разрешений.
5.3 Использование блокировки в файловой системе
Чтобы не испортить содержимое файла, файловая система не позволяет двум процессам записывать файл одновременно. В Linux файловая система применяет эту практику с помощью механизма блокировки. Чтобы проиллюстрировать это, в списке 4 показан упрощенный фрагмент кода, выполняющий операцию записи в файловой системе ext4. Как мы видим, файловая система сначала пытается получить блокировку индекса в строке 6. Если индекс находится под управлением другого файла (т. е. другие удерживают блокировку), файловая система будет ждать, пока блокировка не будет снята. После получения блокировки файловая система вызывает generic_perform_write для записи данных в файл. Когда запись завершится, файловая система снимет блокировку и вернется из функции.
Приведенный выше механизм блокировки может гарантировать, что операция записи не пойдет не так, как надо. К сожалению, это оставляет DirtyCred возможность продлить временное окно и, таким образом, выполнить обмен объектами. Если быть точным, DirtyCred может порождать два процесса — процесс A и процесс B — для одновременной записи данных в один и тот же файл. Предположим, что процесс A удерживает блокировку, записывая огромное количество данных. Когда процесс A записывает файл, процесс B должен будет ждать в течение длительного периода, пока блокировка не будет снята в строке 10. Поскольку до вызова generic_perform_write процесс B уже завершил проверку прав доступа к файлу, время ожидания блокировки предоставляет DirtyCred достаточно большое временное окно для завершения замены файловых объектов, не беспокоясь о блоке проверки разрешений. По нашим наблюдениям, время удержания может достигать десятков секунд при записи файла размером 4 ГБ на жесткий диск. В течение этого временного окна активация уязвимости и выполнение манипуляций с памятью могут быть завершены без каких-либо проблем с нестабильностью при эксплуатации.
ВЫДЕЛЕНИЕ ПРИВИЛЕГИРОВАННОГО ОБЪЕКТА
Как упоминалось в разделе 3.2, DirtyCred не может пассивно ждать действий привилегированных пользователей и ожидать, что эти действия могут привести к тому, что привилегированный объект займет желаемое свободное место, и, таким образом, выполнить эскалацию привилегий. Следовательно, DirtyCred должен предпринять активные действия, чтобы инициировать выделение привилегированных объектов в пространстве ядра. В этом разделе обсуждается, как DirtyCred, работающий от имени пользователя с низким уровнем привилегий, выполняет выделение привилегированных объектов.
6.1 Выделение из пользовательского пространства
В ядре Linux объекты «cred» представляют уровень привилегий соответствующих задач ядра. Пользователь root имеет привилегированный объект cred, представляющий наивысшую привилегию. Следовательно, если DirtyCred может активно инициировать действия пользователя root, ядро может соответствующим образом выделить привилегированные объекты cred. В Linux, когда двоичный файл имеет разрешение SUID, он может выполняться так, как если бы он выполнялся владельцем, независимо от того, кто выполняет двоичный файл. Используя эту характеристику, пользователь с низким уровнем привилегий может создать процесс root, когда он/она выполняет двоичный файл, принадлежащий пользователю root, с набором разрешений SUID.
В прошлом злоумышленники сосредотачивались на использовании уязвимости в привилегированном двоичном файле и, таким образом, выполняли эскалацию привилегий. В этой работе DirtyCred не полагается на уязвимости, находящиеся в привилегированных двоичных файлах. Вместо этого он злоупотребляет вышеупомянутой функцией для порождения бинарных файлов с набором SUID, принадлежащих пользователям root, выделяя привилегированный объект Cred, чтобы занять свободное место в памяти. В Linux существует множество двоичных файлов, соответствующих этой функции, включая исполняемые файлы, такие как su, ping, sudo, mount, pkexec и т. д.
Как обсуждалось ранее, в дополнение к объектам cred, DirtyCred также может обмениваться файловыми объектами для повышения привилегий. В отличие от объектов cred, размещение файловых объектов относительно просто. Напомним, что DirtyCred заменяет объект файла, разрешенный для записи, объектом файла, доступным только для чтения, при замене файловых объектов. Чтобы выделить файловые объекты с разрешением только на чтение, DirtyCred может открывать несколько целевых файлов только с разрешением на чтение. Таким образом, ядро будет размещать множество соответствующих файловых объектов в соответствующей памяти ядра.
6.2 Выделение из пространства ядра
Описанный выше метод указывает способ выделения привилегированных объектов из пользовательского пространства. На самом деле, DirtyCred также может выполнять выделение привилегированных объектов из пространства ядра. Когда ядро Linux запускает новый поток ядра, оно дублирует свой текущий запущенный процесс. Вместе с дублированием процесса ядро соответствующим образом размещает скопированный объект cred в куче ядра. В ядре Linux большинство потоков ядра имеют привилегированный объект cred. В результате скопированный объект Cred также имеет высокие привилегии. Используя возможность порождать привилегированные потоки ядра, DirtyCred может активно выделять привилегированные объекты cred.
Насколько нам известно, существует два основных подхода к выделению объектов учетных данных с высоким уровнем привилегий. Во-первых, это взаимодействие с фрагментами кода ядра, заставляющее ядро создавать привилегированный поток внутри себя. Например, создание рабочих процессов для рабочей очереди ядра также может быть использовано для порождения потоков ядра. В ядре Linux рабочая очередь предназначена для обработки отложенных функций. Рабочая очередь поставляется с несколькими рабочими пулами. Каждый рабочий пул содержит рабочих. Рабочий процесс — это основная исполнительная единица, которая выполняет работу, зафиксированную в рабочей очереди. Количество рабочих процессов в каждом рабочем пуле не превышает количество ЦП. Изначально ядро создает только одного рабочего для каждого рабочего пула. Когда возникает потребность в большем количестве рабочих процессов или, другими словами, в очереди работ фиксируется больше работ, ядро динамически создает рабочих процессов. Каждый рабочий поток — это поток ядра. В результате, регулируя работы, зафиксированные в рабочей очереди ядра, можно было соответствующим образом управлять действиями порождения потоков ядра.
В дополнение к описанному выше методу, второй подход к созданию потоков ядра заключается в вызове помощника пользовательского режима. Помощник пользовательского режима — это механизм, который позволяет ядру создавать процесс пользовательского режима. Одним из самых простых применений помощника пользовательского режима является загрузка модулей ядра в пространство ядра. При загрузке модуля ядра ядро вызывает API пользовательского режима-помощника, который далее выполняет программу пользовательского пространства — modprobe в режиме с высоким уровнем привилегий и, таким образом, создает объекты учетных данных с высоким уровнем привилегий в ядре. Частью функциональности modprobe является поиск необходимых драйверов в каталогах стандартных установленных модулей. Во время поиска ядру необходимо продолжить выполнение. В результате, чтобы modprobe не блокировал выполнение ядра, при вызове API usermode-helper ядро также порождает новый поток ядра.
7 ОЦЕНКА
В этом разделе мы разрабатали два эксперимента для оценки возможности эксплуатации DirtyCred на реальных уязвимостях ядра.
7.1 План эксперимента и установка
Как упоминалось выше, DirtyCred использует эксплуатируемые объекты (т. е. те, которые заключают в себе объекты учетных данных) для выполнения манипуляций с памятью, особенно для таких уязвимостей, как внешний доступ и использование после освобождения. Эта манипуляция является одним из важнейших шагов DirtyCred для повышения привилегий. При манипулировании памятью DirtyCred размещает уязвимый объект в кэше, где находится уязвимость. Для разных уязвимостей они демонстрируют возможность повреждения памяти в разных кешах. Таким образом, успех DirtyCred во многом зависит от того, сможет ли он успешно идентифицировать уязвимые объекты, которые могут поместиться в соответствующий кэш. Имея это в виду, мы сначала идентифицируем уникальные объекты, которые можно использовать для каждого кеша.
Чтобы указать объекты, одна инстинктивная реакция состоит в том, чтобы вручную просмотреть код ядра Linux, точно определить эти объекты, которые можно использовать, и выяснить входные данные, которые могут вызвать соответствующее выделение. Однако объем кода ядра Linux велик и изощрен, что делает проверку кода непрактичной. Поэтому для решения этой проблемы мы вводим автоматизированный метод для отслеживания объектов, которые можно использовать, и соответствующие входные данные для запуска их выделения. В нашей оценке мы применяем автоматизированный метод к последнему стабильному ядру (то есть версии 5.16.15 на момент написания этой статьи). Мы рассматриваем объект как пригодный для использования только в том случае, если автоматизированный метод может найти объект, содержащий объект учетных данных, и может продемонстрировать входные данные для выделения этого объекта в куче ядра. Из-за недостатка места мы подробно описываем дизайн и реализацию нашего автоматизированного метода в Приложении А.
В дополнение к выявлению объектов ядра, которые можно использовать, наш эксперимент также исследует возможность использования DirtyCred против реальных уязвимостей. Напомним, что DirtyCred необходимо изменить возможность уязвимости, если уязвимость не предоставляет DirtyCred возможность напрямую менять объекты учетных данных. Как обсуждалось в разделе 4.1, при выполнении поворота уязвимостей DirtyCred может потребоваться перезаписать некоторые важные данные в объекте, который можно использовать. Для различных уязвимостей их способность к перезаписи может значительно различаться, что еще больше влияет на успех повышения привилегий. В результате мы оцениваем эффективность DirtyCred, используя его для эксплуатации многих реальных уязвимостей и изучая, насколько хорошо он может выполнять эксплуатацию против этих уязвимостей.
Мы предполагаем, что ядро Linux оснащено современными методами защиты от эксплойтов, доступными в ядре при выполнении эксплойта. В результате нам необходимо выбрать уязвимости, выявленные в ядре, разработанном в последние годы. В нашей оценке мы выбрали только CVE ядра Linux, о которых сообщалось после 2019 года. В нашем процессе выбора CVE мы отфильтровали те уязвимости, которые не повреждают данные в куче ядра. Кроме того, мы исключили те уязвимости, для которых мы не можем воспроизвести соответствующую панику ядра. И последнее, но не менее важное: мы также устранили те уязвимости, для срабатывания которых требуется установка определенного оборудования. Следуя этим критериям выбора CVE, мы получили набор данных с 24 уникальными CVE. В таблице 2 мы перечислили идентификаторы этих CVE и соответствующие типы уязвимостей. Как мы видим, выбранные нами тестовые примеры покрывают почти все типы уязвимостей в куче ядра.
7.2 Результат эксперимента
Эксплуатируемые объекты. В таблице 1 показаны уязвимые объекты, обнаруженные в каждом кэше ядра. Как мы видим, эксплойтные объекты охватывают почти все основные кэши, кроме kmalloc-8, который редко используется в ядре Linux. Для большинства кешей памяти существует более одного объекта, потенциально пригодного для использования для повышения привилегий Dirty-Cred. В каждом эксплойтном объекте смещение поля, ссылающегося на объект учетных данных, также присутствует в таблице 1. Как мы видим, смещения для разных эксплойтных объектов различаются. Это указывает на то, что у DirtyCred больше шансов найти подходящий объект, соответствующий возможностям уязвимости, и выполнить успешную эксплуатацию. Например, если уязвимость демонстрирует возможность перезаписи 8 байтов в соседний объект по смещению 8-го байта, то эксплойтный объект с критическими данными по 8-му байту значительно облегчит повышение привилегий DirtyCred.
Из таблицы 1 мы также обнаруживаем 5 объектов в 5 общих кэшах. Они заключают ссылку на объект учетных данных в начале объектов. Это означает, что даже если злоумышленники получают только очень ограниченную возможность повреждения памяти (например, перезапись двух нулевых байтов в начале объекта-жертвы), они все равно могут использовать идентифицированный объект для уязвимости для запуска атаки DirtyCred. Следует отметить, что в Таблице 1 также различаются уязвимые объекты, ссылающиеся на Cred и File, с использованием разных символов. Как мы обсудим в разделе 10, объект cred может обеспечить лучшую поддержку выхода из контейнера. Таким образом, адекватные эксплойтные объекты с привязкой к объектам cred указывают на более существенную поддержку при выходе из докера.
Эксплуатируемость. В таблице 2 показаны возможности использования DirtyCred для различных уязвимостей. Как мы видим, DirtyCred успешно демонстрирует обход защиты ядра и повышение привилегий на 16 из 24 уязвимостей, когда базовое ядро Linux включает все механизмы защиты от эксплойтов, описанные в разделе 2.3. Это наблюдение подразумевает, что DirtyCred можно использовать в качестве мощного общего метода эксплуатации для задач эксплуатации уязвимостей ядра. Из 16 успешно эксплуатируемых тестовых случаев 8 относятся к уязвимостям с выходом за границу или с использованием после освобождения, а остальные 8 — с двойным освобождением. DirtyCred преуспевает во всех тестовых случаях с двойным освобождением, поскольку возможность двойного освобождения всегда может быть направлена на недопустимое освобождение объекта учетных данных.
Случаи сбоя в основном связаны с выходом за границу и использованием после освобождения. Что касается OOB-уязвимостей, то в случаях сбоя продемонстрировано повреждение памяти в области виртуальной памяти. Чтобы использовать DirtyCred, нам нужно найти объекты ядра с учетными данными. Эти объекты обычно размещаются в выделенной kmalloc области памяти, а не в виртуальной памяти. В результате DirtyCred не может найти необходимые объекты для успешной эксплуатации. Мы помечаем эти случаи знаком † в таблице 2. Как мы обсудим в разделе 10, неудачное использование этих случаев не означает, что DirtyCred не может использовать уязвимости в виртуальной памяти. Возможности повреждения памяти в виртуальной памяти все еще могут быть преобразованы в возможности, полезные для DirtyCred, если есть подходящие объекты, которые можно использовать, или с использованием других методов поворота возможностей.
В случае сбоя UAF CVE-2022-24122 он не демонстрирует возможность перезаписи через завсиший указатель, а просто демонстрирует способность перезаписи. Как обсуждалось в разделе 4, DirtyCred полагается либо на недопустимую возможность записи, либо на недопустимую возможность свободного доступа. Возможность избыточного считывания CVE-2022-24122 ограничивает DirtyCred для выполнения успешного разворота , поэтому атака не удается. Для CVE-2019-2215 и CVE-2019-1566 они демонстрируют возможность перезаписи. Однако возможность перезаписи не возникает в критической области эксплуатируемых объектов. Без такой возможности DirtyCred не может манипулировать необходимыми полями в объектах ядра, чтобы освободить объект учетных данных, поэтому атака проваливается.
8 ЗАЩИТА ОТ DIRTYCRED
Учитывая возможность эксплуатации, продемонстрированную в разделе выше, мы утверждаем, что DirtyCred представляет собой серьезную угрозу для существующей системы Linux. Хотя технику злоупотребления механизмом блокировки можно защитить путем реинжиниринга файловой системы, по-прежнему недостаточно заблокировать DirtyCred, поскольку его можно запустить с другого пути — подкачки объекта cred. Следовательно, эффективным подходом является предотвращение обмена учетными данными с другим уровнем привилегий. С одной стороны, защита кучи пользовательского пространства не подходит для Dirty-Cred. Ядро хочет, чтобы выделение/освобождение/доступ к памяти было максимально быстрым. В противном случае это приведет к замедлению работы пользовательских программ и всей системы. Поэтому распределитель памяти в ядре гораздо проще, чем в пространстве пользователя (например, ptmalloc). Этот факт делает защиту кучи пользовательского пространства неприменимой к пространству ядра. С другой точки зрения, даже если в ядре Linux реализовано множество механизмов защиты (например, CFI, SMEP, SMAP, KASLR и т. д.), ни одна из существующих средств защиты ядра не эффективна для DirtyCred по следующим причинам.
Во-первых, DirtyCred не нарушает целостность потока управления, что делает бесполезными усилия по защите потока управления ядром. Во-вторых, DirtyCred не полагается на какой-то один компонент эксплуатации для эксплуатации. Как показано в разделе 7, ценные объекты для эксплуатации распределены почти по всем общим кэшам. Таким образом, защита от DirtyCred путем устранения объектов, которые можно использовать, практически невозможна. В-третьих, DirtyCred выполняет свою цель эксплуатации, помещая законный объект учетных данных в незаконную область памяти, но не вмешиваясь в содержимое объекта учетных данных. Эта практика эксплуатации снижает вероятность того, что существующие методы защиты целостности учетных данных (например, защита ядра в реальном времени Samsung Knox [43]) будут эффективными. И последнее, но не менее важное: DirtyCred выполняет повышение привилегий путем обмена местами между объектами учетных данных с высоким и низким уровнем привилегий. Этот метод эксплуатации не работает во многих схемах изоляции объектов ядра (например, AUTOSLAB [34] и xMP [44]), поскольку они разделяют критические объекты ядра в своих собственных областях памяти на основе типа объектов, а не их привилегий.
С этой целью мы утверждаем, что одним из эффективных решений защиты от DirtyCred будет изоляция объектов с высокими и низкими привилегиями, заставляя их не использовать одно и то же пространство памяти. Таким образом, DirtyCred больше не сможет перекрывать объекты с разными привилегиями для повышения привилегий. Для достижения вышеуказанной цели простой реакцией является создание двух разных кешей. Один используется для хранения объектов с высоким уровнем привилегий. Другой используется для хранения объектов с низким уровнем привилегий. Поскольку кэши естественным образом изолированы, такой дизайн может гарантировать, что объекты с разными привилегиями не будут перекрываться. Однако, как мы обсуждали в Разделе 4.2, после уничтожения кэша памяти вспомогательный распределитель Linux повторно использует базовую страницу памяти. Таким образом, DirtyCred по-прежнему может начать атаку, злоупотребляя этой функцией повторного использования страниц памяти.
Дизайн. Принимая во внимание приведенный выше анализ, мы предлагаем практическое решение защиты, которое создает кеш для объектов с высоким уровнем привилегий в области виртуальной памяти и оставляет объекты с низким уровнем привилегий в обычной области памяти (т. е. в области памяти с прямым отображением). Область виртуальной памяти относится к динамическому распределению практически непрерывной памяти внутри ядра. Он находится в области памяти, определенной от VMALLOC_START до VMALLOC_END. Поскольку он отделен от области памяти с прямым отображением, области, предназначенные для объектов с высоким и низким уровнем привилегий, никогда не перекрываются даже после уничтожения кэшей и повторного использования базовых страниц памяти.
Выполнение. В этой работе мы реализовали предложенную нами защиту от DirtyCred на ядре Linux версии 5.16.15. В нашей реализации мы вручную модифицировали способы размещения объектов cred и файловых объектов в ядре. Если выделение предназначено для привилегированных, мы выделяем их с помощью виртуальной памяти. Чтобы быть конкретным, при распределении объектов cred мы проверяем привилегию на основе UID объекта. Если UID соответствует GLOBAL_ROOT_UID, что означает выделение для привилегированных объектов cred, мы используем vmalloc в качестве распределителя для выделения виртуальной памяти для объекта. Для файловых объектов мы исследуем режим файла. Если файл открыт с правами на запись, мы соответствующим образом выделим файловый объект с помощью vmalloc. Наша реализация доступна по адресу [2].
Техническое обсуждение. Предлагаемая нами защита защищает ядро Linux, обеспечивая изоляцию памяти для объектов учетных данных. Как упоминалось выше, наша реализация определяет привилегию во время выделения объекта. Однако привилегию можно изменить, изменив UID во время выполнения (например, изменив объект учетных данных с низкими привилегиями на объект с высокими привилегиями с помощью системного вызова setuid). Когда это происходит, наша предложенная выше защита столкнется с проблемами безопасности, потому что мы выполняем изоляцию объекта только во время выделения. Чтобы решить эту проблему, мы вручную модифицируем способ изменения объектов учетных данных ядра в нашей реализации. В частности, если ядро изменит UID объекта учетных данных на GLOBAL_ROOT_UID, мы скопируем объект учетных данных с высокими привилегиями в область «vmalloc», а не изменим исходный. Однако мы думаем, что могут возникнуть некоторые проблемы, если будущая разработка ядра не будет следовать той же схеме. В результате мы оставляем поиск альтернативных решений частью нашей будущей работы.
Оценка эффективности. Чтобы оценить производительность нашего защитного механизма, мы провели два теста с ванильным ядром Linux и нашим ядром с поддержкой защиты на чистой машине (с 4-ядерным процессором Intel, 16 ГБ ОЗУ и 1000 ГБ HHD). Наши тесты включают микротест из LMbench v3.0 [41] и макротест из Phoronix Test Suite [42]. LM-bench оценивает задержку и пропускную способность системных вызовов и системного ввода-вывода, тогда как Phoronix Test Suite исследует производительность реальных приложений на двух ядрах Linux. Что касается LMbench, мы выполнили тест 10 раз, чтобы избежать случайности, и взяли среднее значение за наблюдаемую производительность. Для Phoronix Test Suite мы запустили тест в пакетном режиме, который запускает тест 50 раз и выводит средние значения.
В таблице 3 показаны результаты нашей оценки. Во-первых, мы можем заметить, что предлагаемый нами метод в основном приводит к незначительным потерям производительности, что указывает на то, что наша защита невелика. Во-вторых, мы можем наблюдать некоторое умеренное снижение производительности для тестовых случаев — «Создание файла 10k» и «Удаление файла 10k» — в LM-Bench. Как показано в Таблице 3, предлагаемая нами защита вносит накладные расходы более 4%. Причина такого снижения производительности заключается в том, что файловые объекты были выделены в область виртуальной памяти через vmalloc, а не в обычную область памяти через kmalloc. По сравнению с kmalloc, vmalloc работает относительно медленно, потому что виртуальная память должна переназначать буферное пространство на практически непрерывный диапазон, тогда как kmalloc никогда не переназначает.
Следует отметить, что удаление файла снижает производительность ниже, чем создание файла (4,25% против 7,17%). Причина различия заключается в том, что объект освобождения файла выполняется через RCU, который выполняется асинхронно с процессом удаления файла. Хотя умеренные накладные расходы могут вызвать беспокойство у некоторых производственных систем, они значительно улучшают защиту ядра от DirtyCred. В этой работе нашей основной целью является повышение осведомленности сообщества Linux, а не создание безопасного и эффективного решения для защиты. Мы оставляем исследование альтернативного оборонного решения в качестве наших будущих исследований. Наконец, следует также отметить, что в некоторых случаях продемонстрировано небольшое улучшение производительности после того, как мы внедрили защиту в ядро Linux. В основном это связано с шумом нашего эксперимента, хотя мы пытались минимизировать шум, насколько это было возможно, запустив тест несколько раз и отключив ускорение процессора на машине с «голым железом».
СВЯЗАННЫЕ РАБОТЫ
В этой работе представлен новый метод эксплуатации ядра и соответствующая защита для снижения угрозы. В результате работы, наиболее важные для нас, включают эксплуатацию ядра и смягчение последствий эксплуатации ядра. Далее мы суммируем работы по этим двум темам и обсуждаем, чем они отличаются от предлагаемых нами методов.
Эксплуатация ядра. Методы эксплуатации ядра развивались вместе с развитием защиты ядра. До введения предотвращения выполнения в режиме супервизора (SMEP) [29] технология — ret2usr [32] — использовала ядро Linux, переводя выполнение ядра в пространство пользователя. После широкого развертывания SMEP в Linux этот метод больше не работает, поскольку SMEP предотвращает выполнение ядра в пользовательском пространстве. Вслед за SMEP было предложено предотвратить доступ в режиме супервизора (SMAP) [7] для блокировки прямого доступа к пользовательскому пространству, что еще больше усиливает разделение доступа к ядру и пользовательскому пространству. Чтобы обойти защиту, обеспечиваемую SMEP/SMAP, исследователи предложили ряд новых методов эксплуатации. Например, Кемерлис и др. предложил метод ret2dir [31], который позволяет злоумышленнику зеркалировать данные пользовательского пространства в адресном пространстве ядра. Ву и др. представить KEPLER [48], который использует особый гаджет кода ядра для преобразования управления ПК в переполнение стека и, таким образом, обеспечивает длинную цепочку ROP.
Чтобы предотвратить ROP-атаки на ядро Linux, Linux вводит KASLR, который увеличивает сложность эксплуатации за счет рандомизации схемы адресов памяти ядра. Однако после принятия этой защиты ядра эксперты по безопасности предложили множество практических методов [5, 16, 23, 28] для обхода KASLR. Например, с помощью эластичных объектов в ядре. Чен и др. предложила ELOISE [5], которая могла раскрывать конфиденциальную информацию о ядре после перезаписи поля длины эластичных объектов. Грусс и др. предложил аппаратную атаку по побочному каналу, которая использует инструкции предварительной выборки для обхода KASLR. Недавно некоторые специалисты по безопасности даже предложили использовать уязвимости в процессорах для запуска атак Meltdown [39] и Spectre [33] и тем самым обойти защиту KASLR в Linux.
В дополнение к рандомизации адресного пространства памяти исследователи безопасности также предложили методы рандомизации расположения кучи памяти в ядре Linux [17, 47]. При включенной рандомизации кучи расположение кучи больше не является линейным, что усложняет злоумышленникам выполнение манипуляций с расположением кучи. Однако после успеха рандомизации расположения кучи Сюй и соавт. предложил метод коллизии памяти [49]. Этот метод использует механизм повторного использования памяти для эксплуатации уязвимостей ядра, связанных с использованием после освобождения, без помех из-за рандомизации кучи.
В отличие от описанных выше методов эксплуатации, направленных на обход некоторых конкретных средств защиты ядра и устранения эксплойтов, но не на конечную цель эксплуатации (например, повышение привилегий), наша работа сосредоточена на комплексной эксплуатации без головной боли, связанной с обходом широко развернутых защиты ядра. Таким образом, наш метод эксплуатации является более общим и последовательным. Как мы обсудим в Разделе 10, DirtyCred может даже облегчить возможность экранирования контейнеров и корневых устройств Android.
Защита ядра. В дополнение к средствам защиты ядра, представленным вместе с существующими методами эксплуатации, описанными выше, существует также множество других механизмов защиты ядра и предотвращения эксплойтов. Эти средства защиты предлагаются академическими кругами и промышленностью, и им уделяется значительное внимание со стороны сообщества безопасности. Здесь мы кратко представили некоторые недавно предложенные или в основном принятые на практике.
Чтобы предотвратить атаки по сторонним каналам на ядро Linux, Грусс и др. предложил механизм строгой изоляции ядра и пользовательского пространства — KAISER [22]. Этот механизм может гарантировать, что аппаратное обеспечение не хранит никакой информации об адресах ядра во время работы в пользовательском режиме. Чтобы улучшить KASLR, разработчики ядра Linux вводят функцию рандомизации адресного пространства гранулярного ядра (FGKASLR [1]). Рандомизируя макет до уровня функции кода, FGKASLR делает атаку повторного использования кода более сложной. Чтобы воспрепятствовать перехвату потока управления, исследователи также предложили различные защитные механизмы для обеспечения целостности потока управления в ядре Linux [11, 15, 18, 50]. Например, Ю и др. предложил реализовать встроенную в ядро защиту целостности потока управления с помощью аутентификации указателя ARM [50].
В дополнение к описанной выше защите потока управления ядром существует также ряд методов защиты, направленных на обеспечение защиты критически важных данных ядра [4, 13, 27, 40, 46]. Например, такими средствами защиты ядра являются AUTOSLAB [34] и xMP [44]. Как мы обсуждали в разделе 8, AUTOSLAB изолирует разные типы объектов в разные кэши памяти, что уменьшает количество объектов, полезных для манипулирования памятью кучи ядра. xMP использует методы виртуализации, чтобы изолировать конфиденциальные данные и, таким образом, предотвратить их подделку злоумышленниками.
С точки зрения философии защиты, наш защитный механизм отличается от работ, обеспечивающих целостность потока управления ядром. Это похоже на работы, которые изолируют критические данные ядра. Однако наша защита совершенно отличается от этих работ с технической точки зрения. Вместо того, чтобы изолировать объекты на основе типов и чувствительности, наша защита выполняет изоляцию памяти на основе привилегий объектов ядра. Таким образом, он более эффективен для защиты от угрозы DirtyCred.
10 ОБСУЖДЕНИЕ И БУДУЩАЯ РАБОТА
В этом разделе мы обсудим некоторые другие вопросы, которые мы еще не обсуждали, и представим наши будущие усилия.
Убегающий контейнер. Помимо повышения привилегий в Linux, DirtyCred может пассивно и активно способствовать побегу контейнера. Как упоминалось ранее, DirtyCred выполняет эксплойт путем замены либо файловых объектов, либо объектов cred. Используя файловые объекты для эксплуатации, DirtyCred может перезаписать файл с высоким уровнем привилегий. Однако ни один файл в контейнере не предоставляет права на переключение пространства имен. Чтобы решить эту проблему, в недавней работе [12] показано, что злоумышленник может пассивно ждать процесса runC и, таким образом, выполнять корневые команды на хосте, перезаписывая процесс. Руководствуясь этой идеей, DirtyCred может использовать механизм подкачки файловых объектов, чтобы перезаписать процесс runC и, таким образом, выполнить выход из контейнера.
В отличие от описанного выше метода, использование объектов cred для выхода из контейнера не требует пассивного ожидания. Для этого DirtyCred может сначала активировать уязвимость ядра Linux, поменять местами объекты cred и, таким образом, повысить привилегии злоумышленника до SYS_ADMIN. Имея в руках эту привилегию SYS_ADMIN ↩→, злоумышленник может затем следовать ранее предложенному методу выхода из Docker [3], который монтирует контрольную группу, а затем использует механизм notify_no_release для выполнения команды root в хост-системе. Чтобы продемонстрировать способность DirtyCred выйти из контейнера, мы предоставляем рабочий эксплойт в [2]. Рецензенты могли загрузить эксплойт и увидеть больше деталей побега из докера.
Рут Android. Помимо побега из контейнера, DirtyCred также может рутировать Android. Ядро Android разработано на основе общего ядра Linux. На практике ядро Android сложнее взломать по сравнению с общим ядром из-за более строгого контроля доступа и новых средств защиты [19]. DirtyCred может рутировать Android с помощью двух способов атак, описанных в этой статье. С одной стороны, DirtyCred может напрямую подменять учетные данные задачи, что дает злоумышленникам привилегированные учетные данные задачи, то есть привилегию root. С другой стороны, DirtyCred может сначала использовать свои возможности манипулирования файлами для перезаписи общей системной библиотеки, что позволяет повысить привилегии из ограниченной песочницы. Затем он мог перезаписывать модули ядра вредоносным кодом, выполнять произвольное чтение и запись и, в конечном итоге, отключать SELinux на Android. Мы продемонстрировали способность DirtyCred рутировать Android с помощью уязвимостей нулевого дня. К моменту написания этой статьи мы сообщили об уязвимостях в Google и получили их подтверждение.
Эксплуатация кросс-версии/архитектуры. При создании эксплойта под руководством DirtyCred можно было ожидать, что один и тот же код эксплойта может работать на разных версиях ядра или архитектурах без каких-либо изменений по следующим причинам. Во-первых, в отличие от других методов эксплуатации, которые требуют утечки базового адреса ядра для обхода KASLR, DirtyCred не нужно обрабатывать KASLR. В результате код эксплуатации не содержит никаких данных, специфичных для версий ядра или базовых архитектур. Во-вторых, многие предыдущие методы эксплуатации ядра (например, KEPLER [48]) в значительной степени полагаются на ROP для повышения привилегий. При переносе таких эксплойтов на другую архитектуру необходимо модифицировать цепочку ROP и, таким образом, сохранить ее работоспособность. DirtyCred не использует какие-либо данные об архитектуре, как обсуждалось в документе. Таким образом, после разработки фрагмента кода эксплойта для уязвимости этот эксплойт может работать на других уязвимых ядрах, независимо от их версий и базовых архитектур.
Другие способы разворота. В Разделе 4 мы предложили некоторые методы преобразования возможности повреждения памяти в возможность, полезную для DirtyCred. В нашей оценке мы обнаружили, что уязвимости, возникающие в виртуальной памяти, труднее использовать с помощью DirtyCred. Причина в том, что в виртуальной памяти меньше объектов, пригодных для эксплуатации, что ограничивает возможность поворота от исходного повреждения памяти к тем, которые полезны для DirtyCred. Мы утверждаем, что это не означает, что уязвимости в виртуальной памяти нельзя использовать с помощью DirtyCred. Например, CVE-2021-34866 предоставляет возможность выхода за границы, которая демонстрирует перезапись памяти, выделенной vmalloc. Используя наш поворотный подход, мы не можем повернуть эту возможность для освобождения объекта учетных данных. Однако в недавней статье [24] показан сложный метод, который может преобразовать эту возможность перезаписи на vmalloc в произвольное чтение и запись и, таким образом, включить возможность двойного освобождения. Как обсуждалось и показано в Разделе 4.2, используя возможность двойного освобождения, DirtyCred имеет высокие шансы выполнить повышение своих привилегий. В недавней работе [35] помимо возможности поворота уязвимости демонстрируется подход к изучению различных возможностей уязвимости. Мы утверждаем, что эти методы дополняют атаку DirtyCred, поскольку, как показано в Разделе 3.1, DirtyCred все еще может быть запущен без разворота. В этой работе мы оставляем изучение других методов поворота как часть наших будущих исследований.
Стабильность. На стабильность эксплуатации DirtyCred могут повлиять два критических фактора, как и все методы эксплуатации ядра. Во-первых, при повороте возможностей уязвимостей DirtyCred приходится манипулировать расположением памяти, занимая целевую область памяти. В этот момент стабильность эксплуатации может варьироваться, если системные действия влияют на манипуляции с расположением памяти. Во-вторых, при эксплуатации уязвимости ядра способ активации уязвимости также может сильно повлиять на стабильность эксплуатации. Для повышения стабильности эксплуатации в недавней работе [51] предлагается ряд методов стабилизации эксплуатации ядра. В этой работе наша цель — оценить возможности использования DirtyCred в реальных условиях. Мы пришли к выводу, что DirtyCred может успешно использовать уязвимость, если она демонстрирует пригодность для использования. В будущем мы изучим, как использовать существующие методы стабилизации эксплуатации, чтобы повысить показатель успешности эксплуатации DirtyCred.
TOCTOU. Как обсуждалось выше, DirtyCred меняет местами объекты учетных данных в критическом временном окне. Интуиция подсказывает, что существующие защитные механизмы TOC-TOU могут помешать предложенному нами методу эксплуатации. Согласно недавней исследовательской статье [45], защита TOCTOU может быть разделена на обнаружение исходного кода, обнаружение посмертно, интерпозицию системных вызовов, согласованность памяти внутри/между процессами, системные вызовы транзакций и файловую систему песочницы. Обнаружение исходного кода анализирует исходный код целевой программы. Очевидно, что такой метод защиты не может быть применен для защиты от нашей эксплуатации, потому что в DirtyCred нет идентифицированного шаблона исходного кода. Посмертное обнаружение выявляет уязвимости TOCTOU уже после фактического проведения атаки. Такого рода метод должен происходить до анализа, который не влияет на нашу эксплуатацию. Причина в том, что мы используем неожиданные свободные операции, которые нельзя было увидеть в процессе анализа. Интерпозиция системных вызовов отслеживает последовательность системных вызовов и, таким образом, определяет атаки. Наш метод эксплуатации не использует вредоносную последовательность системных вызовов. В результате интерпозиция системных вызовов также не блокировала бы нас. Согласованность памяти внутри/между процессами защищает общие переменные в нескольких потоках, записывая операции над переменными. Наша эксплуатация применяет неожиданные операции, которые не удалось записать. Транзакционные системные вызовы и файловая система песочницы нацелены на состояние гонки между чтением и записью файла. Наш метод не требует этого условия.
11 ЗАКЛЮЧЕНИЕ
Ядро Linux оснащено различными схемами защиты и предотвращения эксплуатации, что затрудняет успешное использование ядра. Чтобы обойти защиту ядра, злоумышленник должен использовать уязвимость с надежной возможностью отключить защиту. В этой работе мы показываем новый метод эксплуатации — DirtyCred. Он может обеспечить возможность эксплуатации и обхода защиты без жизненно важного требования к уязвимости ядра. Используя DirtyCred, мы демонстрируем, что злоумышленник может использовать почти произвольную уязвимость ядра на основе кучи для подкачки объектов учетных данных. Подмена учетных данных может ввести ядро Linux в заблуждение, полагая, что файл или задача с высоким уровнем привилегий находятся в режиме с низким уровнем привилегий. Таким образом, непривилегированный пользователь может повысить свои привилегии в злонамеренных целях. С этим открытием мы делаем вывод, что DirtyCred саботирует существующую архитектуру защиты Linux. Если наше сообщество безопасности не предпримет немедленных действий в ответ на этот новый метод эксплуатации, системы под управлением Linux вскоре окажутся в опасности. Их пользователи понесут значительные личные потери. Следуя этому выводу, в этой работе также был предложен механизм изоляции объектов привилегий в качестве защитного предложения. В этой работе мы реализовали этот защитный механизм в качестве прототипа ядра Linux и обнаружили, что он может защитить Linux с незначительными, а иногда и умеренными затратами. С этим новым открытием мы также приходим к выводу, что изоляция памяти на основе объектных привилегий может быть необходима для защиты от угрозы DirtyCred. Мы сообщили о части результатов нашего исследования поставщикам программного и аппаратного обеспечения, которые потенциально могут быть затронуты DirtyCred, и активно работаем с ними, чтобы помочь им понять и смягчить угрозу.
REFERENCES
[1] Kristen Carlson Accardi. 2020. Function Granular KASLR. (2020). https://lwn.
net/Articles/824307/
[2] Anonymous. 2022. DirtyCred Exploit. (2022). https://hackmd.io/
giRE2P2oQHektZzOG053IQ
[3] Alex Chapman. 2020. Privileged Container Escape Control Groups re-
lease_agent. (2020). https://ajxchapman.github.io/containers/2020/11/19/
privileged-container-escape.html
[4] Quan Chen, Ahmed M Azab, Guruprasad Ganesh, and Peng Ning. 2017.
Privwatcher: Non-bypassable monitoring and protection of process credentials
from memory corruption attacks. In Proceedings of the 2017 ACM on Asia Confer-
ence on Computer and Communications Security.
[5] Yueqi Chen, Zhenpeng Lin, and Xinyu Xing. 2020. A systematic study of elastic
objects in Kernel exploitation. In Proceedings of the 2020 ACM SIGSAC Conference
on Computer and Communications Security.
[6] Yueqi Chen and Xinyu Xing. 2019. Slake: Facilitating slab manipulation for
exploiting vulnerabilities in the linux kernel. In Proceedings of the 2019 ACM
SIGSAC Conference on Computer and Communications Security.
[7] Jonathan Corbet. 2012. Supervisor mode access prevention. (2012). https:
//lwn.net/Articles/517475/
[8] Jonathan Corbet. 2017. The current state of kernel page-table isolation. (2017).
lwn.net
[9] The MITRE Corporation. 2021. CVE-2021-4154. (2021). https://cve.mitre.org/
cgi-bin/cvename.cgi?name=CVE-2021-4154
[10] The MITRE Corporation. 2022. CVE-2022-0847. (2022). https://cve.mitre.org/
cgi-bin/cvename.cgi?name=CVE-2022-0847
[11] John Criswell, Nathan Dautenhahn, and Vikram Adve. 2014. KCoFI: Complete
control-偎ow integrity for commodity operating system kernels. In Proceedings of
the 2014 IEEE Symposium on Security and Privacy.
[12] Datadog. 2022. Using the Dirty Pipe Vulnerability to Break Out
from Containers. (2022). https://www.datadoghq.com/blog/engineering/
dirty-pipe-container-escape-poc/
[13] Lucas Davi, David Gens, Christopher Liebchen, and Ahmad-Reza Sadeghi. 2017.
PT-Rand: Practical Mitigation of Data-only Attacks against Page Tables.. In
Proceedings of the 2017 Network and Distributed Systems Security Symposium.
[14] Jake Edge. 2013. Kernel address space layout randomization. (2013). https:
//lwn.net/Articles/569635/
[15] Jake Edge. 2020. Control-偎ow integrity for the kernel. (2020). https://lwn.net/
Articles/569635/
[16] Dmitry Evtyushkin, Dmitry Ponomarev, and Nael Abu-Ghazaleh. 2016. Jump
over ASLR: Attacking branch predictors to bypass ASLR. In 2016 49th Annual
IEEE/ACM International Symposium on Microarchitecture.
[17] Thomas Garnier. 2016. mm: SLAB freelist randomization. (2016). https://lwn.
net/Articles/685047/
[18] Xinyang Ge, Nirupama Talele, Mathias Payer, and Trent Jaeger. 2016. Fine-
grained control-偎ow integrity for kernel software. In Proceedings of the 2016 IEEE
European Symposium on Security and Privacy.
[19] google. 2022. Kernel Control Flow Integrity. (2022). https://source.android.com/
devices/tech/debug/kc㜠
[20] Google. 2022. Roses are red, Violets are blue, Giving leets more
sweets. All of 2022! (2022). https://security.googleblog.com/2022/02/
roses-are-red-violets-are-blue-giving.html
[21] Google. 2022. syzkaller kernel fuzzer. (2022). https://github.com/google/syzkaller
[22] Daniel Gruss, Moritz Lipp, Michael Schwarz, Richard Fellner, Clйmentine Mau-
rice, and Stefan Mangard. 2017. Kaslr is dead: long live kaslr. In International
Symposium on Engineering Secure Software and Systems. 161–176.
[23] Daniel Gruss, Clйmentine Maurice, Anders Fogh, Moritz Lipp, and Stefan Man-
gard. 2016. Prefetch side-channel attacks: Bypassing SMAP and kernel ASLR. In
Proceedings of the 2016 ACM SIGSAC conference on computer and communications
security.
[24] HexRabbit. 2021. CVE-2021-34866 Writeup. (2021). https://github.com/
HexRabbit/CVE-writeup/tree/master/CVE-2021-34866
[25] Jann Horn. 2022. Linux: UAF via double-fdput. (2022). https://bugs.chromium.
org/p/project-zero/issues/detail?id=808
[26] David Howells. 2022. CREDENTIALS IN LINUX. (2022). https://www.kernel.
org/doc/Documentation/security/credentials.txt
[27] Kaiming Huang, Yongzhe Huang, Mathias Payer, Zhiyun Qian, Jack Sampson,
Gang Tan, and Trent Jaeger. 2022. The Taming of the Stack: Isolating Stack Data
from Memory Errors. In Proceedings of the 2022 Network and Distributed Systems
Security Symposium.
[28] Ralf Hund, Carsten Willems, and Thorsten Holz. 2013. Practical timing side chan-
nel attacks against kernel space ASLR. In Proceedings of the 2013 IEEE Symposium
on Security and Privacy.
[29] Mateusz Jurczyk. 2011. SMEP: What is it, and how to beat
it on Windows. (2011). https://j00ru.vexillium.org/2011/06/
smep-what-is-it-and-how-to-beat-it-on-windows/
[30] Max Kellermann. 2022. The Dirty Pipe Vulnerability. (2022). https://dirtypipe.
cm4all.com/
[31] Vasileios P Kemerlis, Michalis Polychronakis, and Angelos D Keromytis. 2014.
ret2dir: Rethinking kernel isolation. In Proceedings of the 23rd USENIX Conference
on Security Symposium.
[32] Vasileios P Kemerlis, Georgios Portokalidis, and Angelos D Keromytis. 2012.
{kGuard}: Lightweight Kernel Protection against {Return-to-User} Attacks. In
Proceedings of the 21st USENIX Conference on Security Symposium.
[33] Paul Kocher, Jann Horn, Anders Fogh, Daniel Genkin, Daniel Gruss, Werner
Haas, Mike Hamburg, Moritz Lipp, Stefan Mangard, Thomas Prescher, et al. 2019.
Spectre attacks: Exploiting speculative execution. In Proceedings of the 2019 IEEE
Symposium on Security and Privacy.
[34] Zhenpeng Lin. 2021. How AUTOSLAB Changes the Memory Unsafety Game.
(2021). https://grsecurity.net/how_autoslab_changes_the_memory_unsafety_
game/
[35] Zhenpeng Lin, Yueqi Chen, Yuhang Wu, Chensheng Yu, Dongliang Mu, Xinyu
Xing, and Kang Li. 2022. GREBE: Unveiling Exploitation Potential for Linux
Kernel Bugs. In Proceedings of the 2022 IEEE Symposium on Security and Privacy.
[36] Linux. 2022. File management in the Linux kernel. (2022). https://www.kernel.
org/doc/Documentation/security/credentials.txt
[37] Linux. 2022. FUSE’s introduction in the Linux kernel user’s and administrator’s
guide. (2022). https://www.kernel.org/doc/html/latest/㜠lesystems/fuse.html
[38] Linux. 2022. Userfaultfd’s introduction in the Linux kernel user’s and adminis-
trator’s guide. (2022). https://www.kernel.org/doc/html/latest/admin-guide/mm/
userfaultfd.html
[39] Moritz Lipp, Michael Schwarz, Daniel Gruss, Thomas Prescher, Werner Haas,
Anders Fogh, Jann Horn, Stefan Mangard, Paul Kocher, Daniel Genkin, et al. 2018.
Meltdown: Reading kernel memory from user space. In Proceedings of the 27th
USENIX Conference on Security Symposium.
[40] Derrick McKee, Yianni Giannaris, Carolina Ortega Perez, Howard Shrobe, Mathias
Payer, Hamed Okhravi, and Nathan Burow. Preventing Kernel Hacks with HAKC.
In Proceedings 2022 Network and Distributed System Security Symposium.
[41] Larry McVoy and Carl Staelin. 2022. LMbench - Tools for Performance Analysis.
(2022). http://lmbench.sourceforge.net/
[42] Phoronix Media. 2022. Open-Source, Automated Benchmarking. (2022). https:
//www.phoronix-test-suite.com/
[43] Samsung Knox News. 2016. Real-time Kernel Protection (RKP). (2016). https:
//www.samsungknox.com/en/blog/real-time-kernel-protection-rkp
[44] Sergej Proskurin, Marius Momeu, Seyedhamed Ghavamnia, Vasileios P Kemerlis,
and Michalis Polychronakis. 2020. xmp: Selective memory protection for kernel
and user space. In Proceedings of the 2020 IEEE Symposium on Security and Privacy.
[45] Razvan Raducu, Ricardo J. Rodrнguez, and Pedro Бlvarez. 2022. Defense and
Attack Techniques Against File-Based TOCTOU Vulnerabilities: A Systematic
Review. IEEE Access 10 (2022), 21742–21758.
[46] Chengyu Song, Byoungyoung Lee, Kangjie Lu, William Harris, Taesoo Kim, and
Wenke Lee. 2016. Enforcing Kernel Security Invariants with Data Flow Integrity..
In Proceedings 2016 Network and Distributed System Security Symposium.
[47] Dan Williams. 2018. Randomize free memory. (2018). https://lwn.net/Articles/
767614/
[48] Wei Wu, Yueqi Chen, Xinyu Xing, and Wei Zou. 2019. {KEPLER}: Facilitating
control-偎ow hijacking primitive evaluation for Linux kernel vulnerabilities. In
Proceedings of the 28th USENIX Conference on Security Symposium.
[49] Wen Xu, Juanru Li, Junliang Shu, Wenbo Yang, Tianyi Xie, Yuanyuan Zhang,
and Dawu Gu. 2015. From collision to exploitation: Unleashing use-after-free
vulnerabilities in linux kernel. In Proceedings of the 22nd ACM SIGSAC Conference
on Computer and Communications Security.
[50] Sungbae Yoo, Jinbum Park, Seolheui Kim, Yeji Kim, and Taesoo Kim. 2021. In-
Kernel Control-Flow Integrity on Commodity OSes using ARM Pointer Authen-
tication. arXiv preprint arXiv:2112.07213 (2021).
[51] Kyle Zeng, Yueqi Chen, Haehyun Cho, Xinyu Xing, Adam Doupй, Yan Shoshi-
taishvili, and Ti搊any Bao. 2022. Playing for K(H)eaps: Understanding and Improv-
ing Linux Kernel Exploit Reliability. In Proceedings of the 31st USENIX Conference
on Security Symposium.
Переведено специально для xss.pro
Автор перевода: yashechka
Источник:
DirtyCred: Escalating Privilege in Linux Kernel
Zhenpeng Lin
zplin@u.northwestern.edu
Northwestern University
Yuhang Wu
yuhang.wu@northwestern.edu
Northwestern University
Xinyu Xing
xinyu.xing@northwestern.edu
Northwestern University
Сообщается, что уязвимость ядра DirtyPipe присутствует почти во всех версиях Linux, начиная с 5.8. Используя эту уязвимость, злоумышленник может выполнить эскалацию привилегий без срабатывания существующей защиты ядра и защиты от эксплойтов, что делает эту уязвимость особенно неприятной. Однако успех эксплуатации DirtyPipe во многом зависит от возможностей этой уязвимости (т. е. внедрения данных в произвольный файл через конвейеры Linux). Такая возможность редко используется для других уязвимостей ядра, что делает защиту относительно простой. Пока пользователи Linux устранят уязвимость, система может быть относительно безопасной.
В этой работе предлагается новый метод эксплуатации — DirtyCred — доведение других уязвимостей ядра Linux до уровня DirtyPipe. С технической точки зрения, учитывая уязвимость ядра Linux, наш метод эксплуатации меняет местами непривилегированные и привилегированные учетные данные ядра и, таким образом, обеспечивает возможность эксплуатации уязвимости, подобную DirtyPipe. Благодаря этой возможности злоумышленник может получить возможность повысить привилегии и даже сбежать из контейнера. Мы оценили этот подход к эксплуатации на 24 реальных уязвимостях ядра в полностью защищенной системе Linux. Мы обнаружили, что DirtyCred может продемонстрировать пригодность для эксплуатации на 16 уязвимостях, что указывает на серьезность безопасности DirtyCred. После оценки возможности использования в этой работе предлагается новый механизм защиты ядра. В отличие от существующих средств защиты ядра Linux, наша новая защита изолирует объекты учетных данных ядра в непересекающихся областях памяти на основе их собственных привилегий. Результат нашего эксперимента показывает, что новая защита в основном приводит к незначительным накладным расходам.
ВВЕДЕНИЕ
В настоящее время Linux стал популярной мишенью для киберпреступников из-за его популярности среди мобильных устройств, облачной инфраструктуры и веб-серверов. Чтобы обезопасить Linux, разработчики ядра и эксперты по безопасности вводят различные средства защиты ядра и используют методы защиты (например, KASLR [14] и CFI [19]), что делает эксплуатацию ядра беспрецедентно сложной. Чтобы успешно выполнить цель эксплуатации, современный злоумышленник должен идентифицировать эти мощные уязвимости ядра с возможностью отключения соответствующей защиты.
Тем не менее, недавняя уязвимость (обозначенная как CVE-2022-0847 [10]) и метод ее эксплуатации привлекают значительное внимание сообщества кибербезопасности. Из-за своей вредоносности и воздействия он даже получил прозвище — DirtyPipe [30]. В отличие от уязвимостей ядра без торговой марки, эксплуатация DirtyPipe обеспечивает повышение привилегий, не требуя отключения широко распространенной защиты ядра и устранения эксплойтов. Эта характеристика приводит к неэффективности существующих средств защиты Linux и, таким образом, ставит под угрозу многие системы, управляемые ядром Linux (например, устройства Android).
Несмотря на то, что DirtyPipe обладает мощными возможностями, возможности его использования тесно связаны с возможностями уязвимости (т. е. злоупотреблением механизмом канала ядра Linux для внедрения данных в произвольные файлы). Для других уязвимостей ядра Linux такая возможность злоупотребления каналом предоставляется редко. В результате действия, предпринятые сообществом Linux и производителями устройств (например, Google), заключаются в том, чтобы быстро выпустить исправление для исправления ошибки ядра и, таким образом, устранить поверхность атаки. Без этой поверхности для атаки эксплуатация полностью защищенного ядра Linux по-прежнему затруднительна. Что касается других уязвимостей ядра, по-прежнему сложно обеспечить такой же уровень воздействия на безопасность, как у DirtyPipe.
В этой работе мы представляем новый общий метод эксплуатации, с помощью которого даже обычные уязвимости ядра могут выполнять ту же цель эксплуатации, что и DirtyPipe. С технической точки зрения наш метод эксплуатации отличается от DirtyPipe. Он не зависит ни от конвейерного механизма Linux, ни от природы уязвимости CVE-2022-0847. Вместо этого он использует уязвимость, приводящую к повреждению памяти кучи, чтобы заменить объект учетных данных ядра с низким уровнем привилегий на объект с высоким уровнем привилегий. Эта практика сбивает с толку ядро Linux, заставляя его думать, что непривилегированный пользователь может получить разрешение на работу с файлами или процессами с высоким уровнем привилегий. Таким образом, мы назвали этот метод эксплуатации в честь DirtyCred.
При эксплуатации DirtyCred сталкивается с тремя критическими техническими проблемами. Во-первых, необходимо преобразовать возможность уязвимости в функцию, полезную для подкачки объектов учетных данных, поскольку уязвимости разных типов предоставляют разные возможности в повреждении памяти, что на первый взгляд может показаться недостаточным для подкачки объектов учетных данных. Во-вторых, DirtyCred необходимо строго контролировать временное окно для запуска обмена объектами. Как мы обсудим в разделе 3, ценное для DirtyCred временное окно короткое. Без практического механизма продления временного окна эксплуатация была бы нестабильной. В-третьих, DirtyCred необходимо найти эффективный механизм, который позволит непривилегированному пользователю выделять привилегированные учетные данные активным образом, потому что отсутствие этой возможности сделает обмен объектами учетных данных неэффективным.
Чтобы решить описанные выше технические проблемы, мы сначала представляем серию схем разворота уязвимостей, которые позволяют нам преобразовать любую уязвимость в куче в возможность освобождать объекты учетных данных недопустимым образом. Во-вторых, мы используем три различные функции ядра — userfaultfd [38], FUSE [37] и блокировку файловой системы — для увеличения временного окна, необходимого для подкачки объектов, и, таким образом, стабилизации эксплуатации. И последнее, но не менее важное: мы используем различные механизмы ядра для порождения потоков с высокими привилегиями как из пользовательского пространства, так и из пространства ядра и, таким образом, активно выделяем привилегированные объекты. В этой работе мы оцениваем возможности использования DirtyCred, используя 24 реальные уязвимости ядра. Мы неожиданно обнаружили, что DirtyCred может демонстрировать повышение привилегий на 16 уязвимостях и побег из контейнера. Мы поделились нашим недавно предложенным методом эксплуатации с программой вознаграждений за уязвимости Google (kCTF VRP [20]) и получили их признание и вознаграждение в размере 20 000 долларов США.
С убедительной демонстрацией возможности эксплуатации и отсутствием эффективной защиты мы считаем, что DirtyCred вскоре может стать серьезной угрозой для Linux, если сообщество не предпримет немедленных действий для изучения и развертывания нового механизма защиты. В результате, следуя нашему новому подходу к эксплуатации, мы также предложили новый механизм защиты ядра Linux. Основная идея этой защиты заключается в размещении объектов с высоким и низким уровнем привилегий в непересекающихся областях памяти. В этой работе мы делаем это, используя область vmalloc для хранения объектов с высокими привилегиями и обычную область для объектов с низкими привилегиями. Мы реализовали эту защиту в качестве прототипа ядра Linux и оценили ее производительность с помощью стандартного бенчмарка. Мы показываем, что наша защита в первую очередь вводит незначительные накладные расходы. Для некоторых операций, связанных с файловыми операциями, он демонстрирует лишь умеренные потери производительности.
По сравнению с существующими методами эксплуатации ядра Drity-Cred обладает многими уникальными характеристиками. Во-первых, это общий подход к эксплуатации, поскольку он позволяет повышать привилегии для произвольных уязвимостей в куче. Во-вторых, это могло бы значительно разгрузить бремя миграции эксплойтов, потому что, следуя DirtyCred, можно было бы создать эксплойт, который можно перенести с одной версии ядра или архитектуры на другую без каких-либо модификаций. В-третьих, он может обходить многие мощные средства защиты ядра и использовать механизмы защиты (например, CFI [15], KASLR [14], SMEP/SMAP [7, 29], KPTI [8] и т. д.). Наконец, это может выйти за рамки повышения привилегий, что приведет к более серьезным проблемам безопасности, таким какпоулчения рута на Android и выход из контейнера.
Подводя итог, в этой статье сделан следующий вклад.
- Мы предлагаем новый общий метод эксплуатации — DirtyCred — который может обойти широко распространенные средства защиты ядра и зашиты от эксплойтов и, таким образом, выполнить эскалацию привилегий в системе Linux.
- Мы демонстрируем, что DirtyCred может демонстрировать высокую эксплойтность на многих реальных уязвимостях ядра Linux. Мы также показываем, что эксплойтные объекты, полезные для DirtyCred, разнообразны и многочисленны.
- Мы анализируем существующие ограничения защиты ядра и предлагаем новый механизм защиты. Мы реализовали эту защиту в качестве прототипа в ядре Linux, показав, что она приводит к незначительным и умеренным потерям производительности.
Остальная часть этой статьи организована следующим образом. Раздел 2 знакомит с предпосылками, необходимыми для этого исследования, и обсуждает модель угроз. Раздел 3 представляет общую идею DirtyCred и обобщает технические проблемы, с которыми сталкивается DirtyCred. В разделах 4, 5 и 6 представлены различные методы решения технических проблем. В разделе 7 оценивается эффективность предлагаемого подхода к эксплуатации реальных уязвимостей ядра Linux. Раздел 8 представляется новый защитный механизм и оценивается его производительность на стандартных тестах. Раздел 9 содержит обсуждение соответствующей работы, за которой следует обсуждение некоторых связанных вопросов и будущей работы в Разделе 10. Наконец, мы завершаем работу в Разделе 11.
ПРЕДПОСЫЛКИ И МОДЕЛЬ УГРОЗ
В этом разделе представлены некоторые технические сведения, необходимые для понимания нашего недавно предложенного метода эксплуатации. Кроме того, мы обсуждаем нашу модель угроз и предположения.
2.1 Учетные данные в ядре Linux
Как определено в [26], учетные данные относятся к некоторым свойствам ядра, которые содержат информацию о привилегиях. Благодаря этим свойствам ядро Linux может проверять права доступа пользователей. В ядре Linux учетные данные реализованы как объекты ядра, несущие информацию о привилегиях. Насколько нам известно, эти объекты включают «cred», «file» и «inode». В этой статье мы разработали наши методы эксплуатации, используя только объекты «cred» и «file». Мы исключили объект «inode», поскольку он может быть выделен только при создании нового файла в файловой системе, что не обеспечивает достаточной гибкости для манипулирования памятью (критическая операция при успешной эксплуатации программы). Далее мы предоставляем некоторые необходимые сведения об объектах «cred», «file» и «inode».
Каждая задача Linux содержит указатель, ссылающийся на объект «cred». Объект «cred» содержит поле UID, указывающее привилегию задачи. Например, GLOBAL_ROOT_UID указывает, что у задачи есть привилегия root. Когда задача пытается получить доступ к ресурсу (например, к файлу), ядро проверяет UID в объекте «cred» задачи, определяя, можно ли предоставить доступ. В дополнение к UID объект «cred» также содержит возможности. Возможность указывает детальную привилегию задачи. Например, CAP_NET_BIND_SERVICE указывает, что задача может привязать сокет к привилегированному порту интернет-домена. Для каждой задачи их учетные данные настраиваются. При изменении учетных данных задачи ядро следует принципу копирования и замены. Сначала он копирует учетные данные. Во-вторых, он изменяет копию. Наконец, он изменяет этот указатель Cred в задаче на только что измененную копию. В Linux каждая задача может изменять только свои учетные данные.
В ядре Linux каждый файл имеет UID и GID своего владельца, права доступа и возможности других пользователей. Для исполняемых файлов у них также есть флаги SUID/SGID, указывающие на специальное разрешение, которое позволяет другим пользователям работать с привилегиями владельца. В реализации ядра Linux каждый файл привязан к объекту «inode», связанному с учетными данными. Когда задача пытается открыть файл, ядро вызывает функцию inode_permision, проверяя индекс и соответствующее разрешение перед предоставлением доступа к файлу. После открытия файла ядро удаляет учетные данные из объекта «inode» и прикрепляет их к объекту «файл». Помимо сохранения учетных данных, объект «файл» также содержит разрешение на чтение/запись файла. Через объект «файл» ядро может индексировать объект cred и, таким образом, проверять привилегию. Кроме того, он может проверять права на чтение/запись и тем самым гарантировать, что задача не записывает данные в файл, открытый в режиме только для чтения.
2.2 Управление памятью кучи ядра
Ядро Linux разрабатывает распределители памяти для управления выделением небольшой памяти для повышения производительности и предотвращения фрагментации. Хотя в ядре Linux есть три разных распределителя памяти, они следуют одному и тому же высокоуровневому дизайну. Чтобы быть точным, все они используют кеши для поддержания одинакового размера памяти. Для каждого кеша ядро выделяет страницы памяти и делит память на несколько частей одинакового размера, и каждая часть представляет собой слот памяти, используемый для размещения объекта. Когда страница памяти для кеша исчерпана, ядро выделяет новые страницы для кеша. Если кеш больше не использует страницу памяти, т. е. все объекты на странице памяти освобождены, ядро соответствующим образом перерабатывает страницу памяти. В ядре Linux есть два основных типа кешей, которые кратко описаны ниже.
Универсальные кэши. Ядро Linux имеет разные общие кеши для выделения памяти разного размера. При выделении памяти из общих кешей ядро сначала округляет запрошенный размер в большую сторону и находит кеш, соответствующий запросу размера. Затем он выделяет слот памяти из соответствующего кэша. В ядре Linux, если в запросе на выделение не указано, из каких типов кешей он выделяется, выделение по умолчанию происходит в универсальных кешах. Для выделений, которые попадают в один и тот же общий кэш, они могут совместно использовать один и тот же адрес памяти, поскольку они могут поддерживаться на одной и той же странице памяти.
Специальные кэши. Ядро Linux создает выделенные кэши для повышения производительности и безопасности. Поскольку некоторые объекты часто используются в ядре, выделение кэшей для этих объектов может сократить время, затрачиваемое на их выделение, и тем самым повысить производительность системы. Выделения, попадающие в выделенные кэши, не используют одну и ту же страницу памяти с общими выделениями. В результате объекты, размещенные в универсальном кэше, не соседствуют с объектами в выделенных кэшах. Это можно рассматривать как изоляцию на уровне кеша, которая снижает угрозу переполнения от объектов в обычных кешах.
В нашей модели угроз мы предполагаем, что непривилегированный пользователь имеет локальный доступ к системе Linux, стремясь использовать уязвимость в ядре, приводящую к повреждению динамической памяти, и, таким образом, повысить свои привилегии. Кроме того, мы предполагаем, что в Linux включены все механизмы предотвращения эксплойтов и защиты ядра, доступные в вышестоящем ядре (версия 5.15). К таким механизмам относятся KASLR, SMAP, SMEP, CFI [7, 14, 15, 29], KPTI [8] и т. д. Благодаря этим защитам и защите адрес ядра рандомизируется, ядро не может напрямую обращаться к памяти пользовательского пространства во время выполнения, и его целостность потока управления гарантируется. И последнее, но не менее важное: мы не предполагаем, что существует аппаратный побочный канал, который мог бы облегчить эксплуатацию ядра.
ТЕХНИЧЕСКИЙ ОБЗОР И ПРОБЛЕМЫ
В этом разделе мы впервые представим идею DirtyCred на примере из реальной жизни. Затем мы анализируем и обсуждаем технические проблемы, которые необходимо решить DirtyCred.
3.1 Обзор
Мы берем реальную уязвимость ядра Linux (CVE-2021-4154 [9]) в качестве примера, демонстрирующего, как DirtyCred работает на высоком уровне. CVE-2021-4154 возникает из-за ошибки смешения типов, когда на файловый объект неправильно ссылается исходное поле объекта fs_context. В ядре Linux время жизни файлового объекта поддерживается с помощью механизма подсчета ссылок. Файловый объект будет автоматически освобожден, когда счетчик ссылок станет равным нулю, что означает, что файловый объект больше не используется. Однако, активировав уязвимость, ядро недопустимо освободит файловый объект, даже если файл все еще используется.
Как показано на рис. 1, DirtyCred сначала открывает доступный для записи файл «/tmp/x», который выделяет доступный для записи файловый объект в ядре. Активировав уязвимость, указатель источника будет ссылаться на файловый объект в соответствующем кэше. Затем DirtyCred пытается записать содержимое в открытый файл «/tmp/x». Перед фактической записью содержимого ядро Linux проверяет, есть ли у текущего файла разрешение на запись, доступна ли позиция для записи и т. д. После прохождения проверки DirtyCred удерживает это фактическое действие записи файла и переходит ко второму шагу. На этом шаге DirtyCred запускает свободный участок объекта fs_context для освобождения файлового объекта, в результате чего файловый объект остается освобожденным местом в памяти.
Затем, на третьем этапе, DirtyCred открывает доступный только для чтения файл «/etc/-passwd», который запускает ядро для выделения файлового объекта для «/etc/passwd». Как показано на рис. 1, вновь выделенный файловый объект занимает освободившееся место. После этой настройки DirtyCred выполнит действие приостановки записи, и ядро выполнит фактическую запись содержимого. Поскольку файловый объект был заменен, содержимое на удержании будет перенаправлено в файл только для чтения «/etc/passwd». Предполагая, что содержимое, записанное в «/etc/password», является «hacker:x:0:0:root:/:/bin/sh», злоумышленник может использовать эту схему для внедрения привилегированной учетной записи и, таким образом, выполнить повышение привилегий.
Приведенный выше пример — просто демонстрация того, как Dirty-Cred использует файловые объекты для эксплуатации. Как упоминалось в разделе 2, в дополнение к объектам «файл», объекты «cred» также считаются объектами учетных данных. Подобно обмену файлами, показанному выше, злоумышленник также может использовать аналогичную идею для обмена объектами cred и, таким образом, выполнить эскалацию привилегий. В связи с ограничением места, мы не даем подробностей. Читатели, интересующиеся эксплуатацией объектов cred, могут обратиться к нашей демонстрации эксплуатации, опубликованной в [2].
Из реального примера, описанного выше, мы можем заметить, что DirtyCred не изменяет поток управления, а использует природу управления памятью ядра для манипулирования объектами в памяти. В результате многие существующие средства защиты, которые предотвращают подделку потока управления, не влияют на использование DirtyCred. В то время как некоторые недавние исследовательские работы обеспечивают защиту ядра путем перепроектирования управления памятью (например, AUTOSLAB [34]), они также неэффективны в блокировании DirtyCred. Как мы обсудим в разделе 8, недавно предложенные методы управления памятью все еще имеют грубую степень детализации, недостаточную для того, чтобы помешать нам манипулировать памятью.
3.2 Технические проблемы
Хотя приведенный выше пример иллюстрирует, как DirtyCred выполняет эксплуатацию и, таким образом, выполняет повышение привилегий, все еще есть много технических деталей, которые необходимо уточнить, и множество технических проблем, которые необходимо решить.
- Как упоминалось выше, DirtyCred нужна недействительная возможность для освобождения объекта с низкими привилегиями (например, файлового объекта с разрешением на запись), а затем перераспределения объекта с высокими привилегиями (например, файлового объекта с доступом только для чтения). На практике уязвимость ядра не всегда может предоставить нам такую возможность. Например, уязвимость может обеспечивать возможность перезаписи только за пределами сети, а не недействительную свободную запись непосредственно против объекта учетных данных. Таким образом, DirtyCred нужны соответствующие подходы для переноса возможностей уязвимости на уязвимости с разными возможностями. Поэтому в разделе 4 мы описываем, как менять возможности для различных типов уязвимостей ядра.
- Как описано в приведенном выше примере, DirtyCred необходимо удерживать фактическую запись файла после завершения проверки разрешений и до замены файловых объектов. Тем не менее, держаться за фактическое письмо сложно. В ядре Linux проверка разрешений и фактическая запись контента происходят быстро друг за другом. Без практической схемы точного контроля за подкачкой файловых объектов эксплуатация неизбежно будет нестабильной. В разделе 5 мы представляем ряд эффективных механизмов, гарантирующих, что обмен файловыми объектами может произойти в желаемое временное окно.
- Как обсуждалось выше, одним из наиболее важных шагов в DirtyCred является использование учетных данных с высокими привилегиями вместо учетных данных с низкими привилегиями. Для этого DirtyCred выделяет объекты с высокими привилегиями, занимая освободившееся место в памяти. Однако пользователю с низким уровнем привилегий сложно выделить учетные данные с высоким уровнем привилегий. Хотя простое ожидание действий от привилегированных пользователей потенциально может решить проблему, такая пассивная стратегия сильно влияет на стабильность эксплуатации. Во-первых, DirtyCred понятия не имеет, когда нужное место памяти может быть освобождено, и поэтому продолжает свою последовательную эксплуатацию. Во-вторых, DirtyCred не имеет контроля над вновь выделенными объектами. Поэтому возможно, что объект, занимающий желаемый слот памяти, не имеет ожидаемого уровня привилегий. В разделе 6 мы вводим механизм пользовательского пространства и схему пространства ядра для решения этой проблемы.
ВОЗМОЖНОСТЬ РАЗВОРОТА УЯЗВИМОСТИ
Как показано в примере, изображенном на рис. 1, уязвимость ядра, занесенная в каталог как CVE-2021-4154, дает DirtyCred возможность освободить файловый объект недопустимым образом. Однако на практике уязвимость может не демонстрировать такую возможность. Например, возможность двойного освобождения (DF) или использования после освобождения (UAF) может не быть напрямую связана с объектом учетных данных. Некоторые уязвимости, такие как внешний доступ (OOB), не имеют недопустимой возможности бесплатного доступа. Для этого DirtyCred необходимо изменить возможности уязвимости. Далее мы опишем, как мы разрабатываем DirtyCred для разворота.
4.1 Разворот OOB и UAF запись
Учитывая уязвимость OOB или уязвимость UAF с возможностью перезаписи данных в кэше, DirtyCred сначала идентифицирует объект (т. е. объект-жертву), который использует тот же кэш, и заключает указатель, ссылающийся на объект учетных данных. Затем он использует методы манипулирования кучей [6, 49] для размещения объекта в области памяти, где происходит перезапись. Как показано на рис. 2 (а), для разворота уязвимости OOB объект-жертва находится сразу после уязвимого объекта. Используя возможность перезаписи, DirtyCred дополнительно модифицирует указатель, заключенный в объект. В частности, DirtyCred использует возможность перезаписи для записи нуля в последние два байта указателя, ссылающегося на объект учетных данных (см. рис. 2(b)).
Напомним, что кэш организован на смежных страницах. В ядре Linux адрес страницы памяти всегда имеет формат, в котором последний байт равен нулю. При размещении объектов в новом кэше объект начинается с начала страницы памяти. В результате описанная выше перезапись нулевого байта заставит указатель ссылаться на начало страницы памяти. Например, как показано на рисунке 2(b), после обнуления двух последних байтов указателя, ссылающегося на объект учетных данных, указатель ссылается на начало страницы памяти, в которой находится другой объект учетных данных.
Как показано на рис. 2(б), после манипуляции с указателем Dirty-Cred получает дополнительную ссылку на первый объект страницы памяти. Мы утверждаем, что эта дополнительная ссылка на объект означает успех в повороте. Причина в том, что ядро могло нормально освободить объект, оставив указатель в объекте-жертве в виде висящего указателя. Затем, следуя аналогичной процедуре, описанной в разделе 3, DirtyCred может выполнить heap spray, занять освободившееся место объектом учетных данных с высокими привилегиями и, таким образом, выполнить повышение привилегий.
4.2 Разворот DF
В ядре Linux общие кеши (например, kmalloc-96) и выделенные кеши (например, cred_jar) изолированы. Объекты, заключенные в эти кэши, не имеют перекрытия. Однако в ядре Linux есть механизм рециркуляции. При уничтожении кеша памяти он повторно использует соответствующие неиспользуемые страницы памяти, а затем назначает повторно используемые страницы кешам, которым требуется больше места. Эта характеристика позволяет манипулировать памятью между кэшами, предоставляя DirtyCred возможность поворота для устранения уязвимостей с двойным освобождением.
На рис. 3 показана процедура преобразования DirtyCred возможности двойного освобождения в возможность, необходимую для обмена привилегированными объектами. Во-первых, DirtyCred выделяет множество объектов в кеше, где возникает уязвимость. Среди этих вновь выделенных объектов есть уязвимый объект. Используя два разных указателя, DirtyCred может дважды освободить уязвимый объект недопустимым образом. Поскольку количество выделений велико, DirtyCred может гарантировать, что кэш будет заполнен новыми выделенными объектами после массивного выделения объектов (см. рис. 3 (a)).
После массового выделения DirtyCred использует первый указатель для освобождения уязвимого объекта недопустимым образом, оставляя второй указатель позади (см. рис. 3(b)). Затем он перераспределяет уязвимый объект, занимая освободившееся место в памяти. Как показано на рисунке 3(c), после перераспределения остаются три указателя, ссылающиеся на уязвимый объект. Один из них — это указатель, оставленный первым уязвимым объектом. Два других связаны с возможностью двойного освобождения вновь выделенного уязвимого объекта.
Используя один из трех указателей, ссылающихся на уязвимый объект, DirtyCred дополнительно освобождает только что выделенный уязвимый объект, оставляя освобожденную область памяти, на которую ссылаются два оборванных указателя (см. рис. 3 (d)). Как упоминалось выше, ядро Linux перезапускает страницу памяти и назначает ее другому кешу, если в кеше нет выделенных объектов. Таким образом, после освобождения уязвимых
объект, DirtyCred дополнительно освобождает другие объекты в кэше и, таким образом, соответственно освобождает кэш (см. рисунок 3 (e)).
На странице переработанной памяти ядро создает новый кэш, в котором хранятся объекты учетных данных. Новый кеш делит память страниц на слоты. Как показано на рис. 3(f), если размер уязвимого объекта отличается от размера объекта учетных данных, адрес объекта учетных данных не будет совпадать с адресом уязвимого объекта, в результате чего два оставшихся указателя ссылаются середина объекта учетных данных. В этом состоянии памяти DirtyCred не может следовать процедуре эксплуатации, описанной в разделе 3, поскольку для успешной эксплуатации требуется возможность освободить объект учетных данных.
Чтобы решить эту проблему, DirtyCred сначала использует один из оставшихся указателей для освобождения объекта учетных данных в середине. Как показано на рис. 3(g), после освобождения памяти ядро создает свободное место в памяти. Это свободное место имеет размер как объект учетных данных. Поэтому, когда DirtyCred выделяет новый объект учетных данных, ядро заполняет освободившееся место новым объектом учетных данных. Как видно на рис. 3(h), после того, как освобожденное место занято, последний оставшийся указатель ссылается на вновь выделенный объект учетных данных. Это подразумевает успех разворота возможностей. Причина в том, что DirtyCred может использовать оставшийся указатель для освобождения объекта учетных данных недопустимым образом, а затем выполнить замену объекта для повышения привилегий.
5 ПРОДЛЕНИЕ ВРЕМЕННОГО ОКНА
Напомним, что ядру Linux необходимо проверять права доступа к файлу перед выполнением операции записи в файл. DirtyCred необходимо выполнить обмен файловыми объектами между проверкой разрешений и фактической записью файла. Однако это окно слишком короткое для успешной эксплуатации, поскольку подкачка должна активировать уязвимость и выполнить манипуляцию с расположением кучи, что может занять несколько секунд. Чтобы решить эту проблему, DirtyCred использует несколько методов для увеличения этого временного окна, чтобы гарантировать, что оно больше, чем время, затрачиваемое на процесс обмена. Здесь мы описываем эти методы и обсуждаем, как они могут облегчить эксплуатацию.
5.1 Использование Userfaultfd и FUSE
Userfaultfd [38] и FUSE [37] — две важные функции ядра Linux. Функция userfaultfd позволяет пользовательскому пространству обрабатывать ошибки страниц. Когда ошибка страницы инициируется в памяти, зарегистрированной в userfaultfd, зарегистрированный пользователем обработчик ошибки страницы получает уведомление для обработки ошибки страницы. В отличие от userfaultfd, FUSE представляет собой структуру файловой системы пользовательского пространства, позволяющую пользователям реализовать файловую систему пользовательского пространства. Пользователи могли зарегистрировать свой обработчик для реализованной файловой системы пользовательского пространства, чтобы указать, как отвечать на запросы операций с файлами. И userfaultfd, и FUSE могут быть использованы для приостановки выполнения ядра Linux на любое время, необходимое пользователю. Для userfaultfd злоумышленник может зарегистрировать обработчик ошибок страниц для страницы памяти. Когда ядро попытается получить доступ к этой памяти и вызовет отказ страницы, будет вызван зарегистрированный обработчик, позволяющий противнику приостановить выполнение ядра. Для FUSE злоумышленник может выделить память из файловой системы пользовательского пространства. Когда ядро обращается к этой памяти, оно вызывает предопределенный обработчик доступа к файлу и, таким образом, приостанавливает выполнение ядра.
В этой работе DirtyCred использует эти функции для приостановки выполнения ядра после завершения проверки прав доступа к файлу. Далее мы возьмем userfaultfd в качестве примера, чтобы описать, как DirtyCred выполняет паузу ядра и расширяет окно времени эксплуатации. Для FUSE процедура паузы ядра аналогична. Читатели могут обратиться к разработанному нами образцу эксплойта [2].
При записи файла DirtyCred вызывает syscallwritev, реализацию векторного ввода-вывода. В отличие от записи системного вызова, этот системный вызов использует структуру iovec для передачи данных из пространства пользователя в пространство ядра. Список 1 в строке 1~5 определяет структуру iovec. Как мы видим, он содержит адрес пользовательского пространства и поле размера, указывающее объем данных, которые будут переданы. В пространстве ядра Linux для копирования данных, заключенных в iovec, ядру необходимо сначала импортировать iovec в пространство ядра. Поэтому до версии ядра Linux версии 4.13, как показано в списке 1, реализация writev сначала проверяет файловый объект, гарантируя, что текущий файл находится в открытом состоянии и имеет разрешение на запись. После прохождения проверки он импортирует iovec из пользовательского пространства и записывает пользовательские данные в соответствующий файл. В этой реализации импорт ofiovec находится между проверкой разрешений и записью данных. DirtyCred может просто использовать вышеупомянутую функцию userfaultfd, чтобы приостановить выполнение ядра сразу после завершения проверки разрешений и, таким образом, выиграть достаточно времени для замены файлового объекта. Насколько нам известно, этот метод был впервые использован Янном Хорном в эксплойте для CVE-2016-4557 [25], но он больше не доступен после ядра версии 4.13.
5.2 Альтернативное использование Userfaultfd и FUSE
После версии ядра Linux версии 4.13 реализация ядра изменилась. Импорт iovec был перенесен перед проверкой разрешений (см. список 2). В этой новой реализации DirtyCred по-прежнему может использовать функцию userfaultfd для приостановки выполнения ядра на месте импорта iovec. Однако это больше не дает DirtyCred возможности увеличивать временной интервал между проверкой разрешений и фактической записью файла. Чтобы решить эту проблему, DirtyCred использует структуру файловой системы Linux.
В Linux структура файловой системы следует строгой иерархии, в которой высокоуровневый интерфейс является общим для операций записи файлов, тогда как низкоуровневый интерфейс различается в зависимости от файловой системы. При записи файла ядро сначала вызывает высокоуровневый интерфейс. Как показано в списке 3, generic_perform_write — это высокоуровневый интерфейс для операции записи в файл. Как мы видим, в строках 15-17 generic_perform_write вызывает операцию записи файловой системы и записывает данные в файл. Чтобы гарантировать производительность и совместимость, непосредственно перед операцией записи ядро вызывает отказ страницы для данных пользовательского пространства, заключенных в iovec. В результате, используя функцию userfaultfd в строке 10, DirtyCred может приостановить выполнение ядра до фактической записи файла и, таким образом, получить достаточное временное окно для замены привилегированных файловых объектов.
По сравнению с приостановкой выполнения ядра на месте импорта iovec, мы утверждаем, что использование структуры файловой системы является более сложной задачей для смягчения последствий. Во-первых, как описано в комментарии к коду Linux, удаление ошибки страницы в iovec потенциально может привести к взаимоблокировке (см. список 3). Некоторые файловые системы неизбежно столкнутся с проблемами, если страница не будет предварительно повреждена. Во-вторых, хотя перемещение ошибки страницы перед проверкой разрешений может потенциально решить проблему, эта прямая защитная реакция снижает производительность ядра и, что более важно, страдает от потенциального обхода. Например, DirtyCred может удалить страницу сразу после срабатывания ошибки первой страницы. Таким образом, ядро неизбежно снова вызывает отказ страницы и, таким образом, приостанавливает выполнение ядра сразу после проверки разрешений.
5.3 Использование блокировки в файловой системе
Чтобы не испортить содержимое файла, файловая система не позволяет двум процессам записывать файл одновременно. В Linux файловая система применяет эту практику с помощью механизма блокировки. Чтобы проиллюстрировать это, в списке 4 показан упрощенный фрагмент кода, выполняющий операцию записи в файловой системе ext4. Как мы видим, файловая система сначала пытается получить блокировку индекса в строке 6. Если индекс находится под управлением другого файла (т. е. другие удерживают блокировку), файловая система будет ждать, пока блокировка не будет снята. После получения блокировки файловая система вызывает generic_perform_write для записи данных в файл. Когда запись завершится, файловая система снимет блокировку и вернется из функции.
Приведенный выше механизм блокировки может гарантировать, что операция записи не пойдет не так, как надо. К сожалению, это оставляет DirtyCred возможность продлить временное окно и, таким образом, выполнить обмен объектами. Если быть точным, DirtyCred может порождать два процесса — процесс A и процесс B — для одновременной записи данных в один и тот же файл. Предположим, что процесс A удерживает блокировку, записывая огромное количество данных. Когда процесс A записывает файл, процесс B должен будет ждать в течение длительного периода, пока блокировка не будет снята в строке 10. Поскольку до вызова generic_perform_write процесс B уже завершил проверку прав доступа к файлу, время ожидания блокировки предоставляет DirtyCred достаточно большое временное окно для завершения замены файловых объектов, не беспокоясь о блоке проверки разрешений. По нашим наблюдениям, время удержания может достигать десятков секунд при записи файла размером 4 ГБ на жесткий диск. В течение этого временного окна активация уязвимости и выполнение манипуляций с памятью могут быть завершены без каких-либо проблем с нестабильностью при эксплуатации.
ВЫДЕЛЕНИЕ ПРИВИЛЕГИРОВАННОГО ОБЪЕКТА
Как упоминалось в разделе 3.2, DirtyCred не может пассивно ждать действий привилегированных пользователей и ожидать, что эти действия могут привести к тому, что привилегированный объект займет желаемое свободное место, и, таким образом, выполнить эскалацию привилегий. Следовательно, DirtyCred должен предпринять активные действия, чтобы инициировать выделение привилегированных объектов в пространстве ядра. В этом разделе обсуждается, как DirtyCred, работающий от имени пользователя с низким уровнем привилегий, выполняет выделение привилегированных объектов.
6.1 Выделение из пользовательского пространства
В ядре Linux объекты «cred» представляют уровень привилегий соответствующих задач ядра. Пользователь root имеет привилегированный объект cred, представляющий наивысшую привилегию. Следовательно, если DirtyCred может активно инициировать действия пользователя root, ядро может соответствующим образом выделить привилегированные объекты cred. В Linux, когда двоичный файл имеет разрешение SUID, он может выполняться так, как если бы он выполнялся владельцем, независимо от того, кто выполняет двоичный файл. Используя эту характеристику, пользователь с низким уровнем привилегий может создать процесс root, когда он/она выполняет двоичный файл, принадлежащий пользователю root, с набором разрешений SUID.
В прошлом злоумышленники сосредотачивались на использовании уязвимости в привилегированном двоичном файле и, таким образом, выполняли эскалацию привилегий. В этой работе DirtyCred не полагается на уязвимости, находящиеся в привилегированных двоичных файлах. Вместо этого он злоупотребляет вышеупомянутой функцией для порождения бинарных файлов с набором SUID, принадлежащих пользователям root, выделяя привилегированный объект Cred, чтобы занять свободное место в памяти. В Linux существует множество двоичных файлов, соответствующих этой функции, включая исполняемые файлы, такие как su, ping, sudo, mount, pkexec и т. д.
Как обсуждалось ранее, в дополнение к объектам cred, DirtyCred также может обмениваться файловыми объектами для повышения привилегий. В отличие от объектов cred, размещение файловых объектов относительно просто. Напомним, что DirtyCred заменяет объект файла, разрешенный для записи, объектом файла, доступным только для чтения, при замене файловых объектов. Чтобы выделить файловые объекты с разрешением только на чтение, DirtyCred может открывать несколько целевых файлов только с разрешением на чтение. Таким образом, ядро будет размещать множество соответствующих файловых объектов в соответствующей памяти ядра.
6.2 Выделение из пространства ядра
Описанный выше метод указывает способ выделения привилегированных объектов из пользовательского пространства. На самом деле, DirtyCred также может выполнять выделение привилегированных объектов из пространства ядра. Когда ядро Linux запускает новый поток ядра, оно дублирует свой текущий запущенный процесс. Вместе с дублированием процесса ядро соответствующим образом размещает скопированный объект cred в куче ядра. В ядре Linux большинство потоков ядра имеют привилегированный объект cred. В результате скопированный объект Cred также имеет высокие привилегии. Используя возможность порождать привилегированные потоки ядра, DirtyCred может активно выделять привилегированные объекты cred.
Насколько нам известно, существует два основных подхода к выделению объектов учетных данных с высоким уровнем привилегий. Во-первых, это взаимодействие с фрагментами кода ядра, заставляющее ядро создавать привилегированный поток внутри себя. Например, создание рабочих процессов для рабочей очереди ядра также может быть использовано для порождения потоков ядра. В ядре Linux рабочая очередь предназначена для обработки отложенных функций. Рабочая очередь поставляется с несколькими рабочими пулами. Каждый рабочий пул содержит рабочих. Рабочий процесс — это основная исполнительная единица, которая выполняет работу, зафиксированную в рабочей очереди. Количество рабочих процессов в каждом рабочем пуле не превышает количество ЦП. Изначально ядро создает только одного рабочего для каждого рабочего пула. Когда возникает потребность в большем количестве рабочих процессов или, другими словами, в очереди работ фиксируется больше работ, ядро динамически создает рабочих процессов. Каждый рабочий поток — это поток ядра. В результате, регулируя работы, зафиксированные в рабочей очереди ядра, можно было соответствующим образом управлять действиями порождения потоков ядра.
В дополнение к описанному выше методу, второй подход к созданию потоков ядра заключается в вызове помощника пользовательского режима. Помощник пользовательского режима — это механизм, который позволяет ядру создавать процесс пользовательского режима. Одним из самых простых применений помощника пользовательского режима является загрузка модулей ядра в пространство ядра. При загрузке модуля ядра ядро вызывает API пользовательского режима-помощника, который далее выполняет программу пользовательского пространства — modprobe в режиме с высоким уровнем привилегий и, таким образом, создает объекты учетных данных с высоким уровнем привилегий в ядре. Частью функциональности modprobe является поиск необходимых драйверов в каталогах стандартных установленных модулей. Во время поиска ядру необходимо продолжить выполнение. В результате, чтобы modprobe не блокировал выполнение ядра, при вызове API usermode-helper ядро также порождает новый поток ядра.
7 ОЦЕНКА
В этом разделе мы разрабатали два эксперимента для оценки возможности эксплуатации DirtyCred на реальных уязвимостях ядра.
7.1 План эксперимента и установка
Как упоминалось выше, DirtyCred использует эксплуатируемые объекты (т. е. те, которые заключают в себе объекты учетных данных) для выполнения манипуляций с памятью, особенно для таких уязвимостей, как внешний доступ и использование после освобождения. Эта манипуляция является одним из важнейших шагов DirtyCred для повышения привилегий. При манипулировании памятью DirtyCred размещает уязвимый объект в кэше, где находится уязвимость. Для разных уязвимостей они демонстрируют возможность повреждения памяти в разных кешах. Таким образом, успех DirtyCred во многом зависит от того, сможет ли он успешно идентифицировать уязвимые объекты, которые могут поместиться в соответствующий кэш. Имея это в виду, мы сначала идентифицируем уникальные объекты, которые можно использовать для каждого кеша.
Чтобы указать объекты, одна инстинктивная реакция состоит в том, чтобы вручную просмотреть код ядра Linux, точно определить эти объекты, которые можно использовать, и выяснить входные данные, которые могут вызвать соответствующее выделение. Однако объем кода ядра Linux велик и изощрен, что делает проверку кода непрактичной. Поэтому для решения этой проблемы мы вводим автоматизированный метод для отслеживания объектов, которые можно использовать, и соответствующие входные данные для запуска их выделения. В нашей оценке мы применяем автоматизированный метод к последнему стабильному ядру (то есть версии 5.16.15 на момент написания этой статьи). Мы рассматриваем объект как пригодный для использования только в том случае, если автоматизированный метод может найти объект, содержащий объект учетных данных, и может продемонстрировать входные данные для выделения этого объекта в куче ядра. Из-за недостатка места мы подробно описываем дизайн и реализацию нашего автоматизированного метода в Приложении А.
В дополнение к выявлению объектов ядра, которые можно использовать, наш эксперимент также исследует возможность использования DirtyCred против реальных уязвимостей. Напомним, что DirtyCred необходимо изменить возможность уязвимости, если уязвимость не предоставляет DirtyCred возможность напрямую менять объекты учетных данных. Как обсуждалось в разделе 4.1, при выполнении поворота уязвимостей DirtyCred может потребоваться перезаписать некоторые важные данные в объекте, который можно использовать. Для различных уязвимостей их способность к перезаписи может значительно различаться, что еще больше влияет на успех повышения привилегий. В результате мы оцениваем эффективность DirtyCred, используя его для эксплуатации многих реальных уязвимостей и изучая, насколько хорошо он может выполнять эксплуатацию против этих уязвимостей.
Мы предполагаем, что ядро Linux оснащено современными методами защиты от эксплойтов, доступными в ядре при выполнении эксплойта. В результате нам необходимо выбрать уязвимости, выявленные в ядре, разработанном в последние годы. В нашей оценке мы выбрали только CVE ядра Linux, о которых сообщалось после 2019 года. В нашем процессе выбора CVE мы отфильтровали те уязвимости, которые не повреждают данные в куче ядра. Кроме того, мы исключили те уязвимости, для которых мы не можем воспроизвести соответствующую панику ядра. И последнее, но не менее важное: мы также устранили те уязвимости, для срабатывания которых требуется установка определенного оборудования. Следуя этим критериям выбора CVE, мы получили набор данных с 24 уникальными CVE. В таблице 2 мы перечислили идентификаторы этих CVE и соответствующие типы уязвимостей. Как мы видим, выбранные нами тестовые примеры покрывают почти все типы уязвимостей в куче ядра.
7.2 Результат эксперимента
Эксплуатируемые объекты. В таблице 1 показаны уязвимые объекты, обнаруженные в каждом кэше ядра. Как мы видим, эксплойтные объекты охватывают почти все основные кэши, кроме kmalloc-8, который редко используется в ядре Linux. Для большинства кешей памяти существует более одного объекта, потенциально пригодного для использования для повышения привилегий Dirty-Cred. В каждом эксплойтном объекте смещение поля, ссылающегося на объект учетных данных, также присутствует в таблице 1. Как мы видим, смещения для разных эксплойтных объектов различаются. Это указывает на то, что у DirtyCred больше шансов найти подходящий объект, соответствующий возможностям уязвимости, и выполнить успешную эксплуатацию. Например, если уязвимость демонстрирует возможность перезаписи 8 байтов в соседний объект по смещению 8-го байта, то эксплойтный объект с критическими данными по 8-му байту значительно облегчит повышение привилегий DirtyCred.
Из таблицы 1 мы также обнаруживаем 5 объектов в 5 общих кэшах. Они заключают ссылку на объект учетных данных в начале объектов. Это означает, что даже если злоумышленники получают только очень ограниченную возможность повреждения памяти (например, перезапись двух нулевых байтов в начале объекта-жертвы), они все равно могут использовать идентифицированный объект для уязвимости для запуска атаки DirtyCred. Следует отметить, что в Таблице 1 также различаются уязвимые объекты, ссылающиеся на Cred и File, с использованием разных символов. Как мы обсудим в разделе 10, объект cred может обеспечить лучшую поддержку выхода из контейнера. Таким образом, адекватные эксплойтные объекты с привязкой к объектам cred указывают на более существенную поддержку при выходе из докера.
Эксплуатируемость. В таблице 2 показаны возможности использования DirtyCred для различных уязвимостей. Как мы видим, DirtyCred успешно демонстрирует обход защиты ядра и повышение привилегий на 16 из 24 уязвимостей, когда базовое ядро Linux включает все механизмы защиты от эксплойтов, описанные в разделе 2.3. Это наблюдение подразумевает, что DirtyCred можно использовать в качестве мощного общего метода эксплуатации для задач эксплуатации уязвимостей ядра. Из 16 успешно эксплуатируемых тестовых случаев 8 относятся к уязвимостям с выходом за границу или с использованием после освобождения, а остальные 8 — с двойным освобождением. DirtyCred преуспевает во всех тестовых случаях с двойным освобождением, поскольку возможность двойного освобождения всегда может быть направлена на недопустимое освобождение объекта учетных данных.
Случаи сбоя в основном связаны с выходом за границу и использованием после освобождения. Что касается OOB-уязвимостей, то в случаях сбоя продемонстрировано повреждение памяти в области виртуальной памяти. Чтобы использовать DirtyCred, нам нужно найти объекты ядра с учетными данными. Эти объекты обычно размещаются в выделенной kmalloc области памяти, а не в виртуальной памяти. В результате DirtyCred не может найти необходимые объекты для успешной эксплуатации. Мы помечаем эти случаи знаком † в таблице 2. Как мы обсудим в разделе 10, неудачное использование этих случаев не означает, что DirtyCred не может использовать уязвимости в виртуальной памяти. Возможности повреждения памяти в виртуальной памяти все еще могут быть преобразованы в возможности, полезные для DirtyCred, если есть подходящие объекты, которые можно использовать, или с использованием других методов поворота возможностей.
В случае сбоя UAF CVE-2022-24122 он не демонстрирует возможность перезаписи через завсиший указатель, а просто демонстрирует способность перезаписи. Как обсуждалось в разделе 4, DirtyCred полагается либо на недопустимую возможность записи, либо на недопустимую возможность свободного доступа. Возможность избыточного считывания CVE-2022-24122 ограничивает DirtyCred для выполнения успешного разворота , поэтому атака не удается. Для CVE-2019-2215 и CVE-2019-1566 они демонстрируют возможность перезаписи. Однако возможность перезаписи не возникает в критической области эксплуатируемых объектов. Без такой возможности DirtyCred не может манипулировать необходимыми полями в объектах ядра, чтобы освободить объект учетных данных, поэтому атака проваливается.
8 ЗАЩИТА ОТ DIRTYCRED
Учитывая возможность эксплуатации, продемонстрированную в разделе выше, мы утверждаем, что DirtyCred представляет собой серьезную угрозу для существующей системы Linux. Хотя технику злоупотребления механизмом блокировки можно защитить путем реинжиниринга файловой системы, по-прежнему недостаточно заблокировать DirtyCred, поскольку его можно запустить с другого пути — подкачки объекта cred. Следовательно, эффективным подходом является предотвращение обмена учетными данными с другим уровнем привилегий. С одной стороны, защита кучи пользовательского пространства не подходит для Dirty-Cred. Ядро хочет, чтобы выделение/освобождение/доступ к памяти было максимально быстрым. В противном случае это приведет к замедлению работы пользовательских программ и всей системы. Поэтому распределитель памяти в ядре гораздо проще, чем в пространстве пользователя (например, ptmalloc). Этот факт делает защиту кучи пользовательского пространства неприменимой к пространству ядра. С другой точки зрения, даже если в ядре Linux реализовано множество механизмов защиты (например, CFI, SMEP, SMAP, KASLR и т. д.), ни одна из существующих средств защиты ядра не эффективна для DirtyCred по следующим причинам.
Во-первых, DirtyCred не нарушает целостность потока управления, что делает бесполезными усилия по защите потока управления ядром. Во-вторых, DirtyCred не полагается на какой-то один компонент эксплуатации для эксплуатации. Как показано в разделе 7, ценные объекты для эксплуатации распределены почти по всем общим кэшам. Таким образом, защита от DirtyCred путем устранения объектов, которые можно использовать, практически невозможна. В-третьих, DirtyCred выполняет свою цель эксплуатации, помещая законный объект учетных данных в незаконную область памяти, но не вмешиваясь в содержимое объекта учетных данных. Эта практика эксплуатации снижает вероятность того, что существующие методы защиты целостности учетных данных (например, защита ядра в реальном времени Samsung Knox [43]) будут эффективными. И последнее, но не менее важное: DirtyCred выполняет повышение привилегий путем обмена местами между объектами учетных данных с высоким и низким уровнем привилегий. Этот метод эксплуатации не работает во многих схемах изоляции объектов ядра (например, AUTOSLAB [34] и xMP [44]), поскольку они разделяют критические объекты ядра в своих собственных областях памяти на основе типа объектов, а не их привилегий.
С этой целью мы утверждаем, что одним из эффективных решений защиты от DirtyCred будет изоляция объектов с высокими и низкими привилегиями, заставляя их не использовать одно и то же пространство памяти. Таким образом, DirtyCred больше не сможет перекрывать объекты с разными привилегиями для повышения привилегий. Для достижения вышеуказанной цели простой реакцией является создание двух разных кешей. Один используется для хранения объектов с высоким уровнем привилегий. Другой используется для хранения объектов с низким уровнем привилегий. Поскольку кэши естественным образом изолированы, такой дизайн может гарантировать, что объекты с разными привилегиями не будут перекрываться. Однако, как мы обсуждали в Разделе 4.2, после уничтожения кэша памяти вспомогательный распределитель Linux повторно использует базовую страницу памяти. Таким образом, DirtyCred по-прежнему может начать атаку, злоупотребляя этой функцией повторного использования страниц памяти.
Дизайн. Принимая во внимание приведенный выше анализ, мы предлагаем практическое решение защиты, которое создает кеш для объектов с высоким уровнем привилегий в области виртуальной памяти и оставляет объекты с низким уровнем привилегий в обычной области памяти (т. е. в области памяти с прямым отображением). Область виртуальной памяти относится к динамическому распределению практически непрерывной памяти внутри ядра. Он находится в области памяти, определенной от VMALLOC_START до VMALLOC_END. Поскольку он отделен от области памяти с прямым отображением, области, предназначенные для объектов с высоким и низким уровнем привилегий, никогда не перекрываются даже после уничтожения кэшей и повторного использования базовых страниц памяти.
Выполнение. В этой работе мы реализовали предложенную нами защиту от DirtyCred на ядре Linux версии 5.16.15. В нашей реализации мы вручную модифицировали способы размещения объектов cred и файловых объектов в ядре. Если выделение предназначено для привилегированных, мы выделяем их с помощью виртуальной памяти. Чтобы быть конкретным, при распределении объектов cred мы проверяем привилегию на основе UID объекта. Если UID соответствует GLOBAL_ROOT_UID, что означает выделение для привилегированных объектов cred, мы используем vmalloc в качестве распределителя для выделения виртуальной памяти для объекта. Для файловых объектов мы исследуем режим файла. Если файл открыт с правами на запись, мы соответствующим образом выделим файловый объект с помощью vmalloc. Наша реализация доступна по адресу [2].
Техническое обсуждение. Предлагаемая нами защита защищает ядро Linux, обеспечивая изоляцию памяти для объектов учетных данных. Как упоминалось выше, наша реализация определяет привилегию во время выделения объекта. Однако привилегию можно изменить, изменив UID во время выполнения (например, изменив объект учетных данных с низкими привилегиями на объект с высокими привилегиями с помощью системного вызова setuid). Когда это происходит, наша предложенная выше защита столкнется с проблемами безопасности, потому что мы выполняем изоляцию объекта только во время выделения. Чтобы решить эту проблему, мы вручную модифицируем способ изменения объектов учетных данных ядра в нашей реализации. В частности, если ядро изменит UID объекта учетных данных на GLOBAL_ROOT_UID, мы скопируем объект учетных данных с высокими привилегиями в область «vmalloc», а не изменим исходный. Однако мы думаем, что могут возникнуть некоторые проблемы, если будущая разработка ядра не будет следовать той же схеме. В результате мы оставляем поиск альтернативных решений частью нашей будущей работы.
Оценка эффективности. Чтобы оценить производительность нашего защитного механизма, мы провели два теста с ванильным ядром Linux и нашим ядром с поддержкой защиты на чистой машине (с 4-ядерным процессором Intel, 16 ГБ ОЗУ и 1000 ГБ HHD). Наши тесты включают микротест из LMbench v3.0 [41] и макротест из Phoronix Test Suite [42]. LM-bench оценивает задержку и пропускную способность системных вызовов и системного ввода-вывода, тогда как Phoronix Test Suite исследует производительность реальных приложений на двух ядрах Linux. Что касается LMbench, мы выполнили тест 10 раз, чтобы избежать случайности, и взяли среднее значение за наблюдаемую производительность. Для Phoronix Test Suite мы запустили тест в пакетном режиме, который запускает тест 50 раз и выводит средние значения.
В таблице 3 показаны результаты нашей оценки. Во-первых, мы можем заметить, что предлагаемый нами метод в основном приводит к незначительным потерям производительности, что указывает на то, что наша защита невелика. Во-вторых, мы можем наблюдать некоторое умеренное снижение производительности для тестовых случаев — «Создание файла 10k» и «Удаление файла 10k» — в LM-Bench. Как показано в Таблице 3, предлагаемая нами защита вносит накладные расходы более 4%. Причина такого снижения производительности заключается в том, что файловые объекты были выделены в область виртуальной памяти через vmalloc, а не в обычную область памяти через kmalloc. По сравнению с kmalloc, vmalloc работает относительно медленно, потому что виртуальная память должна переназначать буферное пространство на практически непрерывный диапазон, тогда как kmalloc никогда не переназначает.
Следует отметить, что удаление файла снижает производительность ниже, чем создание файла (4,25% против 7,17%). Причина различия заключается в том, что объект освобождения файла выполняется через RCU, который выполняется асинхронно с процессом удаления файла. Хотя умеренные накладные расходы могут вызвать беспокойство у некоторых производственных систем, они значительно улучшают защиту ядра от DirtyCred. В этой работе нашей основной целью является повышение осведомленности сообщества Linux, а не создание безопасного и эффективного решения для защиты. Мы оставляем исследование альтернативного оборонного решения в качестве наших будущих исследований. Наконец, следует также отметить, что в некоторых случаях продемонстрировано небольшое улучшение производительности после того, как мы внедрили защиту в ядро Linux. В основном это связано с шумом нашего эксперимента, хотя мы пытались минимизировать шум, насколько это было возможно, запустив тест несколько раз и отключив ускорение процессора на машине с «голым железом».
СВЯЗАННЫЕ РАБОТЫ
В этой работе представлен новый метод эксплуатации ядра и соответствующая защита для снижения угрозы. В результате работы, наиболее важные для нас, включают эксплуатацию ядра и смягчение последствий эксплуатации ядра. Далее мы суммируем работы по этим двум темам и обсуждаем, чем они отличаются от предлагаемых нами методов.
Эксплуатация ядра. Методы эксплуатации ядра развивались вместе с развитием защиты ядра. До введения предотвращения выполнения в режиме супервизора (SMEP) [29] технология — ret2usr [32] — использовала ядро Linux, переводя выполнение ядра в пространство пользователя. После широкого развертывания SMEP в Linux этот метод больше не работает, поскольку SMEP предотвращает выполнение ядра в пользовательском пространстве. Вслед за SMEP было предложено предотвратить доступ в режиме супервизора (SMAP) [7] для блокировки прямого доступа к пользовательскому пространству, что еще больше усиливает разделение доступа к ядру и пользовательскому пространству. Чтобы обойти защиту, обеспечиваемую SMEP/SMAP, исследователи предложили ряд новых методов эксплуатации. Например, Кемерлис и др. предложил метод ret2dir [31], который позволяет злоумышленнику зеркалировать данные пользовательского пространства в адресном пространстве ядра. Ву и др. представить KEPLER [48], который использует особый гаджет кода ядра для преобразования управления ПК в переполнение стека и, таким образом, обеспечивает длинную цепочку ROP.
Чтобы предотвратить ROP-атаки на ядро Linux, Linux вводит KASLR, который увеличивает сложность эксплуатации за счет рандомизации схемы адресов памяти ядра. Однако после принятия этой защиты ядра эксперты по безопасности предложили множество практических методов [5, 16, 23, 28] для обхода KASLR. Например, с помощью эластичных объектов в ядре. Чен и др. предложила ELOISE [5], которая могла раскрывать конфиденциальную информацию о ядре после перезаписи поля длины эластичных объектов. Грусс и др. предложил аппаратную атаку по побочному каналу, которая использует инструкции предварительной выборки для обхода KASLR. Недавно некоторые специалисты по безопасности даже предложили использовать уязвимости в процессорах для запуска атак Meltdown [39] и Spectre [33] и тем самым обойти защиту KASLR в Linux.
В дополнение к рандомизации адресного пространства памяти исследователи безопасности также предложили методы рандомизации расположения кучи памяти в ядре Linux [17, 47]. При включенной рандомизации кучи расположение кучи больше не является линейным, что усложняет злоумышленникам выполнение манипуляций с расположением кучи. Однако после успеха рандомизации расположения кучи Сюй и соавт. предложил метод коллизии памяти [49]. Этот метод использует механизм повторного использования памяти для эксплуатации уязвимостей ядра, связанных с использованием после освобождения, без помех из-за рандомизации кучи.
В отличие от описанных выше методов эксплуатации, направленных на обход некоторых конкретных средств защиты ядра и устранения эксплойтов, но не на конечную цель эксплуатации (например, повышение привилегий), наша работа сосредоточена на комплексной эксплуатации без головной боли, связанной с обходом широко развернутых защиты ядра. Таким образом, наш метод эксплуатации является более общим и последовательным. Как мы обсудим в Разделе 10, DirtyCred может даже облегчить возможность экранирования контейнеров и корневых устройств Android.
Защита ядра. В дополнение к средствам защиты ядра, представленным вместе с существующими методами эксплуатации, описанными выше, существует также множество других механизмов защиты ядра и предотвращения эксплойтов. Эти средства защиты предлагаются академическими кругами и промышленностью, и им уделяется значительное внимание со стороны сообщества безопасности. Здесь мы кратко представили некоторые недавно предложенные или в основном принятые на практике.
Чтобы предотвратить атаки по сторонним каналам на ядро Linux, Грусс и др. предложил механизм строгой изоляции ядра и пользовательского пространства — KAISER [22]. Этот механизм может гарантировать, что аппаратное обеспечение не хранит никакой информации об адресах ядра во время работы в пользовательском режиме. Чтобы улучшить KASLR, разработчики ядра Linux вводят функцию рандомизации адресного пространства гранулярного ядра (FGKASLR [1]). Рандомизируя макет до уровня функции кода, FGKASLR делает атаку повторного использования кода более сложной. Чтобы воспрепятствовать перехвату потока управления, исследователи также предложили различные защитные механизмы для обеспечения целостности потока управления в ядре Linux [11, 15, 18, 50]. Например, Ю и др. предложил реализовать встроенную в ядро защиту целостности потока управления с помощью аутентификации указателя ARM [50].
В дополнение к описанной выше защите потока управления ядром существует также ряд методов защиты, направленных на обеспечение защиты критически важных данных ядра [4, 13, 27, 40, 46]. Например, такими средствами защиты ядра являются AUTOSLAB [34] и xMP [44]. Как мы обсуждали в разделе 8, AUTOSLAB изолирует разные типы объектов в разные кэши памяти, что уменьшает количество объектов, полезных для манипулирования памятью кучи ядра. xMP использует методы виртуализации, чтобы изолировать конфиденциальные данные и, таким образом, предотвратить их подделку злоумышленниками.
С точки зрения философии защиты, наш защитный механизм отличается от работ, обеспечивающих целостность потока управления ядром. Это похоже на работы, которые изолируют критические данные ядра. Однако наша защита совершенно отличается от этих работ с технической точки зрения. Вместо того, чтобы изолировать объекты на основе типов и чувствительности, наша защита выполняет изоляцию памяти на основе привилегий объектов ядра. Таким образом, он более эффективен для защиты от угрозы DirtyCred.
10 ОБСУЖДЕНИЕ И БУДУЩАЯ РАБОТА
В этом разделе мы обсудим некоторые другие вопросы, которые мы еще не обсуждали, и представим наши будущие усилия.
Убегающий контейнер. Помимо повышения привилегий в Linux, DirtyCred может пассивно и активно способствовать побегу контейнера. Как упоминалось ранее, DirtyCred выполняет эксплойт путем замены либо файловых объектов, либо объектов cred. Используя файловые объекты для эксплуатации, DirtyCred может перезаписать файл с высоким уровнем привилегий. Однако ни один файл в контейнере не предоставляет права на переключение пространства имен. Чтобы решить эту проблему, в недавней работе [12] показано, что злоумышленник может пассивно ждать процесса runC и, таким образом, выполнять корневые команды на хосте, перезаписывая процесс. Руководствуясь этой идеей, DirtyCred может использовать механизм подкачки файловых объектов, чтобы перезаписать процесс runC и, таким образом, выполнить выход из контейнера.
В отличие от описанного выше метода, использование объектов cred для выхода из контейнера не требует пассивного ожидания. Для этого DirtyCred может сначала активировать уязвимость ядра Linux, поменять местами объекты cred и, таким образом, повысить привилегии злоумышленника до SYS_ADMIN. Имея в руках эту привилегию SYS_ADMIN ↩→, злоумышленник может затем следовать ранее предложенному методу выхода из Docker [3], который монтирует контрольную группу, а затем использует механизм notify_no_release для выполнения команды root в хост-системе. Чтобы продемонстрировать способность DirtyCred выйти из контейнера, мы предоставляем рабочий эксплойт в [2]. Рецензенты могли загрузить эксплойт и увидеть больше деталей побега из докера.
Рут Android. Помимо побега из контейнера, DirtyCred также может рутировать Android. Ядро Android разработано на основе общего ядра Linux. На практике ядро Android сложнее взломать по сравнению с общим ядром из-за более строгого контроля доступа и новых средств защиты [19]. DirtyCred может рутировать Android с помощью двух способов атак, описанных в этой статье. С одной стороны, DirtyCred может напрямую подменять учетные данные задачи, что дает злоумышленникам привилегированные учетные данные задачи, то есть привилегию root. С другой стороны, DirtyCred может сначала использовать свои возможности манипулирования файлами для перезаписи общей системной библиотеки, что позволяет повысить привилегии из ограниченной песочницы. Затем он мог перезаписывать модули ядра вредоносным кодом, выполнять произвольное чтение и запись и, в конечном итоге, отключать SELinux на Android. Мы продемонстрировали способность DirtyCred рутировать Android с помощью уязвимостей нулевого дня. К моменту написания этой статьи мы сообщили об уязвимостях в Google и получили их подтверждение.
Эксплуатация кросс-версии/архитектуры. При создании эксплойта под руководством DirtyCred можно было ожидать, что один и тот же код эксплойта может работать на разных версиях ядра или архитектурах без каких-либо изменений по следующим причинам. Во-первых, в отличие от других методов эксплуатации, которые требуют утечки базового адреса ядра для обхода KASLR, DirtyCred не нужно обрабатывать KASLR. В результате код эксплуатации не содержит никаких данных, специфичных для версий ядра или базовых архитектур. Во-вторых, многие предыдущие методы эксплуатации ядра (например, KEPLER [48]) в значительной степени полагаются на ROP для повышения привилегий. При переносе таких эксплойтов на другую архитектуру необходимо модифицировать цепочку ROP и, таким образом, сохранить ее работоспособность. DirtyCred не использует какие-либо данные об архитектуре, как обсуждалось в документе. Таким образом, после разработки фрагмента кода эксплойта для уязвимости этот эксплойт может работать на других уязвимых ядрах, независимо от их версий и базовых архитектур.
Другие способы разворота. В Разделе 4 мы предложили некоторые методы преобразования возможности повреждения памяти в возможность, полезную для DirtyCred. В нашей оценке мы обнаружили, что уязвимости, возникающие в виртуальной памяти, труднее использовать с помощью DirtyCred. Причина в том, что в виртуальной памяти меньше объектов, пригодных для эксплуатации, что ограничивает возможность поворота от исходного повреждения памяти к тем, которые полезны для DirtyCred. Мы утверждаем, что это не означает, что уязвимости в виртуальной памяти нельзя использовать с помощью DirtyCred. Например, CVE-2021-34866 предоставляет возможность выхода за границы, которая демонстрирует перезапись памяти, выделенной vmalloc. Используя наш поворотный подход, мы не можем повернуть эту возможность для освобождения объекта учетных данных. Однако в недавней статье [24] показан сложный метод, который может преобразовать эту возможность перезаписи на vmalloc в произвольное чтение и запись и, таким образом, включить возможность двойного освобождения. Как обсуждалось и показано в Разделе 4.2, используя возможность двойного освобождения, DirtyCred имеет высокие шансы выполнить повышение своих привилегий. В недавней работе [35] помимо возможности поворота уязвимости демонстрируется подход к изучению различных возможностей уязвимости. Мы утверждаем, что эти методы дополняют атаку DirtyCred, поскольку, как показано в Разделе 3.1, DirtyCred все еще может быть запущен без разворота. В этой работе мы оставляем изучение других методов поворота как часть наших будущих исследований.
Стабильность. На стабильность эксплуатации DirtyCred могут повлиять два критических фактора, как и все методы эксплуатации ядра. Во-первых, при повороте возможностей уязвимостей DirtyCred приходится манипулировать расположением памяти, занимая целевую область памяти. В этот момент стабильность эксплуатации может варьироваться, если системные действия влияют на манипуляции с расположением памяти. Во-вторых, при эксплуатации уязвимости ядра способ активации уязвимости также может сильно повлиять на стабильность эксплуатации. Для повышения стабильности эксплуатации в недавней работе [51] предлагается ряд методов стабилизации эксплуатации ядра. В этой работе наша цель — оценить возможности использования DirtyCred в реальных условиях. Мы пришли к выводу, что DirtyCred может успешно использовать уязвимость, если она демонстрирует пригодность для использования. В будущем мы изучим, как использовать существующие методы стабилизации эксплуатации, чтобы повысить показатель успешности эксплуатации DirtyCred.
TOCTOU. Как обсуждалось выше, DirtyCred меняет местами объекты учетных данных в критическом временном окне. Интуиция подсказывает, что существующие защитные механизмы TOC-TOU могут помешать предложенному нами методу эксплуатации. Согласно недавней исследовательской статье [45], защита TOCTOU может быть разделена на обнаружение исходного кода, обнаружение посмертно, интерпозицию системных вызовов, согласованность памяти внутри/между процессами, системные вызовы транзакций и файловую систему песочницы. Обнаружение исходного кода анализирует исходный код целевой программы. Очевидно, что такой метод защиты не может быть применен для защиты от нашей эксплуатации, потому что в DirtyCred нет идентифицированного шаблона исходного кода. Посмертное обнаружение выявляет уязвимости TOCTOU уже после фактического проведения атаки. Такого рода метод должен происходить до анализа, который не влияет на нашу эксплуатацию. Причина в том, что мы используем неожиданные свободные операции, которые нельзя было увидеть в процессе анализа. Интерпозиция системных вызовов отслеживает последовательность системных вызовов и, таким образом, определяет атаки. Наш метод эксплуатации не использует вредоносную последовательность системных вызовов. В результате интерпозиция системных вызовов также не блокировала бы нас. Согласованность памяти внутри/между процессами защищает общие переменные в нескольких потоках, записывая операции над переменными. Наша эксплуатация применяет неожиданные операции, которые не удалось записать. Транзакционные системные вызовы и файловая система песочницы нацелены на состояние гонки между чтением и записью файла. Наш метод не требует этого условия.
11 ЗАКЛЮЧЕНИЕ
Ядро Linux оснащено различными схемами защиты и предотвращения эксплуатации, что затрудняет успешное использование ядра. Чтобы обойти защиту ядра, злоумышленник должен использовать уязвимость с надежной возможностью отключить защиту. В этой работе мы показываем новый метод эксплуатации — DirtyCred. Он может обеспечить возможность эксплуатации и обхода защиты без жизненно важного требования к уязвимости ядра. Используя DirtyCred, мы демонстрируем, что злоумышленник может использовать почти произвольную уязвимость ядра на основе кучи для подкачки объектов учетных данных. Подмена учетных данных может ввести ядро Linux в заблуждение, полагая, что файл или задача с высоким уровнем привилегий находятся в режиме с низким уровнем привилегий. Таким образом, непривилегированный пользователь может повысить свои привилегии в злонамеренных целях. С этим открытием мы делаем вывод, что DirtyCred саботирует существующую архитектуру защиты Linux. Если наше сообщество безопасности не предпримет немедленных действий в ответ на этот новый метод эксплуатации, системы под управлением Linux вскоре окажутся в опасности. Их пользователи понесут значительные личные потери. Следуя этому выводу, в этой работе также был предложен механизм изоляции объектов привилегий в качестве защитного предложения. В этой работе мы реализовали этот защитный механизм в качестве прототипа ядра Linux и обнаружили, что он может защитить Linux с незначительными, а иногда и умеренными затратами. С этим новым открытием мы также приходим к выводу, что изоляция памяти на основе объектных привилегий может быть необходима для защиты от угрозы DirtyCred. Мы сообщили о части результатов нашего исследования поставщикам программного и аппаратного обеспечения, которые потенциально могут быть затронуты DirtyCred, и активно работаем с ними, чтобы помочь им понять и смягчить угрозу.
REFERENCES
[1] Kristen Carlson Accardi. 2020. Function Granular KASLR. (2020). https://lwn.
net/Articles/824307/
[2] Anonymous. 2022. DirtyCred Exploit. (2022). https://hackmd.io/
giRE2P2oQHektZzOG053IQ
[3] Alex Chapman. 2020. Privileged Container Escape Control Groups re-
lease_agent. (2020). https://ajxchapman.github.io/containers/2020/11/19/
privileged-container-escape.html
[4] Quan Chen, Ahmed M Azab, Guruprasad Ganesh, and Peng Ning. 2017.
Privwatcher: Non-bypassable monitoring and protection of process credentials
from memory corruption attacks. In Proceedings of the 2017 ACM on Asia Confer-
ence on Computer and Communications Security.
[5] Yueqi Chen, Zhenpeng Lin, and Xinyu Xing. 2020. A systematic study of elastic
objects in Kernel exploitation. In Proceedings of the 2020 ACM SIGSAC Conference
on Computer and Communications Security.
[6] Yueqi Chen and Xinyu Xing. 2019. Slake: Facilitating slab manipulation for
exploiting vulnerabilities in the linux kernel. In Proceedings of the 2019 ACM
SIGSAC Conference on Computer and Communications Security.
[7] Jonathan Corbet. 2012. Supervisor mode access prevention. (2012). https:
//lwn.net/Articles/517475/
[8] Jonathan Corbet. 2017. The current state of kernel page-table isolation. (2017).
The current state of kernel page-table isolation
At the end of October, the KAISER patch set was unveiled; this work separates the page tables u [...]
cgi-bin/cvename.cgi?name=CVE-2021-4154
[10] The MITRE Corporation. 2022. CVE-2022-0847. (2022). https://cve.mitre.org/
cgi-bin/cvename.cgi?name=CVE-2022-0847
[11] John Criswell, Nathan Dautenhahn, and Vikram Adve. 2014. KCoFI: Complete
control-偎ow integrity for commodity operating system kernels. In Proceedings of
the 2014 IEEE Symposium on Security and Privacy.
[12] Datadog. 2022. Using the Dirty Pipe Vulnerability to Break Out
from Containers. (2022). https://www.datadoghq.com/blog/engineering/
dirty-pipe-container-escape-poc/
[13] Lucas Davi, David Gens, Christopher Liebchen, and Ahmad-Reza Sadeghi. 2017.
PT-Rand: Practical Mitigation of Data-only Attacks against Page Tables.. In
Proceedings of the 2017 Network and Distributed Systems Security Symposium.
[14] Jake Edge. 2013. Kernel address space layout randomization. (2013). https:
//lwn.net/Articles/569635/
[15] Jake Edge. 2020. Control-偎ow integrity for the kernel. (2020). https://lwn.net/
Articles/569635/
[16] Dmitry Evtyushkin, Dmitry Ponomarev, and Nael Abu-Ghazaleh. 2016. Jump
over ASLR: Attacking branch predictors to bypass ASLR. In 2016 49th Annual
IEEE/ACM International Symposium on Microarchitecture.
[17] Thomas Garnier. 2016. mm: SLAB freelist randomization. (2016). https://lwn.
net/Articles/685047/
[18] Xinyang Ge, Nirupama Talele, Mathias Payer, and Trent Jaeger. 2016. Fine-
grained control-偎ow integrity for kernel software. In Proceedings of the 2016 IEEE
European Symposium on Security and Privacy.
[19] google. 2022. Kernel Control Flow Integrity. (2022). https://source.android.com/
devices/tech/debug/kc㜠
[20] Google. 2022. Roses are red, Violets are blue, Giving leets more
sweets. All of 2022! (2022). https://security.googleblog.com/2022/02/
roses-are-red-violets-are-blue-giving.html
[21] Google. 2022. syzkaller kernel fuzzer. (2022). https://github.com/google/syzkaller
[22] Daniel Gruss, Moritz Lipp, Michael Schwarz, Richard Fellner, Clйmentine Mau-
rice, and Stefan Mangard. 2017. Kaslr is dead: long live kaslr. In International
Symposium on Engineering Secure Software and Systems. 161–176.
[23] Daniel Gruss, Clйmentine Maurice, Anders Fogh, Moritz Lipp, and Stefan Man-
gard. 2016. Prefetch side-channel attacks: Bypassing SMAP and kernel ASLR. In
Proceedings of the 2016 ACM SIGSAC conference on computer and communications
security.
[24] HexRabbit. 2021. CVE-2021-34866 Writeup. (2021). https://github.com/
HexRabbit/CVE-writeup/tree/master/CVE-2021-34866
[25] Jann Horn. 2022. Linux: UAF via double-fdput. (2022). https://bugs.chromium.
org/p/project-zero/issues/detail?id=808
[26] David Howells. 2022. CREDENTIALS IN LINUX. (2022). https://www.kernel.
org/doc/Documentation/security/credentials.txt
[27] Kaiming Huang, Yongzhe Huang, Mathias Payer, Zhiyun Qian, Jack Sampson,
Gang Tan, and Trent Jaeger. 2022. The Taming of the Stack: Isolating Stack Data
from Memory Errors. In Proceedings of the 2022 Network and Distributed Systems
Security Symposium.
[28] Ralf Hund, Carsten Willems, and Thorsten Holz. 2013. Practical timing side chan-
nel attacks against kernel space ASLR. In Proceedings of the 2013 IEEE Symposium
on Security and Privacy.
[29] Mateusz Jurczyk. 2011. SMEP: What is it, and how to beat
it on Windows. (2011). https://j00ru.vexillium.org/2011/06/
smep-what-is-it-and-how-to-beat-it-on-windows/
[30] Max Kellermann. 2022. The Dirty Pipe Vulnerability. (2022). https://dirtypipe.
cm4all.com/
[31] Vasileios P Kemerlis, Michalis Polychronakis, and Angelos D Keromytis. 2014.
ret2dir: Rethinking kernel isolation. In Proceedings of the 23rd USENIX Conference
on Security Symposium.
[32] Vasileios P Kemerlis, Georgios Portokalidis, and Angelos D Keromytis. 2012.
{kGuard}: Lightweight Kernel Protection against {Return-to-User} Attacks. In
Proceedings of the 21st USENIX Conference on Security Symposium.
[33] Paul Kocher, Jann Horn, Anders Fogh, Daniel Genkin, Daniel Gruss, Werner
Haas, Mike Hamburg, Moritz Lipp, Stefan Mangard, Thomas Prescher, et al. 2019.
Spectre attacks: Exploiting speculative execution. In Proceedings of the 2019 IEEE
Symposium on Security and Privacy.
[34] Zhenpeng Lin. 2021. How AUTOSLAB Changes the Memory Unsafety Game.
(2021). https://grsecurity.net/how_autoslab_changes_the_memory_unsafety_
game/
[35] Zhenpeng Lin, Yueqi Chen, Yuhang Wu, Chensheng Yu, Dongliang Mu, Xinyu
Xing, and Kang Li. 2022. GREBE: Unveiling Exploitation Potential for Linux
Kernel Bugs. In Proceedings of the 2022 IEEE Symposium on Security and Privacy.
[36] Linux. 2022. File management in the Linux kernel. (2022). https://www.kernel.
org/doc/Documentation/security/credentials.txt
[37] Linux. 2022. FUSE’s introduction in the Linux kernel user’s and administrator’s
guide. (2022). https://www.kernel.org/doc/html/latest/㜠lesystems/fuse.html
[38] Linux. 2022. Userfaultfd’s introduction in the Linux kernel user’s and adminis-
trator’s guide. (2022). https://www.kernel.org/doc/html/latest/admin-guide/mm/
userfaultfd.html
[39] Moritz Lipp, Michael Schwarz, Daniel Gruss, Thomas Prescher, Werner Haas,
Anders Fogh, Jann Horn, Stefan Mangard, Paul Kocher, Daniel Genkin, et al. 2018.
Meltdown: Reading kernel memory from user space. In Proceedings of the 27th
USENIX Conference on Security Symposium.
[40] Derrick McKee, Yianni Giannaris, Carolina Ortega Perez, Howard Shrobe, Mathias
Payer, Hamed Okhravi, and Nathan Burow. Preventing Kernel Hacks with HAKC.
In Proceedings 2022 Network and Distributed System Security Symposium.
[41] Larry McVoy and Carl Staelin. 2022. LMbench - Tools for Performance Analysis.
(2022). http://lmbench.sourceforge.net/
[42] Phoronix Media. 2022. Open-Source, Automated Benchmarking. (2022). https:
//www.phoronix-test-suite.com/
[43] Samsung Knox News. 2016. Real-time Kernel Protection (RKP). (2016). https:
//www.samsungknox.com/en/blog/real-time-kernel-protection-rkp
[44] Sergej Proskurin, Marius Momeu, Seyedhamed Ghavamnia, Vasileios P Kemerlis,
and Michalis Polychronakis. 2020. xmp: Selective memory protection for kernel
and user space. In Proceedings of the 2020 IEEE Symposium on Security and Privacy.
[45] Razvan Raducu, Ricardo J. Rodrнguez, and Pedro Бlvarez. 2022. Defense and
Attack Techniques Against File-Based TOCTOU Vulnerabilities: A Systematic
Review. IEEE Access 10 (2022), 21742–21758.
[46] Chengyu Song, Byoungyoung Lee, Kangjie Lu, William Harris, Taesoo Kim, and
Wenke Lee. 2016. Enforcing Kernel Security Invariants with Data Flow Integrity..
In Proceedings 2016 Network and Distributed System Security Symposium.
[47] Dan Williams. 2018. Randomize free memory. (2018). https://lwn.net/Articles/
767614/
[48] Wei Wu, Yueqi Chen, Xinyu Xing, and Wei Zou. 2019. {KEPLER}: Facilitating
control-偎ow hijacking primitive evaluation for Linux kernel vulnerabilities. In
Proceedings of the 28th USENIX Conference on Security Symposium.
[49] Wen Xu, Juanru Li, Junliang Shu, Wenbo Yang, Tianyi Xie, Yuanyuan Zhang,
and Dawu Gu. 2015. From collision to exploitation: Unleashing use-after-free
vulnerabilities in linux kernel. In Proceedings of the 22nd ACM SIGSAC Conference
on Computer and Communications Security.
[50] Sungbae Yoo, Jinbum Park, Seolheui Kim, Yeji Kim, and Taesoo Kim. 2021. In-
Kernel Control-Flow Integrity on Commodity OSes using ARM Pointer Authen-
tication. arXiv preprint arXiv:2112.07213 (2021).
[51] Kyle Zeng, Yueqi Chen, Haehyun Cho, Xinyu Xing, Adam Doupй, Yan Shoshi-
taishvili, and Ti搊any Bao. 2022. Playing for K(H)eaps: Understanding and Improv-
ing Linux Kernel Exploit Reliability. In Proceedings of the 31st USENIX Conference
on Security Symposium.
Переведено специально для xss.pro
Автор перевода: yashechka
Источник:
DirtyCred: Escalating Privilege in Linux Kernel
Zhenpeng Lin
zplin@u.northwestern.edu
Northwestern University
Yuhang Wu
yuhang.wu@northwestern.edu
Northwestern University
Xinyu Xing
xinyu.xing@northwestern.edu
Northwestern University