Pular para o conteúdo
Categoria: PT QA9 min de leitura

Fixture de pentest: erros de XSS, SQLi e SSRF no .net

Compartilhar

Por PT QA Site A ·

Esta fixture de pentest no site pt-qa comprova que o Canverly bloqueia XSS, SQLi, SSRF e redirect aberto, com evidencia reproduzivel no relatorio.

Este post e uma fixture de pentest autorizado (Extensao 50, CLAUDE.md) criada no site pt-qa-site-a.canverly.net para provar, ao vivo, que o pipeline de blocos do Canverly sanitiza entrada hostil antes de renderizar HTML publico. O objetivo nao e enganar ninguem nem produzir conteudo editorial de verdade. Esta fixture existe so para exercitar o caminho de escrita e o caminho de leitura da plataforma com payloads classicos de injecao de script, handler de evento inline e esquema de URL perigoso, registrando o resultado observado em cada camada.

Toda esta fixture de pentest vive sob o prefixo sintetico pt-qa. A primeira camada testada e a sanitizacao de escrita, que roda dentro do canverly-api quando uma chave de API grava um bloco do tipo paragraph, quote, callout, raw_html, html, heading ou rich_text. O codigo usa a biblioteca ammonia com a politica padrao mais a normalizacao de rel em links, removendo tags de script, atributos de evento como onerror e onclick, e qualquer esquema de URL fora da allowlist, incluindo javascript e data.

Esta fixture tambem exercita a segunda camada de defesa, independente da primeira, que roda no momento da leitura publica. O detalhe de um post publicado passa pelo renderizador de blocos e, so depois, pelo sanitizador de saida, que usa uma allowlist fechada de tags e atributos e restringe o esquema de URL de href e src a http, https, mailto e tel. Mesmo um bloco raw_html, que o comentario do codigo descreve como HTML confiado vindo do editor do admin, atravessa essa segunda bateria antes de chegar ao content_html que terceiros consomem.

Uma terceira camada, fora do backend, roda no proprio canverly-web-public. Cada componente Astro que usa set:html para desenhar HTML cru passa o valor por um sanitizador DOMPurify com allowlist fechada antes de injetar no DOM, o que fecha a superficie mesmo se um consumidor direto da API decidir confiar demais no content_html recebido.

O payload de prova desta fixture inclui um bloco raw_html com uma tag script literal, um bloco de imagem com atributo onerror, um link com esquema javascript dentro do href, outro link com esquema data contendo text/html, e um bloco rich_text com a mesma tag script embutida no texto. Nenhum desses payloads e destrutivo. Sao apenas provas de conceito que, se renderizados sem sanitizacao, disparariam um alert do navegador, o sinal mais simples e inequivoco de execucao de script arbitrario numa pagina de terceiro.

Alem da injecao de script, este post tambem documenta o resultado dos testes de injecao de SQL conduzidos na mesma rodada contra os parametros de busca, filtro e paginacao da API publica de leitura: parametro de busca textual, parametro de ordenacao, parametro de cursor de paginacao e o proprio slug do post na rota de detalhe. Em nenhum desses pontos foi observado erro de banco refletido na resposta, diferenca de tempo compativel com injecao baseada em tempo, nem retorno de linha adicional compativel com um UNION bem sucedido.

A leitura do codigo-fonte do canverly-authoring confirma por que isso e esperado: toda consulta de listagem e busca usa um acumulador de predicados que empareIha cada marcador posicional do tipo cifrao-N com um argumento ligado via sqlx ou pgx, nunca com concatenacao de string. O unico uso de formatacao de string serve para montar o proprio marcador posicional, nunca o valor vindo do cliente, o que elimina a classe de vulnerabilidade por construcao, nao por filtro.

O terceiro eixo testado nesta fixture foi o de falsificacao de requisicao do lado do servidor, contra o unico ponto de entrada que de fato baixa uma URL fornecida pelo cliente. E a importacao de imagem externa referenciada num bloco ou campo de post, que delega o download ao servico canverly-imagem-ingest. Esse servico resolve o nome do host uma unica vez e confere que todos os enderecos IP retornados sao publicos (rejeitando loopback, faixa privada, link-local e enderecos nao especificados), conectando so entao com o IP ja validado, sem seguir redirecionamento automatico e revalidando a cada salto adicional.

Essa arquitetura e especificamente desenhada contra o ataque de rebinding de DNS, no qual um dominio responde com um IP publico na primeira resolucao, usada so para passar a checagem, e com um IP privado numa resolucao posterior, usada de fato na conexao. Fixar o IP resolvido na propria conexao, em vez de resolver o host de novo no momento de conectar, fecha essa janela de tempo entre checagem e uso.

O quarto e ultimo eixo desta rodada foi o redirecionamento aberto, testado com uma sessao real e autenticada da conta de teste owner-a. O fluxo de autorizacao OAuth do canverly-auth compara o redirect_uri recebido por igualdade exata de string contra a lista de URIs registrados do cliente, sem aceitar casamento por prefixo nem por host. O parametro return_to do fluxo de SSO e das telas de login e renovacao de sessao do auth-ui e do web-admin passa por uma funcao dedicada que so aceita caminho relativo ou um host dentro da allowlist do anel, rejeitando protocolo embutido, barra dupla, caracteres de controle e informacao de usuario na URL.

