Что мешает этому коду получить адрес vDSO, а это легкодоступная информация, и даже прочитать vDSO и получить адреса и коды системных функций?
Мешает незнание адреса vDSO, так как это не легкодоступная информация. Не должно быть фиксированного адреса или регистра, по которому можно было бы узнать адрес vDSO.
Конечно. А можно и свой user mode полностью написать для Zircon.
Но и JIT'инг байт-кода в машинный до сих пор эксплуатируется. И реализация виртуальной машины тоже никогда не станет идеальной (в рамках отсутствия уязвимостей).
Можно собрать Linux в котором сискол будет операцией передачи управления на случайную шлюзовую страницу
vDSO это не какой-то rocket science, который не повторить в другой ОС, это просто PoC.
Но заложенный принцип в начале разработке ОС не потребует в будущем ломать бинарную совместимость с существующим кодом.
Что мешает этому коду получить адрес vDSO, а это легкодоступная информация, и даже прочитать vDSO и получить адреса и коды системных функций?
Мешает незнание адреса vDSO, так как это не легкодоступная информация. Не должно быть фиксированного адреса или регистра, по которому можно было бы узнать адрес vDSO.
Стандартные сисколы требуют только знания индекса системной функции.
Вызов функции из vDSO требует знания ее адреса, который специально рандомизируется в адресном пространстве.
Мы защищаемся от внедрённого кода, который по какой-то причине не атакует пользовательский процесс, ничего о нём не знает, но пытается при этом атаковать ядро, исполняясь из этого самого пользовательского процесса?
Да. Злоумышленник шлет вредоносный pdf, который обрабатывается уязвимым ридером:
выделяются блоки памяти в куче, куда копируется содержимое файла вместе с вредоносным машинным кодом (shell-кодом)
используя уязвимость, злоумышленнику удается передать управление на shell-код
Shell-код ничего не знает о процессе, в который он загружен, кроме того, что он сидит где-то в heap'е этого процесса. Адреса хипов тоже рандомизируются. До ASLR он просто вызывал функции системных библиотек по захардкоженным (известным заранее) адресам. Потом ввели ASLR, и атакующий (для исполнения полезных действий) стал в сам shell-код встраивать инструкции syscall'а (которым нужен только индекс функции, а не адрес в 64-х битном адресном пространстве).
NtReadFile:
mov eax,6
syscall
Нет, такой конечно может случиться, но это крайне редкие ситуации и все современные ОС успешно с этим борются.
С переменным успехом, стоимость эксплуатации уязвимостей растет. В Zircon следующий шаг: давайте не будем позволять произвольному коду вызывать syscall'ы.
Никто и не позиционирует этот механизм, как серебряная пуля против эксплоитов:
Это отличный инструмент уменьшения поверхности атаки.
Легитимный код нити знает, ему аргументом передан адрес vDSO (который расположен с памяти процесса по произвольному случайному адресу).
Произвольных внедренный shell-код не знает об адресном процесса ничего, если, например, в начале не эксплуатировалась еще одну уязвимость утечки адресов в этом же процессе.
Есть ощущение, что это можно сделать тупо скомпилировав vdso как «position independent».
Вероятнее всего так и сделано, раз vDSO не требует обработку reloc'ов
Всегда мучил вопрос, почему не используют этой фичи.
Внедрение новых механизмов безопасности всегда идет со скрипом (https://habr.com/company/pt/blog/424633/ например), получается сделать это в новой ОС иногда проще.
Современные ОС c ASLR не запрещают совершать системный вызов из произвольного кода: будь то ntdll, ROP-цепочка из произвольного кода или внедренный шелкод.
Та же работа с сетью теперь станет медленнее: сначала прыгаем в vdso, а уже оттуда в ядро, вместо прямого прыжка в ядро.
Накладные расходы, безусловно, будут присутствовать. Насколько они серьезно будут отражаться на реальной работе (учитывая, что ОС не позиционируется, как серверная) — нужно замерять.
Или они откроют vdso прямую работу с железом в юзерленде?
Допустим, удаленно пробили (RCE) браузер с "широким vDSO". Если не было второй уязвимости раскрытия памяти, то мы не знаем где в памяти расположены системные библиотеки (ни файл прочесть, ни через сокет отравить). Одним из существующих приемов — определить (или угадать) версию ОС заранее, а затем включить в shell-код системные вызовы напрямую (как кусок кода из ntdll.dll той же версии, а на Linux, вроде, номера системных вызовов достаточно стабильны). Здесь же придется сканировать память на предмет поиска ELF заголовка. Насколько это сложно, учитывая то, что нужно корректно обработать отсутствующие страницы виртуальной памяти (организовать SEH) — не знаю, надо изучать внутренности обработки исключений по памяти для Fuchsia.
https://habr.com/post/435482/#comment_19598754
Никто не обещал, что до vDSO каким-то мифическим образом можно будет проверить код.
Вероятно это мой промах и авторов оригинальной статьи, что мы не смогли донести эту простую мысль сразу
Конечно. А можно и свой user mode полностью написать для Zircon.
Но и JIT'инг байт-кода в машинный до сих пор эксплуатируется. И реализация виртуальной машины тоже никогда не станет идеальной (в рамках отсутствия уязвимостей).
Позволю себе заметить, что мы сейчас говорим про ОС Fuchsia у которой:
Который в свою очередь крутит приложения на Dart'е, который по сути является альтернативой JavaScript :)
И в Windows похожий подход практикуется:
Но статься не только (и не столько) об этом
А можно обрушить текущий процесс, если это не указатель, а просто число, похожее на адрес.
Да, можно и на 0 делить, а в регистре индекс передавать.
Статья не про какой-то экзотический способ передачи управления ядру ОС.
И концепция vDSO один из вариантов реализации.
Мы говорим об одной и той же инструкции процессора syscall/sysenter? Про https://www.codemachine.com/article_syscall.html?
vDSO это не какой-то rocket science, который не повторить в другой ОС, это просто PoC.
Но заложенный принцип в начале разработке ОС не потребует в будущем ломать бинарную совместимость с существующим кодом.
Да
Мешает незнание адреса vDSO, так как это не легкодоступная информация. Не должно быть фиксированного адреса или регистра, по которому можно было бы узнать адрес vDSO.
За эппловский XNU commpage не скажу (не знаю), но ключевые особенности vDSO:
Раздел "Поддержка со стороны ядра", пунтк 2: "Проверка адресов возврата для функций системных вызовов."
Оригинал: https://fuchsia.googlesource.com/zircon/+/master/docs/vdso.md#Enforcement
Подробнее тут: https://habr.com/post/435482/#comment_19598458
Стандартные сисколы требуют только знания индекса системной функции.
Вызов функции из vDSO требует знания ее адреса, который специально рандомизируется в адресном пространстве.
Тут постарался раскрыть мысль: https://habr.com/post/435482/#comment_19598458
Да. Злоумышленник шлет вредоносный pdf, который обрабатывается уязвимым ридером:
Shell-код ничего не знает о процессе, в который он загружен, кроме того, что он сидит где-то в heap'е этого процесса. Адреса хипов тоже рандомизируются. До ASLR он просто вызывал функции системных библиотек по захардкоженным (известным заранее) адресам. Потом ввели ASLR, и атакующий (для исполнения полезных действий) стал в сам shell-код встраивать инструкции syscall'а (которым нужен только индекс функции, а не адрес в 64-х битном адресном пространстве).
NtReadFile:
С переменным успехом, стоимость эксплуатации уязвимостей растет. В Zircon следующий шаг: давайте не будем позволять произвольному коду вызывать syscall'ы.
Никто и не позиционирует этот механизм, как серебряная пуля против эксплоитов:
Легитимный код нити знает, ему аргументом передан адрес vDSO (который расположен с памяти процесса по произвольному случайному адресу).
Произвольных внедренный shell-код не знает об адресном процесса ничего, если, например, в начале не эксплуатировалась еще одну уязвимость утечки адресов в этом же процессе.
Как прочитать то, адрес чего мы не знаем?
Вероятнее всего так и сделано, раз vDSO не требует обработку reloc'ов
Внедрение новых механизмов безопасности всегда идет со скрипом (https://habr.com/company/pt/blog/424633/ например), получается сделать это в новой ОС иногда проще.
Современные ОС c ASLR не запрещают совершать системный вызов из произвольного кода: будь то ntdll, ROP-цепочка из произвольного кода или внедренный шелкод.
"Бесплатные" механизмы безопасности в наше время большая редкость))
Если известен адрес vDSO (или смещений внутри), то проше вызывать публичное ABI. Ставка на рандомизацию адреса загрузки в каждом процессе.
Накладные расходы, безусловно, будут присутствовать. Насколько они серьезно будут отражаться на реальной работе (учитывая, что ОС не позиционируется, как серверная) — нужно замерять.
Сомнительно
Допустим, удаленно пробили (RCE) браузер с "широким vDSO". Если не было второй уязвимости раскрытия памяти, то мы не знаем где в памяти расположены системные библиотеки (ни файл прочесть, ни через сокет отравить). Одним из существующих приемов — определить (или угадать) версию ОС заранее, а затем включить в shell-код системные вызовы напрямую (как кусок кода из ntdll.dll той же версии, а на Linux, вроде, номера системных вызовов достаточно стабильны). Здесь же придется сканировать память на предмет поиска ELF заголовка. Насколько это сложно, учитывая то, что нужно корректно обработать отсутствующие страницы виртуальной памяти (организовать SEH) — не знаю, надо изучать внутренности обработки исключений по памяти для Fuchsia.