Skip to main content

Vulnerabilidade de dia zero de execução remota de código no Gitpod via WebSockets

Escrito por:
blog-feature-pypi-spoof

27 de fevereiro de 2023

0 minutos de leitura

TLDR

Este artigo descreve um projeto de pesquisa atual do Snyk Security Labs, voltado a ambientes de desenvolvimento baseados na nuvem (CDEs), que resultou na tomada total de um espaço de trabalho na plataforma Gitpod e se estendeu à conta SCM do usuário. Esses problemas foram divulgados de forma responsável ao Gitpod e foram resolvidos em um único dia útil.

Ambientes de desenvolvimento na nuvem e Gitpod

Conforme um número crescente de empresas começa a adotar ambientes de desenvolvimento baseados na nuvem para obter benefícios como maior desempenho, melhor experiência do desenvolvedor, ambientes de desenvolvimento consistentes e tempos de configuração reduzidos, foi impossível não considerar as implicações de segurança da adoção desses IDEs baseados na nuvem.

Antes, vamos oferecer uma breve visão geral da operação dos CDEs para entendermos a diferença entre o desenvolvimento baseado na nuvem e o desenvolvimento tradicional, baseado em estações de trabalho locais, e como isso altera o cenário de segurança dos desenvolvedores.

Ao contrário do desenvolvimento tradicional, os CDEs são executados em máquinas hospedadas na nuvem com um backend de IDE. Geralmente, é oferecida uma versão web do IDE e suporte à integração com um IDE instalado localmente via SSH, oferecendo aos usuários uma experiência fluida e familiar. Ao usar um CDE, o código da organização e eventuais serviços de suporte, como um banco de dados de desenvolvimento, são hospedados na nuvem. Confira no diagrama a seguir uma representação visual do fluxo de informações em um CDE.

blog-websocket-takeover-cde-diagram

Os riscos de segurança dos ambientes de desenvolvimento instalados localmente não são novidade. No entanto, historicamente, não receberam muita atenção dos desenvolvedores. Em maio de 2021, a Snyk divulgou extensões vulneráveis do VS Code que levaram a um vazamento de dados ou execução arbitrária de comandos com um clique. Esses ambientes de desenvolvimento tradicionais, baseados em estações de trabalho, como uma instância local do VS Code ou IntelliJ, apresentam outras preocupações de segurança da informação, incluindo falhas de hardware, segurança de dados e malware. Essas questões podem ser abordadas usando criptografia completa de discos, controle de versões, backups e sistemas antimalware. No entanto, muitas perguntas sobre a adoção de ambientes de desenvolvimento baseados na nuvem continuam sem resposta: 

  • O que acontece quando um espaço de trabalho de IDE na nuvem é infectado com malware?

  • O que acontece quando os controles de acesso são insuficientes e permitem acessar espaços de trabalho de outros usuários e até mesmo outras organizações?

  • O que acontece quando um desenvolvedor malintencionado extrai a propriedade intelectual da empresa de uma máquina hospedada na nuvem, fora da visibilidade do software de prevenção de perda de dados ou de segurança de endpoints da organização?

Em um projeto de pesquisa de segurança atual realizado aqui na Snyk, examinamos as implicações de segurança da adoção de IDEs baseados na nuvem. Neste artigo, apresentamos um estudo de caso de uma das vulnerabilidades descobertas durante nossa exploração inicial na plataforma Gitpod. 

Exame da plataforma Gitpod

Aviso: quando decidimos analisar soluções de IDE na nuvem para nossa pesquisa, optamos por soluções auto-hospedadas ou baseadas na nuvem de fornecedores com políticas de segurança claramente definidas que oferecem um porto seguro para os pesquisadores. 

Um dos CDEs mais populares é o Gitpod. Com uma ampla adoção e um abrangente conjunto de recursos (incluindo backups automatizados, integração com Git pronta para uso e vários backends de IDE), o Gitpod garantiu sua presença entre os primeiros produtos que analisamos.

A primeira etapa da nossa pesquisa foi conhecer os fluxos de trabalho básicos do Gitpod, configurar uma organização e experimentar o produto. Para observar as várias APIs e transações, usamos o Burp Suite para capturar o tráfego. Em seguida, acessamos o código-fonte do Gitpod no GitHub para estudar o funcionamento interno das APIs e revisamos toda a documentação relevante sobre a arquitetura para entender melhor cada um dos componentes e suas funções. Este vídeo que oferece uma descrição detalhada inicial da arquitetura do Gitpod foi um ótimo recurso. Resumindo, o Gitpod usa vários microsserviços implantados em um ambiente do Kubernetes, onde cada espaço de trabalho de usuário é implantado em um pod efêmero dedicado. 

O principal conjunto de componentes externos do Gitpod está relacionado ao painel, à autenticação e à criação e gerenciamento de espaços de trabalho, organizações e contas. Essencialmente, o principal componente é adequadamente chamado de servidor (server), um aplicativo TypeScript que expõe uma API de JSONRPC via WebSocket, que por sua vez é consumida por um frontend React chamado painel (dashboard). 

