Общий метод эксплуатации процесса рендеринга браузера: после использования уязвимости для получения произвольного примитива чтения/записи памяти пользовательского режима,
Однако на этом противостояние не закончилось. Появились некоторые новые методы обхода CFG. Например, в chakra/jscript9 поток выполнения кода захватывается путем подделки адреса возврата функции в стеке; в версии 8 для выполнения шелл-кода используется
Анализируя образец CVE-2021-26411 в естественных условиях, мы обнаружили новый метод обхода защиты от CFG с помощью Windows RPC (Remote Procedure Call) [3]. Этот метод не полагается на цепочку ROP. Создав
Ретроспектива
В моем блоге «CVE-2021-26411: Internet Explorer mshtml use-after-free» проиллюстрирована основная причина:
Исправление этой уязвимости в патче Windows March заключается в добавлении проверки индекса перед удалением объекта в функции
Идея эксплуатации такой уязвимости UAF с контролируемым размером памяти заключается в следующем: использовать два разных типа указателей (BSTR и Dictionary.items), чтобы указать на повторно используемую память, затем утечка указателя и возможность разыменования указателя достигается за счет смешения типов:
Введение и эксплуатация Windows RPC
Windows RPC используется для поддержки сценария распределенных вызовов функций клиент/сервер. На основе Windows RPC клиент может вызывать функции сервера так же, как вызов локальной функции. Базовая архитектура Windows RPC показана следующим образом:
Программа клиент / сервер передает параметры вызова или возвращаемые значения функции заглушки нижнего уровня. Функция заглушки отвечает за инкапсуляцию данных в формат NDR(Network Data Representation). Связь через библиотеку времени выполнения обеспечивается через
Ниже приведен пример idl:
Когда клиент вызывает функцию добавления, сервер получает запрос на обработку от
Как показано на вышеупомянутом рисунке, в структуре
Вот пример, представляющий структуру
Согласно приведенному выше idl, когда клиент вызывает
Можно видеть, что дамп памяти динамической отладки согласуется с анализом структуры
Затем мы анализируем, как
Команда
Основываясь на приведенном выше анализе, после достижения произвольного примитива чтения/записи в память мы можем создать поддельный
Далее необходимо решить две проблемы:
Мы видим, что это косвенный вызов функции и есть проверка CFG. Следовательно, нам нужно подумать, как обойти здесь защиту CFG после подделки указателя функции
Давайте сначала решим Проблему 1: как вызвать
Мы можем заменить указатель функции vtable объекта DOM на
Затем решаем Вопрос 2: Как обойти защиту CFG в rpcrt4! NdrServerCall2?
Метод в примере:
После решения двух проблем поддельный
Скриншот эксплуатации:
Некоторые мысли
Новый метод обхода защиты от CFG за счет использования Windows RPC, представленного в CVE-2021-26411 в исходном образце. Эта технология эксплуатации не требует построения цепочки ROP и выполнения произвольного кода напрямую с помощью поддельного
Ссылки
[1] https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
[2] https://windows-internals.com/cet-on-windows/
[3] https://docs.microsoft.com/en-us/windows/win32/rpc/rpc-start-page
От ТС
За оригиналом сюда
Спасибо weaver за материал
Интересный способ обхода CFG, а главное простой и действенный.
Перевод:
Azrv3l cпециально для xss.pro
BTC: bc1qs2fk7zftnwwhhdrw9ge6ncxrspeyta7dymjwkj
ETH: 0xEb8CdE54aBaA7186E9dB8A27f6898C9F02397bab
vtable объекта DOM/js подделывается, чтобы захватить поток выполнения кода. Затем VirtualProtect вызывается цепочкой ROP для изменения памяти шеллкода на PAGE_EXECUTE_READWRITE, и, наконец, поток выполнения кода переходит к шеллкоду с помощью цепочки ROP. После Windows 8.1 Microsoft представила средство CFG (Control Flow Guard) [1] для проверки косвенного вызова функции, что снижает риск взлома vtable для выполнения кода.Однако на этом противостояние не закончилось. Появились некоторые новые методы обхода CFG. Например, в chakra/jscript9 поток выполнения кода захватывается путем подделки адреса возврата функции в стеке; в версии 8 для выполнения шелл-кода используется
WebAssembly со свойством исполняемой памяти. В декабре 2020 года Microsoft представила технологию смягчения последствий CET(Control-flow Enforcement Technology) [2], основанную на процессоре Intel Tiger Lake в Windows 10 20H1, которая защищает от взлома адрес возврата функции в стеке. Таким образом, как обойти CFG в среде смягчения последствий CET стало новой проблемой для эксплуатации уязвимостей.Анализируя образец CVE-2021-26411 в естественных условиях, мы обнаружили новый метод обхода защиты от CFG с помощью Windows RPC (Remote Procedure Call) [3]. Этот метод не полагается на цепочку ROP. Создав
RPC_MESSAGE, можно выполнить произвольный код, вызвав вручнуюrpcrt4!NdrServerCall2.Ретроспектива
В моем блоге «CVE-2021-26411: Internet Explorer mshtml use-after-free» проиллюстрирована основная причина:
removeAttributeNode() запускает обратный вызов valueOf объекта атрибута nodeValue. Во время обратного вызова clearAttributes() вызывается вручную, что приводит к предварительному освобождению BSTR, сохраненного в nodeValue. После возврата обратного вызова valueOf объект nodeValue не проверяется, что приводит к UAF.Исправление этой уязвимости в патче Windows March заключается в добавлении проверки индекса перед удалением объекта в функции
CAttrArray::Destroy
Идея эксплуатации такой уязвимости UAF с контролируемым размером памяти заключается в следующем: использовать два разных типа указателей (BSTR и Dictionary.items), чтобы указать на повторно используемую память, затем утечка указателя и возможность разыменования указателя достигается за счет смешения типов:
Введение и эксплуатация Windows RPC
Windows RPC используется для поддержки сценария распределенных вызовов функций клиент/сервер. На основе Windows RPC клиент может вызывать функции сервера так же, как вызов локальной функции. Базовая архитектура Windows RPC показана следующим образом:
Программа клиент / сервер передает параметры вызова или возвращаемые значения функции заглушки нижнего уровня. Функция заглушки отвечает за инкапсуляцию данных в формат NDR(Network Data Representation). Связь через библиотеку времени выполнения обеспечивается через
rpcrt4.dll.Ниже приведен пример idl:
C++:
[
uuid("1BC6D261-B697-47C2-AF83-8AE25922C0FF"),
version(1.0)
]
interface HelloRPC
{
int add(int x, int y);
}
Когда клиент вызывает функцию добавления, сервер получает запрос на обработку от
rpcrt4.dll и вызывает rpcrt4!NdrServerCall2:
rpcrt4!NdrServerCall2 имеет только один параметр PRPC_MESSAGE, который содержит важные данные, такие как индекс функции и параметры. Структура RPC_MESSAGE сервера и основная структура вспомогательных данных показаны следующим образом (32 bits):
Как показано на вышеупомянутом рисунке, в структуре
RPC_MESSAGE двумя важными переменными вызова функции являются Buffer и RpcInterfaceInformation. Buffer хранит параметры функции, а RpcInterfaceInformation указывает на структуру RPC_SERVER_INTERFACE. Структура RPC_SERVER_INTERFACE сохраняет информацию об интерфейсе программы сервера, в которой DispatchTable (+ 0x2c) сохраняет указатели интерфейсных функций библиотеки времени выполнения и функции-заглушки, а InterpreterInfo (+ 0x3c) указывает на структуру MIDL_SERVER_INFO. Структура MIDL_SERVER_INFO сохраняет информацию интерфейса IDL сервера, а DispatchTable (+ 0x4) сохраняет массив указателей функций подпрограммы сервера.Вот пример, представляющий структуру
RPC_MESSAGEСогласно приведенному выше idl, когда клиент вызывает
add (0x111, 0x222), серверная программа прерывается на rpcrt4!NdrServerCall2:
Можно видеть, что дамп памяти динамической отладки согласуется с анализом структуры
RPC_MESSAGE, а функция добавления хранится в MIDL_SERVER_INFO.DispatchTable.Затем мы анализируем, как
rpcrt4!NdrServerCall2 вызывает функцию добавления в соответствии с RPC_MESSAGE:Rpcrt4!NdrServerCall2 вызывает rpcrt4!NdrStubCall2. Rpcrt4!NdrStubCall2 вычисляет адрес указателя функции на основе MIDL_SERVER_INFO.DispatchTable и RPC_MESSAGE.ProcNum и передает указатель функции, параметры функции и длину параметра в rpcrt4!Invoke
Команда
rpcrt4!Invoke, наконец, вызывает стандартную функцию, предоставленную сервером:
Основываясь на приведенном выше анализе, после достижения произвольного примитива чтения/записи в память мы можем создать поддельный
RPC_MESSAGE, установить указатель функции и параметры функции, которые нужно вызвать, и вызвать rpcrt4!NdrServerCall2 вручную, чтобы реализовать выполнение любой функции.Далее необходимо решить две проблемы:
- Как вызвать
rpcrt4!NdrServerCall2в javascript - При наблюдении за вызовом функции серверной подпрограммы в
rpcrt4!Invoke:
Мы видим, что это косвенный вызов функции и есть проверка CFG. Следовательно, нам нужно подумать, как обойти здесь защиту CFG после подделки указателя функции
MIDL_SERVER_INFO.DispatchTable.Давайте сначала решим Проблему 1: как вызвать
rpcrt4!NdrServerCall2 в javascript?: Мы можем заменить указатель функции vtable объекта DOM на
rpcrt4!NdrServerCall2. Поскольку rpcrt4!NdrServerCall2 является допустимым указателем, записанным в CFGBitmap, он может пройти проверку CFG. Образец заменяет MSHTML!CAttribute :: normalize на rpcrt4!NdrServerCall2 и вызывает «xyz.normalize ()» в javascript для вызова rpcrt4!NdrServerCall2.Затем решаем Вопрос 2: Как обойти защиту CFG в rpcrt4! NdrServerCall2?
Метод в примере:
- Используйте поддельные RPC_MESSAGE и
rpcrt4!NdrServerCall2для вызова VirtualProtect и измените атрибут памятиRPCRT4!__ guard_check_icall_fptrнаPAGE_EXECUTE_READWRITE - Замените указатель
ntdll!LdrpValidateUserCallTarget, сохраненный вrpcrt4!__guard_check_icall_fptr, наntdll!KiFastSystemCallRet, чтобы отключить проверку CFG в rpcrt4.dll - Восстановить атрибут памяти
RPCRT4!__guard_check_icall_fptr
JavaScript:
function killCfg(addr) {
var cfgobj = new CFGObject(addr)
if (!cfgobj.getCFGValue())
return
var guard_check_icall_fptr_address = cfgobj.getCFGAddress()
var KiFastSystemCallRet = getProcAddr(ntdll, 'KiFastSystemCallRet')
var tmpBuffer = createArrayBuffer(4)
call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, 0x40, tmpBuffer])
write(guard_check_icall_fptr_address, KiFastSystemCallRet, 32)
call2(VirtualProtect, [guard_check_icall_fptr_address, 0x1000, read(tmpBuffer, 32), tmpBuffer])
map.delete(tmpBuffer)
}
После решения двух проблем поддельный
RPC_MESSAGE можно использовать для вызова любого указателя функции, включая буфер, хранящий шелл-код, поскольку проверка CFG в rpcrt4.dll была прервана. Наконец, образец записывает шелл-код в расположение msi.dll+0x5000 и, наконец, вызывает шелл-код через rpcrt4!NdrServerCall2
JavaScript:
var shellcode = new Uint8Array([0xcc])
var msi = call2(LoadLibraryExA, [newStr('msi.dll'), 0, 1]) + 0x5000
var tmpBuffer = createArrayBuffer(4)
call2(VirtualProtect, [msi, shellcode.length, 0x4, tmpBuffer])
writeData(msi, shellcode)
call2(VirtualProtect, [msi, shellcode.length, read(tmpBuffer, 32), tmpBuffer])
call2(msi, [])
Скриншот эксплуатации:
Некоторые мысли
Новый метод обхода защиты от CFG за счет использования Windows RPC, представленного в CVE-2021-26411 в исходном образце. Эта технология эксплуатации не требует построения цепочки ROP и выполнения произвольного кода напрямую с помощью поддельного
RPC_MESSAGE. Эта технология эксплуатации проста и стабильна. Разумно полагать, что это станет новой и эффективной технологией эксплуатации, позволяющей обойти защиту от CFG.Ссылки
[1] https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
[2] https://windows-internals.com/cet-on-windows/
[3] https://docs.microsoft.com/en-us/windows/win32/rpc/rpc-start-page
От ТС
За оригиналом сюда
Спасибо weaver за материал
Интересный способ обхода CFG, а главное простой и действенный.
Перевод:
Azrv3l cпециально для xss.pro
BTC: bc1qs2fk7zftnwwhhdrw9ge6ncxrspeyta7dymjwkj
ETH: 0xEb8CdE54aBaA7186E9dB8A27f6898C9F02397bab