Lições de segurança cibernética: uma vulnerabilidade PATH no Windows

Em uma de nossas auditorias regulares de segurança de aplicativos ExpressVPN, descobrimos uma vulnerabilidade interessante.

Em uma de nossas auditorias regulares de segurança de aplicativos Avance Network, descobrimos uma vulnerabilidade interessante. Ele não foi encontrado em nossa própria base de código, mas resultou do uso do próprio .NET Core que, na pior das hipóteses, poderia resultar no aumento de privilégios na plataforma Windows. No entanto, a vulnerabilidade só poderia ser explorada se um dos limites de segurança controversos fosse violado: o diretório gravável em PATH.

 

Neste artigo, explicaremos em detalhes a variável de ambiente PATH e as implicações de segurança de tê-la configurada incorretamente e lançaremos luz sobre algumas de nossas descobertas neste espaço.

 

Este problema de vulnerabilidade PATH foi encontrado durante uma auditoria de uma versão beta fechada de nosso produto para Windows não disponível para consumidores. Corrigimos o problema depois que o descobrimos e divulgamos a descoberta à Microsoft.

 

Qual é a variável de ambiente PATH?

 

Quando um usuário tenta executar um programa a partir da interface de linha de comando (CLI), o Windows precisa saber a verdadeira localização do programa para executá-lo. Em nosso exemplo abaixo, tentamos executar o ping . O Windows não sabe imediatamente onde o ping está localizado, mas ainda consegue localizá-lo.

 

 

Internamente, o Windows procura o local por meio da variável de ambiente PATH . O ambiente PATH é uma lista de diretórios delimitada por ponto e vírgula (;), como a seguinte.

 

C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\dotnet\;C:\Users\User\AppData\Local\Microsoft\WindowsApps;;C:\Users\User\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\User\.dotnet\tools

 

Observamos que PATH engloba a variável de ambiente PATH para o sistema e o usuário, embora, para simplificar, o restante do artigo se concentre na variável de ambiente PATH do sistema . Em nosso exemplo, o Windows pesquisa cada um dos caminhos da lista para executáveis ​​com o nome de base de ping e executa o primeiro que corresponda (não faz distinção entre maiúsculas e minúsculas). Aqui, o executável foi encontrado na primeira entrada de PATH , C: \ Windows \ system32 e C: \ Windows \ System32 \ PING.EXE é executado.

 

 

Pode-se pensar em um PATH como uma lista de locais confiáveis ​​nos quais o Windows pode pesquisar programas para executar. Isso não se limita apenas à linha de comando; O próprio Windows depende da variável de ambiente PATH para carregar dependências, particularmente bibliotecas de vínculo dinâmico (DLLs). Se uma determinada DLL não puder ser encontrada, o PATH pode ser percorrido para localizar a DLL.

 

CAMINHO: Uma superfície de ataque não monitorada

 

Desnecessário dizer que regras estritas devem ser aplicadas nos caminhos no PATH para que sejam considerados confiáveis. Em particular, se o conteúdo de qualquer um dos diretórios em PATH puder ser modificado por qualquer usuário local / remoto sem privilégios, todas as apostas estão canceladas . Infelizmente, qualquer administrador pode adicionar diretórios ao acaso na variável PATH sem nenhuma verificação de segurança realizada pelo sistema operacional. Isso pode acontecer por vários motivos:

 

Erro do usuário: um administrador deseja invocar um determinado programa apenas por seu nome de base na linha de comando e adiciona o diretório onde o programa reside, sem primeiro verificar as permissões no diretório.

 

Instalação vulnerável: durante o processo de instalação, um programa benigno adiciona um diretório com controles de acesso incorretos à variável de ambiente PATH sem bloquear as permissões nesse diretório. Pesquisadores de segurança descobriram vulnerabilidades desse tipo nos últimos anos, por exemplo, CVE-2020-12510.

 

muita confusão sobre se ter um diretório gravável por todos no PATH é um risco de segurança. Provamos definitivamente que é um risco à segurança com os cenários de ataque descritos abaixo.

 

O PATH para NT Autoridade / Sistema

 

Apresentamos um roteiro para aumentar os privilégios na máquina local, dado um diretório gravável em PATH. Especificamente, nos seguintes cenários de ataque, presumimos que o seguinte é verdadeiro:

 

A vítima está executando o Windows

 

Um diretório listado em PATH pode ser escrito por qualquer usuário

O invasor tem a capacidade de gravar arquivos no diretório em 2)