No painel, é fácil integrar um provedor de SCM, como GitHub ou Bitbucket, para importar um repositório e iniciar um ambiente de desenvolvimento, que disponibiliza o código-fonte e um ambiente Git funcional. Após o provisionamento, o espaço de trabalho pode ser acessado via SSH e HTTPS em um subdomínio de gitpod.io (ou seja, https://[WORKSPACE_NAME].[CLUSTER_NAME].gitpod.io) por meio do componente ws-proxy, baseado em Golang. 

A vulnerabilidade de segurança descoberta em nossa pesquisa está relacionada principalmente ao componente servidor e ao JSONRPC servido por uma conexão via WebSocket que, por fim, possibilitou a tomada de controle do espaço de trabalho no Gitpod.

Detalhes técnicos

WebSockets e a política de mesma origem

O WebSocket é uma tecnologia que permite comunicação bidirecional em tempo real entre um cliente (normalmente, um navegador) e um servidor. Ele estabelece uma conexão persistente entre o cliente e o servidor para permitir a transferência contínua de dados em tempo real, sem precisar repetir solicitações HTTP. 

Do ponto de vista de segurança, um aspecto interessante dos WebSockets é que um mecanismo de segurança de navegador, a política de mesma origem (SOP), não se aplica. Esse controle de segurança impede um site de emitir uma solicitação AJAX para outro site e ler a resposta. Se isso fosse possível, seria uma preocupação de segurança, já que os navegadores costumam enviar cookies junto com todas as solicitações (mesmo para solicitações de origem cruzada, como ataques relacionados a CSRF). Sem a SOP, qualquer site seria capaz de enviar solicitações para sites externos e obter seus dados de outros domínios.

Isso nos leva à classe de vulnerabilidades conhecida como sequestro de WebSocket entre sites. Esse ataque é semelhante a uma combinação de falsificação de solicitação entre sites e erro de configuração de CORS. Quando um handshake de WebSocket depende exclusivamente de cookies HTTP para autenticação, um site malicioso pode iniciar uma nova conexão WebSocket com o aplicativo vulnerável, permitindo que o invasor envie e receba dados através da conexão.

Nas revisões de aplicativos com conexões WebSocket, sempre vale a pena verificar detalhadamente essa possibilidade. Vamos examinar a solicitação de WebSocket para o servidor do Gitpod.

blog-websocket-takeover-gitpod.io-upgrade
blog-websocket-takeover-switching-protocols-feb-9

Em circunstâncias normais, a conexão é atualizada para um WebSocket e a comunicação começa. Não houve nenhuma autenticação adicional na troca por WebSockets em si. O JSONRPC pode ser invocado pela conexão WebSocket.

blog-websocket-takeover-jsonrpc-2.0

Até o momento, não encontramos nenhuma autenticação adicional no canal estabelecido, o que é um bom sinal para possíveis invasores. Agora, vamos conferir a ocorrência de verificações adicionais de Origin. Para isso, adulteramos o cabeçalho Origin de um handshake que observamos.

blog-websocket-takeover-origin-workspace-id
blog-websocket-takeover-switching-protocols-feb-12

Parece promissor. Aparentemente, o domínio evil.com consegue enviar solicitações de WebSocket entre origens para gitpod.io. No entanto, outro mecanismo de segurança apresenta um desafio.

Ignorar cookie SameSite

Os cookies SameSite são uma adição relativamente recente que oferece mitigação parcial contra ataques de falsificação de solicitação entre sites (CSRF). Embora não adotado por todos, a maioria dos navegadores comuns definiu Lax como o valor padrão para todos os cookies que não desativam explicitamente o SameSite. Portanto, embora a vulnerabilidade subjacente esteja presente, se os cookies SameSite não forem ignorados, nosso ataque seria em grande parte teórico e funcionaria apenas com um subconjunto de navegadores desatualizados e de nichos específicos.

Então, o que é um site no contexto do SameSite? Simplificando, o site corresponde a uma combinação entre esquema e domínio registrável (se houver) do host de origem. Se examinarmos as especificações do SameSite, veremos que os subdomínios não são considerados. Isso é menos rigoroso do que a especificação de uma origem usada pela política de mesma origem, que consiste em esquema + host (incluindo subdomínios) + porta (por exemplo: https://security.snyk.io:8443).

blog-websocket-takeover-url-breakdown

Já vimos antes que o espaço de trabalho é exposto por um subdomínio em gitpod.io. No contexto do SameSite, o URL do espaço de trabalho é considerado como sendo o mesmo site gitpod.io. Portanto, deve ser possível que um espaço de trabalho envie uma solicitação SameSite entre domínios para um domínio *.gitpod.io com os cookies originais do usuário anexados. Vamos ver se conseguimos usar um espaço de trabalho controlado por um invasor para servir um conteúdo de sequestro de WebSocket. 

Primeiro, para verificar se os cookies são realmente transmitidos e se a comunicação WebSocket é realizada, vamos abrir o console do navegador de um espaço de trabalho e tentar iniciar uma conexão WebSocket.

blog-websocket-takeover-gitpod-outline-cropped

Como podemos ver na captura de tela acima, tentamos abrir uma nova conexão WebSocket e, após a abertura, enviamos uma solicitação de JSONRPC. A saída do console mostra que uma mensagem foi recebida com o resultado da nossa solicitação, confirmando que os cookies são enviados e a origem está autorizada a abrir um websocket para gitpod.io.

Agora, precisamos encontrar uma forma de, a partir do espaço de trabalho, servir um código JavaScript que possa ser acessado por um usuário do Gitpod. Analisando os recursos disponíveis, é possível expor portas no espaço de trabalho e permitir o acesso a elas usando o gitpod-cli, uma ferramenta de linha de comando que está disponível no caminho: é só digitar gp. Podemos invocar gp ports expose 8080 e configurar um servidor web Python básico usando python -m http.server 8080. Por sua vez, isso cria um novo subdomínio onde a porta exposta pode ser acessada, como mostrado a seguir.

blog-websocket-takeover-consol-error

No entanto, a conexão falhou. Isso é um tanto preocupante e exige mais investigação. Aqui, abrimos o código-fonte e começamos a buscar a possível causa do problema. Encontramos o seguinte padrão de expressão regular, que aparentemente é usado para extrair o nome do espaço de trabalho do URL.

blog-websocket-takeover-base-workspace-id

A maneira como essa correspondência é realizada causa a extração incorreta do nome do espaço de trabalho, como demonstrado nesta captura de tela:

blog-websocket-takeover-test-string

Portanto, parece que não podemos servir nosso conteúdo a partir de uma porta exposta dentro do espaço de trabalho hospedado pelo Gitpod e precisamos encontrar outra maneira. Até agora, já sabemos que temos acesso privilegiado a uma máquina que executa o serviço VS Code e atende a solicitações enviadas para o URL do nosso espaço de trabalho. Como podemos abusar disso de alguma forma?

A ideia inicial era encerrar o processo vscode e iniciar um servidor web Python para servir um arquivo HTML. Infelizmente, isso não funcionou e o espaço de trabalho foi reinicializado. Ao que parece, isso foi feito por um serviço supervisor local. Durante o teste dessa abordagem, notamos que, quando encerramos o processo sem vincular outro à porta do VS Code, o serviço supervisor reiniciava automaticamente o processo vscode, causando em uma breve interrupção da interface do usuário sem uma reinicialização completa do espaço de trabalho.

Tivemos uma ideia promissora. Podemos aplicar um patch ao VS Code para servir um exploit incorporado?

Foi relativamente fácil aplicar um patch ao VS Code. Comparando o código-fonte original do servidor do VS Code com a versão distribuída, encontramos em pouco tempo um local conveniente para servir o exploit.

O VS Code contém um endpoint de API em /version, que retorna a confirmação da versão atual:

blog-websocket-takeover-pathname-version

Modificamos o endpoint para retornar o Content-Type correto de text/html e o conteúdo de um arquivo HTML. Agora, encerramos o processo vscode para que as alterações que acabamos de fazer fossem carregadas em uma nova instância do processo do VS Code:

blog-websocket-takeover-template-python

Por fim, podemos usar os métodos getLoggedInUser, getGitpodTokens, getOwnerToken e addSSHPublicKey do JSONRPC para criar um conteúdo que nos conceda controle total sobre os espaços de trabalho do usuário quando um usuário desavisado do Gitpod acessa nosso link.

Veja isso em ação:

blog-websocket-takeover-pwnpod-info

Como podemos ver, conseguimos extrair algumas informações confidenciais sobre a conta do usuário e fomos notificados de que nossa chave SSH foi adicionada à conta. Vamos ver se conseguimos uma conexão SSH com o espaço de trabalho:

blog-websocket-takeover-task-list-redacted

Missão concluída. Como mostrado acima, temos acesso total aos espaços de trabalho do usuário depois que ele visitou um link que enviamos.

Cronograma

  • Segunda-feira, 13 de fevereiro de 2023: vulnerabilidade revelada ao fornecedor

  • Segunda-feira, 13 de fevereiro de 2023: fornecedor reconhece a vulnerabilidade

  • Terça-feira, 14 de fevereiro de 2023: nova versão lançada e implantada na instância de produção de SaaS do Gitpod

  • Terça-feira, 22 de fevereiro de 2023: CVE-2023-0957 atribuída

  • Quarta-feira, 1º de março de 2023: fornecedor lança nova versão do Gitpod Self-Hosted e emite um aviso

Resumo

Neste post, apresentamos as primeiras descobertas da nossa pesquisa atual sobre ambientes de desenvolvimento na nuvem (CDEs). Nesses ambientes, o acesso a um link, a exploração de uma vulnerabilidade geralmente incompreendida (sequestro de WebSocket) e o uso de um desvio prático de cookies SameSite permitiram a tomada total de uma conta. Com a crescente popularidade de espaços de trabalho de desenvolvedores na nuvem, é importante considerar os riscos adicionais apresentados por eles.

Gostaríamos de parabenizar o Gitpod por sua resposta rápida e eficaz na abordagem dessa vulnerabilidade de segurança. Esperamos apresentar mais descobertas sobre soluções de desenvolvimento remoto baseadas na nuvem em um futuro próximo.