
Техники эксплуатации ChakraCore
CVE-2016-7190 [0] — это переполнение кучи в функции Array.map() в ChakraCore, которое позволяет перезаписывать смежную память. Основная идея получения произвольного чтения/записи заключается в том, чтобы сначала выделить несколько последовательных массивов целых чисел JavaScript и использовать переполнение для изменения размера одного массива. Затем мы используем этот массив для изменения базового адреса Uint8Array на любой адрес, который хотим читать/записывать. Причина этого дополнительного шага в том, что переполнение ограничено 2-кратным размером переполненного массива целых чисел.
Эта уязвимость очень подходит для тестирования различных стратегий эксплуатации, поскольку её можно легко повторно внедрить в текущие версии ChakraCore (см. undo-cve-2016-7190.patch).
В этом примере мы перехватываем поток управления, перезаписывая указатель vtable объекта Uint8Array C++ на контролируемый адрес памяти и вызывая функцию объекта Uint8Array, что приводит к вызову виртуальной функции.
Целостность потока управления (CFI) — это защитная техника для смягчения атак, направленных на перехват потока управления. Общая идея CFI заключается в построении графа потока управления (CFG) приложения во время компиляции, а затем во внедрении во время выполнения проверок, гарантирующих, что поток управления не отклоняется от статически вычисленного CFG. Однако, если приложение, например веб-браузер, поддерживает динамическую генерацию кода, CFG должен быть расширяемым во время выполнения. Это накладывает ряд проблем:
Во время нашего исследования мы сосредоточились на последней проблеме. Основная идея заключается в манипулировании входными данными (данными) JIT-компилятора. В результате JIT-компилятор генерирует вредоносный код, который затем интегрируется в текущий контекст — и даже может быть усилен с помощью CFI. Параллельно с нашим исследованием theori [4] показали, как обойти CFI, манипулируя выходными данными JIT-компилятора. Эта атака смягчается проверкой целостности выходных данных с помощью контрольной суммы. Это не может остановить нашу атаку, потому что мы манипулируем входными данными JIT-компилятора. ОДНАКО, при вынесении JIT-компиляции в отдельный процесс (так называемый Arbitrary Code Guard [3]) обе атаки смягчаются.
Мы демонстрируем, что злоумышленник может использовать атаку только на данные против JIT-компилятора для генерации произвольного нативного кода. В частности, мы модифицируем промежуточное представление (IR) JIT-компилятора, чтобы внедрить контролируемые злоумышленником инструкции. Когда JIT-компилятор затем генерирует нативный код на основе модифицированного IR, он генерирует нативный код, контролируемый злоумышленником.
С момента первоначального проведения исследования и до настоящего времени IR ChakraCore изменился. Мы не приложили усилий для переноса атаки, поэтому для экспериментов с этой атакой используйте следующие бинарные файлы.
Во время анализа ACG [3] мы заметили, среди прочего [1,2], что глобальные данные только для чтения, хранящиеся в секции .mrdata, должны быть скорректированы для интеграции динамически генерируемого кода. Это делается с помощью функции LdrProtectMrdata(), которая использует блокировку для обеспечения потокобезопасности. Однако секция .mrdata сначала повторно отображается как доступная для записи до захвата блокировки. Интересно, что секция .mrdata содержит базовый адрес и размер самой секции .mrdata, которые позже используются для повторного отображения этой секции только для чтения.
Злоумышленник может использовать это для создания примитива атаки, позволяющего переотображать память только для чтения как доступную для записи. Для этого злоумышленник выполняет следующие шаги:
Следствием этой атаки является то, что ранее доверенные данные, т.е. данные, отображённые только для чтения, становятся недоверенными. В нашей proof-of-concept мы используем этот примитив для обхода Control-flow Guard (CFGuard) путём изменения указателя на верификационную функцию CFGuard, который сохранён в _guard_dispatch_icall_fptr. Эффект можно наблюдать, подключив отладчик и изменив переменную bypass_cfguard.
[0] https://bugs.chromium.org/p/project-zero/issues/detail?id=923
[1] http://alex-ionescu.com/publications/euskalhack/euskalhack2017-cfg.pdf
[2] https://sites.google.com/site/bingsunsec/dataonlyattack
[3] https://blogs.windows.com/msedgedev/2017/02/23/mitigating-arbitrary-native-code-execution/
[4] http://theori.io/research/chakra-jit-cfg-bypass