
Описание версии Sleirsgoevy реализации эксплоита CVE-2018-4386 от Fire30 под названием Bad_Hoist
[!Note] Справочная информация о PS4:
Консоль PlayStation 4 оснащена пользовательским AMD x86-64 CPU (8 ядер), ее ОС Orbis основана на FreeBSD (v9.0) с частями из NetBSD. Она также включает широкий спектр дополнительного открытого ПО, такого как Mono VM и WebKit.
Интернет-браузер, используемый PS4, на самом деле построен на проекте WebKit с открытым исходным кодом. Это движок рендеринга с открытым исходным кодом, который отображает веб-страницы в браузерах для iOS, Wii U, 3DS, PS Vita и PS4.
Интернет-браузер PS4 на самом деле состоит из 2 отдельных процессов. Тот, который мы перехватываем для выполнения кода, это основной процесс WebKit (который обрабатывает парсинг HTML и CSS, декодирование изображений и выполнение JavaScript, например). Другой обрабатывает всё остальное: отображение графики, получение ввода от контроллера, управление историей и закладками и т.д.
Браузер WebKit на PS4 использует несколько аллокаторов кучи, каждый из которых обслуживает разные компоненты. Вот они:
Суть CVE-2018-4386 — логическая ошибка в движке JavaScriptCore (JSC) WebKit (v605.1.15), версии, используемой в прошивке PS4 6.XX. Ошибка находится в функции BytecodeGenerator::hoistSloppyModeFunctionIfNecessary и связана с неправильной обработкой поднятия переменных (hoisting) в нестрогом режиме JavaScript, особенно внутри циклов for-in.
Уязвимый компонент (ForInContext):
Основная цель — ForInContext. Это внутренняя структура, используемая JavaScriptCore для управления состоянием цикла for-in, отслеживающая текущую переменную итерации и набор перечисляемых свойств.
Когда объявление функции поднимается внутри цикла for-in, движок должен аннулировать связанный объект ForInContext, если переменная итерации перезаписывается. Однако из-за ошибки этого не происходит. Это позволяет заменить переменную итерации на произвольный объект. Несмотря на это, движок продолжает рассматривать переменную как строковое имя свойства.
Когда позже вызывается обработчик байт-кода op_get_direct_pname, он использует переменную итерации напрямую как строковый объект без проверки типа.
Передавая поддельный объект вместо строки, что приводит к путанице типов (type confusion), мы можем использовать это для достижения повреждения памяти и даже полезных примитивов эксплуатации, таких как addrof, fakeobj и произвольное чтение/запись.
Идентификатор структуры: Каждый объект в JavaScriptCore, включая внутренние представления, такие как WTF::StringImpl, имеет идентификатор структуры (или тег типа), который сообщает движку, что это за объект и как интерпретировать его поля.
Путаница типов: Наш эксплойт использует ошибку CVE-2018-4386, чтобы объект JavaScript интерпретировался как StringImpl. Это цель функции create_impl(), которая возвращает объект WTF::StringImpl с путаницей типов, который затем можно передать в функцию trigger() как тот произвольный объект, о котором мы говорили ранее в части механизм уязвимости этого описания.
Однако для этого макет памяти и идентификатор структуры должны быть «достаточно близки» к тому, что движок ожидает от реального строкового объекта.
JSString::toIdentifier() внутри?В движке JavaScriptCore WebKit интернет-браузера PS4 есть метод с именем JSString::toIdentifier(). Этот метод преобразует строковый объект JavaScript (JSString) во внутреннее представление Identifier.
Этот Identifier используется по всему движку для эффективного сравнения, хранения и поиска имен свойств, имен переменных и других строк, которые должны быстро и часто ссылаться движком JavaScript.
Он проверяет, что объект является допустимой строкой и что его идентификатор структуры соответствует тому, что движок ожидает от строкового объекта. Если строка является rope (конкатенацией строк), он может сплющить ее перед преобразованием. Затем он либо извлекает существующий Identifier для строки, либо создает новый, если его нет.
Затем этот Identifier используется внутри для быстрого поиска свойств и переменных.
JSString::toIdentifier()Когда эксплойт входит в цикл for, который повторяется 1024 раза, каждая итерация создает новый объект WTF::StringImpl с путаницей типов с 32 новыми идентификаторами структуры, возвращаемыми функцией create_impl(). Когда этот объект с путаницей типов используется и передается в trigger() как произвольный объект, JSC вызывает на нем JSString::toIdentifier().
JSString::toIdentifier() проверяет определенные биты в идентификаторе структуры, чтобы подтвердить, что объект является допустимой строкой или может рассматриваться как таковая. Генерируя множество объектов с разными макетами и идентификаторами структуры, эксплойт увеличивает шансы, что хотя бы один из них будет иметь идентификатор структуры, который проходит внутренние проверки в JSString::toIdentifier().