Невозможно отучить людей изучать самые ненужные предметы.
Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3
Надо знать обо всем понемножку, но все о немногом.
Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы
Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)
Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода
Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5
Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости
Справочник от А до Я
HTML, CSS, JavaScript
Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы
| Помогли мы вам |
Летом я выступил с докладом по этой теме на конференции ZeroNights 2021.
Слайды доклада в PDF
В предыдущей статье я описал прототип эксплоита для локального повышения привилегий на Fedora для платформы x86_64. Я рассказал, как состояние гонки в реализации виртуальных сокетов ядра Linux может привести к повреждению четырех байтов ядерной памяти. Я показал, как атакующий может шаг за шагом превратить эту ошибку в произвольное чтение‑запись памяти ядра и повысить свои привилегии в системе. Но некоторые ограничения этого способа повысить привилегии мешали мне экспериментировать в системе под защитой LKRG. Я решил продолжить исследование и выяснить, можно ли их устранить.
Мой прототип эксплоита выполнял произвольную запись с помощью перехвата потока управления при вызове деструктора destructor_arg в атакованном ядерном объекте sk_buff.
Этот деструктор имеет следующий прототип:
void (*callback)(struct ubuf_info *, bool zerocopy_success);Когда ядро вызывает его в функции skb_zcopy_clear(), регистр RDI содержит первый аргумент функции. Это адрес самой структуры ubuf_info. А регистр RSI хранит единицу в качестве второго аргумента функции.
Содержимое этой структуры ubuf_info контролируется эксплоитом. Однако первые восемь байтов в ней должны быть заняты адресом функции‑деструктора, как видно на схеме. В этом и есть основное ограничение. Из‑за него ROP-гаджет для переключения ядерного стека на контролируемую область памяти (stack pivoting) должен выглядеть примерно так:
mov rsp, qword ptr [rdi + 8] ; retК сожалению, ничего похожего в ядре Fedora vmlinuz-5. обнаружить не удалось. Но зато с помощью ROPgadget я нашел такой гаджет, который удовлетворяет этим ограничениям и выполняет запись ядерной памяти вообще без переключения ядерного стека:
mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rdx + rcx*8], rsi ; retКак сказано выше, RDI — это адрес ядерной памяти, содержимое которой контролирует атакующий. В регистре RSI содержится единица, а в RCX — ноль. То есть этот гаджет записывает семь нулевых байтов и один байт с единицей по адресу, который задает атакующий. Как выполнить повышение привилегий процесса с помощью этого ROP-гаджета? Мой прототип эксплоита записывает ноль в поля uid, gid, effective и effective структуры cred.
Мне удалось придумать хоть и странный, но вполне рабочий эксплоит‑примитив. При этом я не был полностью удовлетворен этим решением, потому что оно не давало возможности полноценного ROP. Кроме того, приходилось выполнять перехват потока управления дважды, чтобы перезаписать все необходимые поля в struct . Это делало прототип эксплоита менее надежным. Поэтому я решил немного отдохнуть и продолжить исследование.
Первым делом я решил еще раз посмотреть на состояние регистров процессора в момент перехвата потока управления. Я поставил точку останова в функции skb_zcopy_clear(), которая вызывает обработчик callback из destructor_arg:
$ gdb vmlinuxgdb-peda$ target remote :1234gdb-peda$ break ./include/linux/skbuff.h:1481
Вот что отладчик показывает прямо перед перехватом потока управления.
Какие ядерные адреса хранятся в регистрах процессора? RDI и R8 содержат адрес ubuf_info. Разыменование этого указателя дает указатель на функцию callback, который загружен в регистр RAX. В регистре R9 содержится некоторый указатель на память в ядерном стеке (его значение близко к значению RSP). В регистрах R12 и R14 находятся какие‑то адреса памяти в ядерной куче, и мне не удалось выяснить, на какие объекты они ссылаются.
А вот регистр RBP, как оказалось, содержит адрес skb_shared_info. Это адрес моего объекта sk_buff плюс отступ SKB_SHINFO_OFFSET, который равен 3776 или 0xec0 (больше деталей в предыдущей статье). Этот адрес дал мне надежду на успех, потому что он указывает на память, содержимое которой находится под контролем эксплоита. Я начал искать ROP/JOP-гаджеты, использующие RBP.
Я стал просматривать все доступные гаджеты с участием RBP и нашел множество JOP-гаджетов, похожих на этот:
0xffffffff81711d33 : xchg eax, esp ; jmp qword ptr [rbp + 0x48]Адрес RBP также указывает на ядерную память под контролем атакующего. Я понял, что могу выполнить stack pivoting с помощью цепочки таких JOP-гаджетов, после чего выполнить полноценную ROP-цепочку. Отлично!
Для быстрого эксперимента я взял этот гаджет:
xchg eax, esp ; jmp qword ptr [rbp + 0x48]Он переключает ядерный стек на память в пользовательском пространстве. Сначала я удостоверился, что гаджет действительно находится в коде ядра:
$ gdb vmlinux
gdb-peda$ disassemble 0xffffffff81711d33
Dump of assembler code for function acpi_idle_lpi_enter:
0xffffffff81711d30 <+0>: call
0xffffffff810611c0 <fentry
0xffffffff81711d35 <+5>: mov
rcx,QWORD PTR gs:[rip+0x7e915f4b]
0xffffffff81711d3d <+13>:
test
rcx,rcx
0xffffffff81711d40 <+16>:
je
0xffffffff81711d5e Андрея Коновалова, известного исследователя безопасности Linux, не сталкивался ли он с таким эффектом. Андрей обратил внимание, что байты кода, которые распечатало ядро, отличались от вывода утилиты objdump для исполняемого файла ядра.
Это был первый случай в моей практике с ядром Linux, когда дамп кода в ядерном журнале оказался полезен. Я подключился отладчиком к работающему ядру и обнаружил, что код функции acpi_idle_lpi_enter( действительно изменился:
$ gdb vmlinux
gdb-peda$ target remote :1234
gdb-peda$ disassemble 0xffffffff81711d33
Dump of assembler code for function acpi_idle_lpi_enter:
0xffffffff81711d30 <+0>: nop
DWORD PTR [rax+rax*1+0x0]
0xffffffff81711d35 <+5>: mov
rcx,QWORD PTR gs:[rip+0x7e915f4b]
0xffffffff81711d3d <+13>:
test
rcx,rcx
0xffffffff81711d40 <+16>:
je
0xffffffff81711d5e CONFIG_DYNAMIC_FTRACE. Он также испортил множество других JOP-гаджетов, на которые я рассчитывал! Чтобы не столкнуться с этим снова, я решил попробовать искать нужные ROP/JOP-гаджеты в памяти ядра живой виртуальной машины.
Сначала я опробовал команду ropsearch из инструмента gdb-peda, но у нее оказалась слишком ограниченная функциональность. Тогда я зашел с другой стороны и сделал снимок всей области памяти с ядерным кодом с помощью команды gdb-peda . В первую очередь нужно было определить расположение ядерного кода в памяти:
[
ffffffff81000000 T _text[
ffffffff81e026d7 T _etext
Затем я сделал снимок памяти между адресами _text и _etext:
gdb-peda$ dumpmem kerndump 0xffffffff81000000 0xffffffff81e03000
Dumped 14692352 bytes to 'kerndump'
После этого я применил к полученному файлу утилиту ROPgadget. Она может искать ROP/JOP-гаджеты в сыром снимке памяти, если задать дополнительные опции (спасибо за подсказку моему другу Максиму Горячему, известному исследователю безопасности железа):
# ./
Теперь я был готов составить JOP/ROP-цепочку.
|
|
|