Cenário 1: interceptação de PATH - sequestro de ordem de pesquisa

Este cenário de exploração surge como uma extensão natural de como a variável PATH é usada. Suponha que um administrador use regularmente um programa personalizado ( clean.bat ) para fazer operações administrativas. Ele adiciona o diretório em que reside, C: \ tools , à variável PATH do sistema para facilitar a chamada durante suas tarefas normais. O programa é executado quando ele invoca clean e ele felizmente sai para realizar suas outras funções.

 

 

Sem que ele saiba, a pasta C: \ compilador na variável PATH pode ser gravada por todos e sua ordem no PATH é muito anterior à verdadeira localização do programa. Um usuário mal-intencionado percebe e grava um script com o mesmo nome na pasta C: \ compiler . Na próxima vez que o administrador executar limpo a partir da linha de comando, o programa limpo em C: \ compilador será executado:

 

 

A partir daí, a conta do administrador é comprometida - basta contornar o Controle de Conta de Usuário (UAC), o que não é uma garantia de segurança e é trivialmente contornável .

 

Essa técnica é conhecida como sequestro de ordem de pesquisa , em que um binário malicioso encontrado anteriormente na variável PATH é executado no lugar do executável benigno esperado. Um invasor sub-reptício pode garantir que o programa original seja chamado depois que a carga útil for executada, o que significa que o administrador não saberia.

 

Observe que isso não se aplica apenas a comandos executados pelo administrador, mas também por scripts e programas que invocam o shell para executar um comando. Se algum programa ou script não tiver cuidado com a forma como invoca outros programas, essa vulnerabilidade pode ser acionada. 

 

Durante o teste interno de uma compilação de pré-lançamento do aplicativo Windows do Avance Network, encontramos essas invocações que podem ser exploradas quando um diretório em PATH é gravável. Durante a instalação, o programa precisava encontrar as versões instaladas dos tempos de execução do .NET e instalar os tempos de execução ausentes. Se olharmos a documentação, a maneira “ recomendada ” é invocar o executável dotnet , que programaticamente seria parecido com este:

 

```

var process = new Process

{

    StartInfo = new ProcessStartInfo(“dotnet”, "--list-runtimes")

    {

        UseShellExecute = false,

        RedirectStandardOutput = true,

        RedirectStandardError = true

    }

};

process.Start();

process.WaitForExit();

return process.StandardOutput.ReadToEnd();

```

 

Nesse caso, como o dotnet é encontrado por meio da variável de ambiente PATH , a ordem de pesquisa pode ser sequestrada e o binário malicioso pode ser executado em seu lugar. Nossos desenvolvedores rapidamente fizeram a triagem e corrigiram o problema carregando apenas o dotnet de caminhos de instalação confiáveis, evitando que tais técnicas de exploração funcionem mesmo quando há um diretório gravável na variável de ambiente PATH .

 

Cenário 2: sequestro de caminho de pesquisa de DLL em um aplicativo externo privilegiado

 

Bibliotecas de vínculo dinâmico (DLLs) são dependências de um aplicativo empacotado em seu próprio arquivo binário. Isso permite que o código seja compartilhado sem ter várias instâncias do mesmo código espalhadas pelos arquivos. Quando um aplicativo precisa invocar um método de uma dessas bibliotecas, eles carregam a DLL na memória e executam a função relevante na DLL. Como o código é executado a partir da DLL, ele deve ser confiável e não pode ser carregado arbitrariamente.

 

Quando um aplicativo do Windows é carregado, algumas DLLs podem estar faltando no início. Nesse caso, o aplicativo tentará procurar DLLs ausentes de que precisa da seguinte maneira:

 

olhando primeiro para o diretório de onde foi carregado (onde o aplicativo reside)

olhando para o diretório atual

o diretório do sistema

o diretório do Windows

pesquisando nos diretórios listados na variável de ambiente PATH

 

Em circunstâncias normais, esse comportamento é garantido. Os desenvolvedores podem evitar que seus aplicativos sejam carregados fora dos diretórios desejados, certificando-se de que incluam todas as dependências de que o programa precisa na pasta em que reside.

 

No entanto, nem sempre é esse o caso, se o Windows não encontrar a DLL de que precisa, ele pode voltar a ser carregado a partir dos diretórios da variável de ambiente PATH . Isso pode ser sequestrado por um usuário mal-intencionado com acesso de gravação a um diretório no PATH , usando uma técnica conhecida como Phantom DLL Hijacking . Listamos dois estudos de caso abaixo em que aplicativos privilegiados (por exemplo, drivers, serviços) mostram esse comportamento.

 