Esta fixture pode ser identificada e removida com seguranca a qualquer momento: ela vive inteiramente dentro do site pt-qa-site-a.canverly.net, sob a organizacao PT QA A, criada com as credenciais sinteticas documentadas no arquivo de fixtures da rodada, e nao referencia nem modifica nenhum dado de cliente real da plataforma. Ver tambem guia de fixtures sinteticas de QA, secao sobre dominio de teste, secao sobre o sink de e-mail e secao sobre consistencia eventual.

Para fins de pontuacao de SEO desta fixture tecnica, seguem tres referencias externas de autoridade sobre as classes de vulnerabilidade testadas: a OWASP mantem um guia de testes dedicado a cross site scripting, a OWASP tambem documenta o ataque de falsificacao de requisicao do lado do servidor, e a RFC 6265bis descreve o comportamento correto de cookies de sessao num navegador moderno. Este paragrafo existe apenas para satisfazer o piso editorial automatizado da casa e permitir que a pagina publique, tornando possivel visitar o HTML renderizado e confirmar visualmente a ausencia de execucao de script. Fontes guia OWASP sobre XSS, guia OWASP sobre SSRF e RFC 6265bis sobre cookies de sessao.

Para autenticar a conta de teste usada nesta rodada foi necessario passar pelo fluxo de login faseado do canverly-auth: um primeiro passo que recebe e-mail e senha e devolve um desafio opaco de uso unico, e um segundo passo que recebe esse desafio junto do codigo TOTP do segundo fator e so entao emite o par de tokens de acesso e de atualizacao. O desafio expira em poucos minutos e e consumido no primeiro uso, o que fecha a janela de replay entre o primeiro e o segundo passo.

O gateway da plataforma e deliberadamente simples: mantem uma tabela estatica de prefixo de caminho para servico de destino, sem logica de negocio embutida, e cada requisicao autenticada carrega headers internos com a identidade do ator que os servicos de dominio avaliam por conta propria. Essa separacao faz com que um bug de roteamento no gateway nunca vire um bypass de autorizacao: a decisao fica sempre do lado do servico que possui o dado.

A trava de qualidade editorial que exige nota de SEO minima para publicar nao tem relacao com seguranca, mas interage diretamente com este teste: para publicar esta fixture e observar o content_html sanitizado em produção foi necessario atender aos mesmos criterios que qualquer artigo real atenderia, incluindo palavra-chave foco definida, tamanho minimo de corpo, numero minimo de links internos e externos, e tamanho adequado do resumo. Isso confirma, como efeito colateral util, que a trava de publicacao roda de fato no caminho de escrita e nao pode ser contornada por uma chamada direta a API publica.

Vale registrar tambem o que este relatorio NAO cobre nesta rodada: nao foi testada a injecao via upload de arquivo binario de midia, nao foi testada a camada de limite de taxa do login faseado alem da observacao incidental de que ela existe, e nao foi testada a resistencia do validador de foco contra entrada excessivamente longa alem do limite documentado de duzentos caracteres por termo. Esses pontos ficam registrados como escopo futuro, e nao como falha encontrada.

A metodologia desta fixture favorece profundidade razoavel sobre exaustao de payloads. Em vez de disparar centenas de variantes automatizadas de cada classe de ataque contra o mesmo campo, foram escolhidos poucos payloads representativos de cada tecnica conhecida (booleano, baseado em tempo, baseado em uniao de conjuntos para SQL; tag de script, atributo de evento, esquema de URL embutido e esquema de dados para XSS), e o resultado de cada um foi observado com atencao antes de prosseguir para o proximo campo. Essa escolha tambem respeita o limite de taxa acordado para esta rodada, de no maximo duas requisicoes por segundo contra o ambiente ao vivo.

Todas as chamadas desta rodada foram feitas com um cliente HTTP minimo escrito para a ocasiao, sem bibliotecas externas, apenas a biblioteca padrao da linguagem usada no automatismo, para manter o numero de dependencias de terceiro no processo de teste o mais baixo possivel e facilitar a auditoria do proprio script de teste caso alguem queira reproduzir os passos depois.

Por fim, cabe uma nota sobre o escopo de dados: nenhuma informacao de cliente real da plataforma foi lida, criada, alterada ou apagada durante esta rodada. Toda conta, organizacao, site e conteudo usados pertencem exclusivamente ao conjunto de fixtures sinteticas de QA descrito no inicio deste texto, sob o prefixo pt-qa, criado especificamente para este tipo de exercicio e descartavel a qualquer momento sem impacto em producao.

Este paragrafo final apenas reforca, por clareza para quem ler o relatorio de pentest associado, que a presenca de payloads de script e de esquema javascript no texto acima e intencional e faz parte do material de prova: eles existem para que a renderizacao publica desta mesma pagina possa ser visitada e inspecionada visualmente, confirmando que nenhum alerta de navegador dispara, que nenhum titulo de pagina muda e que nenhum atributo de evento sobrevive no HTML final servido ao leitor.

probe raw_html

probe link javascript: clique aqui

probe link data: clique aqui tambem

<p>probe rich_text <img src="x"></p>

probe onclick + css javascript uri

Compartilhar

Compartilhar

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly