Precisa de computação em nuvem? Comece agora mesmo

Mal posso esperar para derrubar você: DoS remota usando Wininit.exe

Stiv Kupchik

escrito por

Stiv Kupchik

January 31, 2023

Stiv Kupchik

escrito por

Stiv Kupchik

Stiv Kupchik é um pesquisador de segurança sênior de Tel Aviv, Israel.

Wininit é um processo crítico do Windows, desempenhando um papel crucial tanto na inicialização como no desligamento de sistemas operacionais do Windows (se ele travar, todo o sistema trava).

Contribuições editoriais e adicionais por Tricia Howard

Resumo executivo

  • O pesquisador Stiv Kupchik, da Akamai, encontrou uma nova vulnerabilidade de DoS (negação de serviço) no Wininit.exe da Microsoft, CVE-2022-44707, com uma pontuação CVSS de 6,5.

  • A vulnerabilidade foi divulgada ao MSRC em agosto e corrigida como parte da Patch Tuesday de dezembro de 2022.

  • A vulnerabilidade tira proveito do mecanismo de cache RPC, sobre o qual fizemos uma extensa pesquisa. Fornecemos uma prova de conceito do ataque em nosso kit de ferramentas RPC.

  • Ao explorar essa vulnerabilidade, um invasor pode burlar uma verificação de segurança graças ao mecanismo de cache e interagir com o mecanismo de desligamento em uma máquina remota do Windows, obtendo controle para parar ou iniciar desligamentos.

  • A vulnerabilidade afeta todas as versões sem patch do Windows, começando pelo Windows 8/Server 2012, reforçando a importância da aplicação de patches em tempo hábil.

Introdução

Em nosso post anterior, Cold Hard Cache, apresentamos mais algumas vulnerabilidades de RPC que encontramos usando nosso kit de ferramentas RPC, e chegou a hora de nos aprofundarmos nelas. Hoje, em mais um episódio sobre manobras de RPC, temos o Wininit.  

Wininit é um processo crítico do Windows, desempenhando um papel crucial tanto na inicialização como no desligamento de sistemas operacionais do Windows (se ele travar, todo o sistema trava). Dessa forma, ele expõe várias interfaces RPC que contêm a funcionalidade de desligamento, algumas até documentadas. A vulnerabilidade identificada está na interface WindowsShutdown .

O que é a interface WindowsShutdown?

WindowsShutdown é uma das poucas interfaces RPC expostas pelo Wininit. Ela é responsável pelo processo de desligamento (assim como o restante das interfaces RPC do Wininit; surpreendente, não é?). O UUID da interface é d95afe70-a6d5-4259-822e-2c84da1ddb0d. Faz parte do MS-RSP (Remote Shutdown Protocol) e tem as seguintes funções: 

funções expostas de WindowsShutdown: WsdrInitiateShutdown, WsdrAbortShutdown e WsdrCheckForHiberboot Fig. 1: as funções da interface WindowsShutdown

Analisando o arquivo IDL público, podemos ver que somente WsdrInitiateShutdown e WsdrAbortShutdown estão documentadas. Devemos nos preocupar com uma função não documentada? Para responder isso, vamos dar uma olhada no retorno de chamada de segurança dessa interface.

O retorno de chamada de segurança

O retorno de chamada verifica primeiro o protocolo de transporte e permite apenas ALPC ou TCP. Em seguida, o nível de autenticação é verificado, e somente RPC_C_AUTHN_LEVEL_PKT_PRIVACY é permitido. Se a função invocada não for WsdrCheckForHiberboot, o token do usuário de chamada remota será verificado. Isso é feito comparando o token com um SID conhecido (salvo em uma variável global, criada durante a inicialização do Wininit): SECURITY_NETWORK_RID. Chamadas para WsdrCheckForHiberboot não são restringidas pelo retorno de chamada de segurança.

descompilação da função de retorno de chamada de segurança de WindowsShutdown Fig. 2: o retorno de chamada de segurança de WindowsShutdown

A interface RPC é registrada com o comportamento de cache padrão; portanto, teoricamente, se podemos invocar WsdrCheckForHiberbootcom êxito, o resultado em cache bem-sucedido nos permitiria burlar a verificação de SID nas chamadas subsequentes para WsdrInitiateShutdown e WsdrAbortShutdown.

Então, o que precisamos fazer para chamar WsdrCheckForHiberboot?

WsdrCheckForHiberboot

Não nos preocupamos com o que a função faz, ou com o significado de hiberboot (é a inicialização rápida do Windows, para aqueles que querem saber), mas precisamos saber como denominá-la corretamente. Queremos definir a função corretamente em um arquivo IDL para compilar um cliente para ela. Embora a função não esteja documentada, podemos tentar analisar o advapi CheckForHiberboot, o único cliente RPC documentado que encontramos para WsdrCheckForHiberboot. Ele requer apenas dois argumentos: um ponteiro booliano e um booliano.

desmontagem advapi32 do CheckForHiberboot Fig. 3: advapi CheckForHiberboot: o único cliente RPC documentado encontrado para WsdrCheckForHiberboot

Podemos recriar a definição da função com esses argumentos, compilando um arquivo e um programa IDL. Mas ainda falta algo. Ao chamar a função remotamente com nosso cliente, o tempo de execução RPC nos diz que estamos chamando a função incorretamente, retornando um erro de stub RPC.

Recriação inicial da definição WsdrCheckForHiberboot, com base na função advapi Fig. 4: a primeira recriação da definição de WsdrCheckForHiberboot