O curioso caso do Crisys

 

Em julho de 2020, recebemos um envio de um pesquisador BugCrisys alegando ter encontrado um escalonamento de privilégios para nosso aplicativo do Windows. O pesquisador forneceu a seguinte prova de que estava carregando o igdgmm32.dll de um diretório na variável de ambiente PATH.

 

A triagem inicial conduzida pelo crisys não foi capaz de reproduzir a descoberta. Nossa equipe de triagem interna então verificou se não perdemos nenhuma descoberta válida. Primeiro estudamos o impacto do problema; do arquivo.exe nunca é executado em um contexto privilegiado e apenas como o usuário atual , portanto , o escalonamento de privilégios seria lateral no pior caso (de um usuário para outro). No entanto, não descartamos a possibilidade de um caminho para uma escalada de privilégios bem-sucedida; pode-se tentar comprometer o administrador que executa o Avance Network.exe de outra conta de usuário sem privilégios na mesma máquina.

 

Em seguida, examinamos os pré-requisitos para que a exploração seja bem-sucedida. O processo de instalação garante que os controles de acesso corretos sejam definidos para as pastas criadas. Isso significa que as pastas em que o Avance Network.exe reside não podem ser gravadas por usuários sem privilégios . A prova de conceito que o pesquisador forneceu carrega de C: \ Python38 , um diretório não relacionado ao Avance Network e que já era gravável em todo o mundo para começar, provavelmente devido a uma configuração incorreta por parte do Administrador. Isso significa que a maioria de nossos usuários não são afetados, a menos que tenham um diretório mundial gravável para começar.

 

Em seguida, aprofundamos a questão subjacente. Da mesma forma, em nossas bancadas de teste de máquina virtual, não conseguimos reproduzir o achado, mas estávamos convencidos de que isso foi possível graças aos logs do Procmon fornecidos pelo pesquisador. Investigamos a própria DLL e descobrimos que igdgmm32.dll faz parte do pacote Intel HD Graphics Drivers. A partir daí, isolamos rapidamente o problema e encontramos este artigo sobre DLL Hijacking. Acontece que o driver é carregado como parte da estrutura de IU do Windows Presentation Foundation (WPF) (uma estrutura usada para construir aplicativos de IU do Windows) e isso ocorre apenas quando o chipset do sistema usado pertence à Intel. Na verdade, essa era a dependência ausente que estava fazendo com que a biblioteca carregasse a partir da variável de ambiente PATH.

 

Infelizmente, neste caso, como o problema subjacente afeta qualquer aplicativo que use a estrutura de interface do usuário do Windows Presentation Foundation , há muito pouco que pode ser feito do nosso lado, exceto as atenuações que já temos em vigor. Uma correção completa exigiria que o fornecedor corrigisse o problema. 

 

Entramos em contato com a Microsoft e a Intel sobre o assunto, creditando o pesquisador original pela descoberta. A Microsoft alegou que não estava sob sua supervisão e nos incitou a notificar a Intel. A Intel investigou o problema e descobriu que o problema levantado no relatório estava presente em uma versão mais antiga do driver (26.20.100.7262), e a versão mais recente na época (27.20.100.8476) não tinha mais o problema. 

 

Mesmo sem um patch do fornecedor, é importante enfatizar que isso só pode ocorrer se um diretório em PATH for gravável, o que por padrão não é o caso, portanto, reiteramos a importância de verificar seu PATH .

 

Ó dependência, onde estás?

 

Em nosso segundo estudo de caso, examinamos uma vulnerabilidade encontrada durante uma auditoria de nosso aplicativo Windows de próxima geração (pré-lançamento). Durante nosso teste, observamos as dependências carregadas via Procmon; uma dependência chamou nossa atenção - Microsoft.DiaSymReader.Native.amd64.dll . Percebemos que ele era carregado sempre que um serviço pertencente ao nosso aplicativo era iniciado ou reiniciado.

 

