O Canal Canário: Quando um Cabeçalho do Cliente Escolhe seu Nível de Privilégio
O desafio
O app Android do ParcelPal pergunta ao backend o que pode fazer assim que abre, e informa em um cabeçalho a qual canal de lançamento pertence. Você tem a requisição de abertura em um repeater. O movimento óbvio é tentar os canais que a API admite conhecer, e isso não rende nada interessante: stable e beta devolvem praticamente a mesma configuração. O valor que você quer não está nessa lista. Leia com atenção o que o servidor devolve, porque um campo da resposta stable comum nomeia um canal que o cliente nunca pede, e esse canal recebe uma configuração de build destinada apenas a aparelhos internos. Envie a requisição com esse canal e envie a credencial que ele expõe.
O que você vai aprender
- Reconhecer uma resposta que varia conforme um cabeçalho controlado pelo cliente
- Ler uma resposta comum em busca de referências a variantes não óbvias
- Entender por que a lista de valores válidos de uma mensagem de erro não é definitiva
- Explicar por que um cliente não deve escolher seu próprio nível de privilégio
- Diferenciar uma credencial ativa de uma de teste pelo prefixo
Habilidades testadas
Pré-requisitos
- Leitura de requisição e resposta HTTP
- JSON básico
Como funciona
Apps mobile perguntam a um endpoint de configuração o que podem fazer, e geralmente se identificam ao fazer isso: uma versão, uma plataforma, um canal de lançamento. No momento em que o servidor muda a resposta com base em um desses valores, esse cabeçalho vira uma decisão de controle de acesso tomada pelo cliente, e o cliente está sob o controle do atacante.
A parte instrutiva deste caso é onde a pista está localizada. Envie um canal qualquer e a API retorna known: ["stable", "beta"], que parece uma enumeração dos valores válidos. Não é. É o conjunto de canais que o servidor está disposto a nomear. Tratar uma mensagem de erro como definitiva é assim que as pessoas concluem que não há nada ali e seguem em frente.
A referência real estava na primeira resposta, antes de qualquer adulteração: flags_manifest aponta para /v1/config?channel=canary. Ninguém classificou esse campo como sensível porque é só um caminho, mas ele nomeia o terceiro canal. Enviar canary retorna uma configuração de build com courier_debug_overlay ativado e um objeto debug contendo dispatch_api_key.
O prefixo pp_live_ é o que transforma isso de curiosidade em incidente. Essa é uma credencial de produção na configuração de um build interno, entregue a qualquer aparelho que reivindique o canal certo.
Erros comuns
- Confiar na lista do corpo de erro.
known: ["stable", "beta"]é o que o servidor admite, não o que ele serve. - Passar os olhos na resposta stable procurando algo com cara de segredo. A pista é um caminho, o campo com a cara menos interessante da página.
- Tentar forçar os nomes de canal por força bruta. Desnecessário. O nome é entregue a você na primeira resposta.
- Enviar o nome do canal como resposta. A resposta é a credencial que o canal expõe, não o canal.
- Mudar o cabeçalho Host durante os testes. A proteção retorna um 404 e parece que o endpoint caiu.
Como se proteger
O bug não é o canal canário. É o fato de um cabeçalho decidir qual configuração um chamador recebe.
- Obtenha o direito de acesso a partir da sessão autenticada ou de uma atestação de build assinada, nunca de um cabeçalho autodeclarado.
- Mantenha a configuração de build interna em um endpoint separado, protegido por autorização real, em vez de um valor na mesma forma de resposta.
- Não coloque credenciais em configuração entregue ao cliente de jeito nenhum. Qualquer coisa enviada a um aparelho é pública; em vez disso, faça o proxy da chamada de dispatch no servidor.
- Escaneie as respostas em busca de prefixos de credenciais ativas na CI. Uma string
pp_live_em qualquer payload acessível pelo cliente deve reprovar o build. - Evite vazar nomes de variantes em respostas públicas, e trate uma lista em uma mensagem de erro como uma decisão de design, não um acidente.