Modelar-e-deduzir: por que bug de lógica não cabe num template

A classe de bug que mais paga não tem forma fixa: é a violação de uma regra que só o alvo conhece. Por isso achá-la exige modelar o alvo antes de disparar o primeiro payload.

Um scanner de assinaturas faz uma pergunta só: "esse payload casa com algum padrão que eu já conheço?" É ótimo para o que tem forma fixa — um <script> refletido, um ' OR 1=1, um CVE com a versão vulnerável no banner. Mas a classe de bug que mais paga em bug bounty — IDOR, bypass de autenticação, falha de lógica de negócio — não tem forma fixa. Ela é a violação de uma regra que só existe dentro daquele alvo. E regra específica de alvo não cabe em template nenhum.

O teto do catálogo

Pense no que o scanner enxerga quando pede GET /api/invoices/1042 e recebe 200 OK. Para ele, é sucesso: rota viva, sem erro. Ele não tem como saber que a fatura 1042 é de outro cliente, nem que a sua conta jamais deveria vê-la. Não existe assinatura para "esse recurso pertence a outra pessoa" — a resposta é sintaticamente idêntica à legítima. O IDOR é invisível para quem só compara padrões.

Bug de lógica é a violação de uma invariante

Achar esse tipo de bug exige inverter o método. Em vez de disparar payloads e ver o que gruda, você primeiro reconstrói a superfície do cliente, infere as invariantes ("todo pedido tem dono", "o preço vem do servidor, nunca do corpo da requisição") e enumera a matriz de autorização inteira: quem pode fazer o quê, com qual objeto, em qual estado. Só então cada requisição vira um teste de hipótese — "e se o usuário A pedir o objeto de B?" — em vez de um chute no escuro.

A máquina de estados dos fluxos críticos

O ganho maior está nos fluxos de várias etapas: login com MFA, redefinição de senha, checkout. Eles são máquinas de estados — sequências de transições com pré-condições. O bug quase nunca está numa etapa isolada; está numa transição que não deveria existir.

Alguns exemplos concretos de classe:

  • Pular o segundo fator reaproveitando o token emitido antes do MFA — o servidor aceita porque tratou o estado "meio-autenticado" como "autenticado".
  • Redefinir a senha de outra conta porque o passo que amarra o token de reset ao e-mail roda depois do passo que já troca a senha.
  • Fechar a compra com quantidade negativa ou preço vindo do cliente, porque a invariante "total ≥ 0 e preço é do servidor" nunca foi verificada naquela transição.

Nenhum desses casos tem payload assinaturável. O que os revela é aprender o autômato do fluxo — por observação ou dirigindo o alvo dentro do escopo — e checar esse modelo contra as invariantes. Cada contraexemplo que a verificação devolve é, literalmente, um bypass deduzido: a máquina de estados admite um caminho que a regra proíbe. Dali se resolve o input exato que percorre esse caminho.

Deduzir gera muito candidato — por isso o juiz é código

O risco óbvio de raciocinar por modelo é o falso-positivo: um contraexemplo teórico que não se sustenta no alvo real. Por isso a proposta e o veredito são coisas separadas. Modelar-e-deduzir apenas propõe; quem julga é um firewall determinístico — dez gates, AutoReject e a confiança recomputada do zero antes de qualquer report. Se a evidência não fecha, o candidato morre. O default é matar. É isso que impede a criatividade do modelo de virar ruído — e report recusado.

O ponto

Scanner de template é um piso, não um teto. Ele limpa o barulho conhecido, e isso tem valor. Mas o bug que ninguém mais achou está na regra que só aquele alvo conhece — e você só chega nela depois de reconstruir o modelo do alvo, não antes de disparar o primeiro payload.

Essa inversão — modelar o alvo, deduzir o bug, deixar o código julgar — é o que a Omni Pentest executa de ponta a ponta, rodando no seu próprio VPS.