Muito parecido com o sequestro de DLL acima, a DLL pode ser sequestrada e carregada de um diretório na variável de ambiente PATH . O AppService estava sendo executado como NT AUTHORITY \ LOCAL SERVICE , que por padrão não é privilegiado. No entanto, devido aos limites de permissão inadequados no Windows, se pudermos obter a execução de código no AppService por meio do plantio de uma DLL mal-intencionada em um diretório PATH gravável , podemos aproveitar um dos desvios existentes para aumentar os privilégios para NT AUTHORITY \ SYSTEM . Isso é lamentável porque, embora NT AUTHORITY \ LOCAL SERVICEfoi projetado para ter menos privilégios, devido à complexidade do sistema operacional Windows, nem todos os caminhos de escalonamento de privilégios são cobertos. Os interessados ​​podem ler mais sobre os escalonamentos de privilégios possíveis aqui.

 

Nossa equipe de desenvolvimento investigou por algum tempo, mas não havia nenhuma referência a esta biblioteca em qualquer lugar de nossa base de código. De alguma forma ou em algum lugar, algo estava carregando essa DLL e tivemos que ir ao fundo dela para identificar a causa raiz e proteger nossos usuários.

 

Então, fizemos algo bastante extremo. Da base de código original, eles retiraram grandes pedaços do código, recompilaram e executaram o programa para ver se a DLL ainda estava carregada. Com isso, pudemos efetivamente fazer uma “pesquisa binária” por meio da base de código para identificar a causa raiz. Acontece que Microsoft.DiaSymReader.Native.amd64.dll foi carregado porque uma exceção não tratada foi lançada no programa. A equipe de segurança ofensiva criou rapidamente uma prova de conceito abaixo.

 

namespace PoC

{

    public class Program

    {

        public static void Main(string[] args)

        {

            var a = args[100]; // triggers IndexOutOfRangeException

        }

    }

}

 

Executamos o PoC, e eis que Microsoft.DiaSymReader.Native.amd64.dll foi carregado!

 

Relatamos o problema à Microsoft em 5 de janeiro de 2021. Em 21 de janeiro, a Microsoft determinou que a vulnerabilidade não atendia ao limite de manutenção porque “Adicionar pastas à variável PATH requer direitos de administrador e todas as pastas padrão incluídas no PATH variável requer permissões de administrador para modificar. ” Isso é consistente com a forma como eles lidaram com vulnerabilidades semelhantes no passado (mais informações sobre isso no Cenário 3).

 

A equipe de desenvolvimento, ao perceber o problema, corrigiu-o imediatamente, empacotando as DLLs ausentes com a instalação. Os arquivos Microsoft.DiaSymReader.Native.amd64.dll para a versão de 64 bits e Microsoft.DiaSymReader.Native.x86.dll para a versão de 32 bits são instalados na pasta do aplicativo onde os aplicativos de serviço residem, portanto, os arquivos não serão mais ser carregado do PATH . Isso significa que nosso aplicativo permanece seguro, independentemente da decisão da Microsoft de publicar um patch para esse problema.

 

Cenário 3: sequestro de caminho de pesquisa de DLL em aplicativos padrão do Windows 

 

Mesmo se você optar por não instalar nada em sua máquina, alguns aplicativos integrados do Windows podem estar sujeitos a sequestro de DLL. Os pesquisadores de segurança estudaram extensivamente essa técnica de exploração e publicaram descobertas detalhadas em diferentes cenários nos quais isso pode ser explorado. Os aplicativos do Windows tendem a ser executados como serviços ou aplicativos com privilégios, portanto, um DLL Hijack explorável permitiria a um usuário executar o código como esse aplicativo para aumentar os privilégios. O pré-requisito, como sempre, é que um diretório em PATH seja gravável para nosso usuário menos privilegiado.

 

O que é particularmente impressionante não é a existência de tais problemas, mas a postura do fornecedor em corrigir esse problema. Existem dois alvos amplamente conhecidos onde isso pode ser explorado, um que funciona para o Windows 8 e inferior e outro que funciona para o Windows 10 . Para ambos os problemas, a Microsoft considerou que eles não cumpriam os padrões de manutenção. Observamos que a primeira técnica de exploração foi atenuada silenciosamente em 2013 com o lançamento do Windows 8.1, embora não haja notícias de patches para o último. Não há defesa profunda: uma vez que uma máquina tem um diretório PATH sem controles de acesso adequados, um processo / usuário malicioso pode facilmente escalar privilégios e executar qualquer tipo de atividade maliciosa como desejar.

 

O que isso significa para o usuário final?

