10 pontos por outsideris 2021-04-07 | Ainda não há comentários. | Compartilhar no WhatsApp

História de um estudante do último ano do ensino médio que, com tempo livre por causa da Covid, foi caçar bug bounties e recebeu US$ 35.000 por um bug bounty de páginas privadas do GitHub.

Ele reportou o bug bounty de páginas privadas do GitHub e havia dois bônus de CTF.

  • US$ 10.000: ler a flag em flag.private-org.github.io sem interação do usuário. Se for possível ler essa flag a partir de uma conta fora da organização private-org, há um bônus adicional de US$ 5.000.

  • US$ 5.000: ler a flag em flag.private-org.github.io com interação do usuário.

Fluxo de autenticação

Como o GitHub Pages é hospedado em um domínio separado, github.io, os cookies de autenticação de github.com não são enviados ao servidor de páginas privadas. Portanto, a autenticação de páginas privadas não consegue identificar o usuário sem integração adicional com github.com. Por isso, o GitHub criou um fluxo de autenticação personalizado.

  • Ao visitar uma página privada, o servidor verifica a existência do cookie __Host-gh_pages_token.

  • Se o cookie não existir ou for inválido, o servidor da página privada redireciona para https://github.com/login.

  • Esse redirecionamento também define um nonce no cookie __Host-gh_pages_session.

    • Como esse cookie usa o prefixo __Host-, ele impede que seja definido via JavaScript fora do domínio do host.
  • /login redireciona para /pages/auth?nonce=&page_id=&path=.

  • Ali, é criado um cookie de autenticação temporário que é passado no parâmetro token para https://pages-auth.github.com/redirect.

  • /redirect encaminha para https://repo.org.github.io/__/auth.

  • Esse endpoint final define os cookies de autenticação __Host-gh_pages_token e __Host-gh_pages_id no domínio repo.org.github.io.

  • Aqui, o nonce de __Host-gh_pages_session, definido anteriormente, também é verificado.

O caminho original da requisição e o ID da página são armazenados respectivamente nos parâmetros de query path e page_id, e o nonce também é armazenado no parâmetro nonce.

Exploração

Retorno CRLF

  • A primeira vulnerabilidade era uma injeção de CRLF no parâmetro page_id de https://repo.org.github.io/__/auth.

  • Foi descoberto que o parsing de page_id ignorava espaços em branco e que esse valor era definido diretamente no header Set-Cookie.

  • Era possível quebrar o parsing com uma injeção CRLF tradicional, mas sem outros impactos.

  • Como o header Location: vinha depois do header Set-Cookie, apesar de ser um redirecionamento 302 o header Location era ignorado e o corpo era renderizado.

Ataque

  • Ao olhar o código do GitHub Enterprise, ele descobriu que o servidor de páginas privadas era implementado com openresty nginx.

  • Ele conseguiu XSS adicionando um byte nulo. Como esse null byte precisava vir no início do body, não era possível fazer um ataque de injeção de header.

  • A partir daí, tornou-se possível executar código JavaScript arbitrário no domínio da página privada.

  • Agora só faltava encontrar uma forma de contornar o nonce.

Burlando o nonce

  • Pela observação, foi descoberto que páginas privadas irmãs da mesma organização podiam definir cookies umas para as outras.

  • Um cookie definido em private-org.github.io é enviado para private-page.private-org.github.io.

  • Se desse para contornar a proteção do prefixo __Host-, seria fácil burlar o nonce.

  • Nem todos os navegadores suportam isso, e o IE não suporta o prefixo __Host-.

  • Mas, ao procurar uma forma melhor, surgiu uma ideia interessante.

  • Ao verificar como os cookies tratavam maiúsculas e minúsculas, foi descoberto que __HOST e __Host eram tratados de forma diferente, e que o GitHub private pages ignorava letras maiúsculas ao fazer o parsing do cookie.

  • Assim, passou a ser possível definir o nonce via JavaScript.

  • Isso rendeu o bônus de US$ 5.000.

Envenenamento de cache

  • A resposta do endpoint /__/auth? é armazenada em cache pelo valor inteiro do page_id forjado.

  • Com isso, se fosse possível envenenar o cache por meio do payload de XSS, até usuários sem interação seriam afetados.

  • Se um atacante comprometer unprivileged.org.github.io para envenenar a autenticação, o payload de XSS fica em cache.

  • Como os cookies são compartilhados no domínio pai org.github.io, o atacante também consegue atacar privileged.org.github.io.

Páginas privadas públicas

  • Para receber o bônus de US$ 15.000, era necessário fazer esse ataque com um usuário que não pertencesse à organização.

  • Isso era possível por causa de uma configuração incorreta que ativava páginas privadas em um repositório público.

    • Ou seja, criar páginas em um repositório privado e depois mudar o repositório para público.
  • Nessas páginas privadas mal configuradas, todos os usuários entram no fluxo de autenticação, e usuários fora da organização passam a ter permissão de leitura.

Ainda não há comentários.

Ainda não há comentários.