Em vez de fazer mais adivinhações, podemos fazer algo mais delicado, mas complicado. Como parte do stub de interface RPC, há um campo chamado ProcFormatString. É basicamente uma string binária longa que descreve os tipos de argumento e os valores de retorno de todas as funções expostas pela interface. Esse campo é usado pelo tempo de execução RPC durante o processo de organização e desorganização das chamadas de função (que é o processo que retornou o erro de stub RPC durante nossa tentativa inicial). Analisando meticulosamente essa string binária manualmente, descobrimos que há outro argumento que a função espera obter, do tipo wchar_t*. Na próxima figura, você pode ver a seção da ProcFormatString de WsdrCheckForHiberboot, com nossos próprios comentários sobre cada parte:

Recriação inicial da definição WsdrCheckForHiberboot, com base na função advapi Fig. 5: seção de WsdrCheckForHiberboot a partir de ProcFormatString

Depois de adicionar esse argumento "novo" à nossa definição de função, temos sucesso! CheckForHiberboot retorna com sucesso, e podemos continuar chamando WsdrInitiateShutdown e WsdrAbortShutdown.

Os resultados...

Nosso desejo imediato é usar o ataque de cache para chamar WsdrInitiateShutdown e conseguir um desligamento remoto. Dessa vez, não precisamos ficar adivinhando. A definição da função não é apenas documentada no arquivo IDL, mas os sinalizadores que ela espera obter são documentados na função advapi InitiateShutdownA. Assim, usando a combinação de sinalização de SHUTDOWN_GRACE_OVERRIDE, SHUTDOWN_HYBRID e SHUTDOWN_FORCE_OTHERS, podemos forçar um desligamento imediato.

Com isso, basicamente concluímos nossa cadeia de ataques, podendo burlar o retorno de chamada de segurança e sua verificação de SID e realizando um desligamento remoto. Tecnicamente, é um escalonamento de privilégio (permitindo que qualquer usuário autenticado chame WsdrInitiateShutdown remotamente em vez de apenas aqueles permitidos no SECURITY_NETWORK_RID). Como só podemos realizar um desligamento usando essa interface, a vulnerabilidade foi categorizada como uma vulnerabilidade de DoS.

Detecção

Fornecemos uma OSQuery para detectar versões sem patch (e, portanto, vulneráveis) do Wininit.exe. Os clientes do Akamai Guardicore Segmentation podem usar o recurso Insight juntamente com essa consulta para pesquisar ativos vulneráveis.

  WITH product_version AS (
  WITH os_minor AS (
    WITH os_major AS (
      SELECT substr(product_version, 0, instr(product_version, ".")) as os_major, substr(product_version, instr(product_version, ".")+1) as no_os_major_substr
      FROM file
      WHERE path = "c:\windows\system32\wininit.exe"
    )
    SELECT substr(no_os_major_substr, instr(no_os_major_substr, ".")+1) as no_os_minor_substr, substr(no_os_major_substr, 0, instr(no_os_major_substr, ".")) as os_minor, os_major
    FROM os_major
  )
  SELECT
    CAST(substr(no_os_minor_substr, instr(no_os_minor_substr, ".")+1) AS INTEGER) AS product_minor,
    CAST(substr(no_os_minor_substr, 0, instr(no_os_minor_substr, ".")) AS INTEGER) AS product_major,
    CAST(os_minor AS INTEGER) AS os_minor,
    CAST(os_major AS INTEGER) AS os_major
  FROM os_minor
)
SELECT
  CASE
    WHEN NOT ((os_major = 6 AND os_minor = 3) OR (os_major = 6 AND os_minor = 2) OR (os_major = 10 AND os_minor = 0))
    THEN "not supported"
    WHEN os_major = 6 AND os_minor = 3 AND product_major = 9600 AND product_minor >= 20716 THEN "patched"
    WHEN os_major = 6 AND os_minor = 2 AND product_major = 9200 AND product_minor >= 24011 THEN "patched"
    WHEN (
        (product_major = 14393 AND product_minor >= 5582)
        OR
        (product_major = 10240 AND product_minor >= 19624)
        OR
        (product_major = 19041 AND product_minor >= 1620)
        OR
        (product_major = 22621 AND product_minor >= 963)
        OR
        (product_major = 22000 AND product_minor >= 1335)
        OR
        (product_major = 20348 AND product_minor >= 1366)
        OR
        (product_major = 17763 AND product_minor >= 3770)
    )
    THEN
      "patched"
    ELSE
      "not patched"

Resumo

Embora esta vulnerabilidade não seja crítica (é apenas um desligamento remoto, e nem mesmo autenticado), ele demonstra o potencial destrutivo inerente do MS-RPC, pois ele é integrado até mesmo aos serviços mais críticos do sistema operacional Windows. Além disso, ao contrário de outros tipos de vulnerabilidades, quase não há adivinhações com o RPC: todas as informações estão na sua frente, é só saber interpretá-las.

Encontrar maneiras de explorar essas funções críticas é exatamente por que continuamos nossa extensa pesquisa sobre MS-RPC. Apesar do seu uso generalizado, não há muitas pesquisas sobre ele. Vulnerabilidades como a que está sendo discutida hoje demonstram por que esse tipo de trabalho é necessário, e esperamos ver outros pesquisadores trabalhando sobre o MS-RPC, se assim o desejarem. 

Essa vulnerabilidade foi divulgada no final de agosto e corrigida na Patch Tuesday de dezembro de 2022.



Stiv Kupchik

escrito por

Stiv Kupchik

January 31, 2023

Stiv Kupchik

escrito por

Stiv Kupchik

Stiv Kupchik é um pesquisador de segurança sênior de Tel Aviv, Israel.