Em abril de 2018, a Microsoft deixou claro que as vulnerabilidades que exigem que um diretório no PATH seja gravável não são vulnerabilidades, uma vez que os diretórios nunca deveriam ser graváveis ​​mundialmente e, se fossem, é culpa do administrador ou do aplicativo que fez essa mudança. Como visto nos Cenários 2 e 3, as técnicas de exploração que aproveitam os diretórios PATH graváveis provavelmente não serão atenuadas por patches oficiais, portanto, cabe aos usuários finais garantir que todos os diretórios no PATH tenham os controles de acesso apropriados no local.

 

Felizmente, essas vulnerabilidades não são comuns. Os usuários raramente alteram a variável de ambiente PATH do sistema , e é ainda mais raro para eles especificar um diretório gravável por todos, embora isso seja definitivamente possível. É mais provável que um processo de instalação apresente uma vulnerabilidade. No entanto, em nossa rápida investigação de aproximadamente 100 dos principais aplicativos para Windows de vários sites de download, nenhuma das instalações apresentou essa vulnerabilidade.

 

Aqui no Avance Network, implementamos medidas defensivas aprofundadas para garantir que, mesmo que o PATH contenha um diretório gravável, nossos aplicativos nunca carreguem o código desses diretórios. Fazemos isso garantindo que os executáveis ​​sejam executados a partir de caminhos confiáveis, juntamente com a mitigação de vulnerabilidades de implantação de DLL quando necessário.

 

No entanto, nunca se pode ser muito cuidadoso. Para isso, criamos um script PowerShell simples que você pode usar para auditar seu sistema. Como acontece com qualquer script que você encontrar na Internet, leia com atenção para ter certeza de entender o que ele está fazendo. 

 

Você pode executar o script como um usuário de baixo privilégio para ver se algum dos diretórios no PATH do sistema é gravável, e o script mostra os diretórios graváveis ​​na linha de comando

 

Você pode se proteger removendo esses diretórios do PATH do sistema ou alterando apropriadamente as permissões dos diretórios listados. Feito isso, você pode executar o script novamente e verificar os resultados para ter certeza de que seu sistema está realmente protegido!

 

É importante que os usuários fiquem atentos para proteger sua privacidade e segurança. Acreditamos no empoderamento dos usuários e capacitá-los a se proteger, munindo-os com ferramentas e tecnologias para isso. Nossa discussão sobre as vulnerabilidades do PATH deve dissipar alguns mitos e esperamos que nosso script tenha ajudado nossos leitores a identificar vulnerabilidades em suas máquinas antes que possam ser exploradas por agentes mal-intencionados.

 

function Test-Administrator

{

    $domain, $userToFind = [String]([Security.Principal.WindowsIdentity]::GetCurrent().Name) -Split '\\'

    $administratorsAccount = Get-WmiObject Win32_Group -filter "LocalAccount=True AND SID='S-1-5-32-544'"

    $administratorQuery = "GroupComponent = `"Win32_Group.Domain='" + $administratorsAccount.Domain + "',NAME='" + $administratorsAccount.Name + "'`""

    $user = Get-WmiObject Win32_GroupUser -filter $administratorQuery | select PartComponent |where {$_ -match "$domain"} |where {$_ -match "$userToFind"}

    $user

}

if (Test-Administrator) {

    Write-Host "Please run as a low privilege user for accurate results."

    Exit 1

}

function Is-Writable-Folder {

    param (

        [parameter(Mandatory=$True)] [string]$Folder

    )

    if (Test-Path "$Folder" -IsValid) {

        # folder exists

        $TestFile = "__test_PATH_$(get-date -f MM-dd-yyyy_HH_mm_ss).tmp"

        $TestFilePath = Join-Path -Path $Folder -ChildPath $TestFile

        Try {

            [io.file]::OpenWrite($TestFilePath).close()

            [io.file]::Delete($TestFilePath)

            return $true

        } Catch {

            return $false

        }

    } else {

        return $false

    }

}

$AllPaths = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path.Split(";")

$WritablePaths = @()

Foreach ($path in $AllPaths)

{

    Try {

        $path = $path.Trim()

        if ($path.Length -gt 0) {

           if (Is-Writable-Folder($path)) {

            $WritablePaths += $path

          }

        }

    } Catch {

        Write-Host "Error processing: '$path' - not a valid directory"

    }

}

If ($WritablePaths.count -eq 0) {

    Write-Host "No writable directories in system PATH found!"

} Else {

    Foreach ($path in $WritablePaths) {

        Write-Host "'$path' is writable!"

    }

}

Pause

 

 


Strong

5178 مدونة المشاركات

التعليقات