Blaze Blog /

Ataque dos clones: Execução remota de código em clientes Git

FeaturedSecurity
Nov 5, 2020
4min read
Ilustração inspirada em Star Wars com os mascotes do Git e do GitHub

Introdução

Este post conta a história um tanto incomum de uma vulnerabilidade que poderia ser usada como um ataque à cadeia de suprimentos e atingir milhões de desenvolvedores de software ao redor do mundo. É também um relato de uma colisão de bugs que pagou uma recompensa a um pesquisador e atribuiu o CVE a outro!

O foco principal deste post é o GitHub Desktop. Outros clientes Git, como GitKraken, Git-Tower e SourceTree, também se mostraram vulneráveis, porém possuem cenários de exploração diferentes que exigem interação do usuário.

Breve descrição do problema

Como parte do processo padrão de clonagem de repositórios do GitHub Desktop, entre outras ações, ele chama o executável git-lfs.

Segundo a página oficial do git-lfs: "O Git Large File Storage (LFS) substitui arquivos grandes, como amostras de áudio, vídeos, conjuntos de dados e gráficos, por ponteiros de texto dentro do Git, enquanto armazena o conteúdo do arquivo em um servidor remoto como GitHub.com ou GitHub Enterprise."

O git-lfs é então chamado no repositório clonado atual, que já está presente no disco.

Uma vulnerabilidade foi descoberta ao clonar um repositório com um arquivo especialmente criado no diretório raiz. Ao clonar esse repositório malicioso, a execução de código é alcançada com os mesmos privilégios do usuário que está executando o GitHub Desktop.

Ao inspecionar o aplicativo desktop com o Process Monitor, notou-se que várias ações do git-lfs chamavam um executável git de dentro do repositório recém-clonado.

procmon

Ao colocar um git malicioso na raiz do repositório, um usuário que o clonar terá esse git malicioso executado pelo git-lfs, tudo isso nos bastidores e de forma transparente para o usuário.

O processo de clonagem ocorre normalmente e não há indicação visual de que um binário malicioso foi executado em vez do executável git original.

Análise da causa raiz

Tentamos entender a causa raiz dessa vulnerabilidade lendo o código do git-lfs. Os autores deste artigo reuniram o máximo de informações possível para compreender a origem do problema.

De https://github.com/git-lfs/git-lfs/blob/master/commands/command_clone.go

Da linha 23:

func cloneCommand(cmd *cobra.Command, args []string) {
requireGitVersion()
if git.IsGitVersionAtLeast("2.15.0") {
msg := []string{
"AVISO: 'git lfs clone' está obsoleto e não será atualizado",
" com novas flags do 'git clone'",
"",
"'git clone' foi atualizado no Git upstream para ter velocidades",
"comparáveis às do 'git lfs clone'.",
}
fmt.Fprintln(os.Stderr, strings.Join(msg, "\n"))
}

A função acima parece ser chamada quando uma ação de clone ocorre. Logo no início, a função chama requireGitVersion() e então verifica se a versão é pelo menos 2.15.0.

De https://github.com/git-lfs/git-lfs/blob/master/commands/commands.go

Linha 537:

func requireGitVersion() {
minimumGit := "1.8.2"
if !git.IsGitVersionAtLeast(minimumGit) {
gitver, err := git.Version()
if err != nil {
Exit("Erro ao obter a versão do git: %s", err)
}
Exit("É necessária a versão %s ou superior do Git para o Git LFS, sua versão: %s", minimumGit, gitver)
}
}

Ele chama !git.IsGitVersionAtLeast(minimumGit), que pode ser encontrado em https://github.com/git-lfs/git-lfs/blob/master/git/version.go

A partir da linha 28:

func IsGitVersionAtLeast(ver string) bool {
gitver, err := Version()
if err != nil {
tracerx.Printf("Erro ao obter a versão do git: %v", err)
return false
}
return IsVersionAtLeast(gitver, ver)
}

A função Version() pode ser encontrada no mesmo arquivo version.go na linha 18:

func Version() (string, error) {
gitVersionOnce.Do(func() {
gitVersion, gitVersionErr =
subprocess.SimpleExec("git", "version")
})
return gitVersion, gitVersionErr
}

A cadeia de chamada da função é a seguinte:
cloneCommand() -> requireGitVersion() -> IsGitVersionAtLeast() -> Version()

Podemos ver que na linha 21 do arquivo version.go, dentro da função Version(), há uma chamada para subprocess.SimpleExec() – que executa o binário do git com o argumento "version".

Existe uma suposição implícita do git-lfs de que, ao executar um binário externo, o sistema operacional primeiro o buscará na variável de ambiente PATH do sistema. Esta é a verdadeira causa raiz da vulnerabilidade.

Chamar o subprocesso 'git' funciona conforme o esperado no GitHub Desktop para MacOS. No Windows, no entanto, a ordem de busca favorece primeiro o diretório atual e só então pesquisa na ordem especificada no PATH.

Exploração

Ao copiar o calc.exe, renomeá-lo para git.exe e fazer o commit/push para a raiz do repositório, o atacante prepara o repositório malicioso que será usado posteriormente para explorar os usuários.

Quando um desenvolvedor clona este repositório usando o GitHub Desktop para Windows, seu subcomponente git-lfs trabalhará na pasta clonada como seu diretório atual, o que significa que todas as chamadas subsequentes para o binário 'git' estarão, na verdade, chamando o git.exe malicioso e não aquele presente no PATH.

github version 2
github where git is 1
cloning1 1
cloning2 1
pwned

Abaixo está um vídeo da exploração deste problema no GitHub Desktop para Windows:

Outros clientes

Durante nossa pesquisa, notamos o SourceTree

  • SourceTree
  • GitKraken

Créditos

A vulnerabilidade foi descoberta e pesquisada simultaneamente por Vitor Fernandes e Julio Fort da Blaze Information Security. O pesquisador independente Dawid Golunski (dobra robota, amigo!) aparentemente descobriu o problema alguns dias antes e o submeteu ao MITRE, enquanto Vitor o submeteu ao programa de bug bounty do GitHub.

Vitor recebeu a recompensa do programa do GitHub no HackerOne, já que seu relatório chegou antes e Dawid foi designado para o CVE.

Referências

[1] https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/path]
[2] https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc753427(v=ws.11)
[3] https://github.com/git-lfs/git-lfs/security/advisories/GHSA-4g4p-42wc-9f3m (Colisão com Dawid Golunski)

Do you have questions? Let's talk.

Get in touch with our cybersecurity experts

Read More