
Эксплойт, подтверждающий концепцию для CVE-2023-41993, путаницы типов JIT в WebKit в Safari. Предоставляет примитивы addrof/fakeobj через манипуляции кучей и путаницу GetterSetter, что позволяет произвольное чтение/запись в процессе WebContent.
PoC-эксплойт для CVE-2023-41993. Написан только до addrof/fakeobj. Надёжность невысока. Если хотите улучшить, попробуйте распылить идентификаторы структуры.
https://po6ix.github.io/POC-for-CVE-2023-41993/pwn.html
Я решил разместить его на GitHub Pages по многочисленным просьбам.
Пожелайте мне удачи, чтобы GitHub не заблокировал меня...
Это потому, что значение factor, определённое в функции pwn, не соответствует вашему устройству.
Для такого случая я сделал так, чтобы использовалось случайное значение от 87 до 1088.
Таким образом, вы можете найти правильное значение factor, просто обновляя страницу время от времени.
Вероятностно, он должен сработать в пределах 100 попыток.
Также было бы неплохо, если бы вы прислали мне информацию, которая отображается в случае успеха.
Это даёт вам примитив чтения/записи для процесса веб-контента Safari.
Но чтобы действительно сделать это полезным, вам потребуется объединить его с другими компонентами.
Возможно, вы хотите детального описания (writeup) для этого. Но, к сожалению, у меня нет времени писать его. Поэтому я оставлю здесь несколько заметок, чтобы вы могли понять, как это работает.
Если посмотреть на коммит, речь идёт об изменении для HeapLocation.
Был добавлен новый фактор, чтобы определить, являются ли узлы одинаковыми или нет.
Это говорит нам о том, что такие узлы, как GetByOffset, MultiGetByOffset, могут быть перепутаны.
Но на самом деле это касается только смещения.
Скажем, есть два узла GetByOffset с разными смещениями.
Один из них будет удалён CSE, а вместо него будет использован оставшийся.
Таким образом, это в основном путаница смещений, но она не даёт доступа к произвольному смещению.
Потому что для CSE таких типов узлов они должны быть подняты фазой LICMPhase.
Для узлов, выполняющих операции записи, подъём в этой фазе не разрешён.
Поэтому такая же путаница не возникает для узлов PutByOffset, MultiPutByOffset.
Кроме того, когда GetByOffset поднимается, вызывается функция safeToExecute, чтобы проверить, легитимен ли узел для выполнения, и разрешается доступ только к смещению, меньшему размера хранилища (inline/ool).
Итак, идея для эксплуатации этой уязвимости — GetterSetter.
Если вызвать Object.__defineGetter__ для определения свойства, создаётся объект GetterSetter, но он хранится в хранилище свойств и в обычной ситуации недоступен.
Однако с помощью этой манипуляции со смещением вы можете получить к нему доступ.
Затем вызывается функция Object, чтобы спровоцировать путаницу типов.
JSObject* JSCell::toObjectSlow(JSGlobalObject* globalObject) const
{
Integrity::auditStructureID(structureID());
ASSERT(!isObject());
if (isString())
return static_cast<const JSString*>(this)->toObject(globalObject);
if (isHeapBigInt())
return static_cast<const JSBigInt*>(this)->toObject(globalObject);
ASSERT(isSymbol());
return static_cast<const Symbol*>(this)->toObject(globalObject);
}
Будет создан объект SymbolObject, у которого GetterSetter является внутренним значением. И это некорректно, так как внутреннее значение SymbolObject должно быть экземпляром Symbol, а не GetterSetter.
let getterSetter = jitme(1);
let symbolObject = Object(getterSetter);
symbolObject.description; // вызов геттера
String Symbol::description() const
{
auto& uid = m_privateName.uid();
return uid.isNullSymbol() ? String() : uid;
}
Затем при вызове геттера description он возвращает экземпляр String. Это путаница типов между Symbol.m_privateName и GetterSetter.m_getter. Каждый раз при вызове этого геттера увеличивается счётчик ссылок поля m_privateName.m_uid, которое находится по смещению 0x0. Это очень полезно, потому что это смещение совпадает с полем structure ID функции-геттера. Вызывая эту функцию несколько раз, можно изменить structure ID экземпляра JSFunction. Я подготовил другой тип с множеством свойств. Затем, если синхронизировать structure ID с ним, можно выполнить запись за границы (OOB) в хранилище свойств. Это напрямую даёт примитив addrof/fakeobj.