No Vuln — empresa brasileira de pentest e auditoria de segurança ofensiva
Voltar ao blog

A cadeia de 7 'cliques' que tomou conta admin de um SaaS sem login (war story 2026)

Pentest recente em SaaS B2B brasileiro estabelecido — 7 falhas pequenas encadeadas viraram tomada total de admin a partir de zero (sem usuário, sem senha).

Vulnerabilidade·9 de junho de 2026·12 min de leitura
Diego Melo — autor
Diego Melo

Pesquisador de segurança e fundador da No Vuln

A cadeia de 7 'cliques' que tomou conta admin de um SaaS sem login (war story 2026)

Imagina abrir a internet, ir até o endereço do seu SaaS, e — sem ter login, sem ter senha, sem clicar em “esqueci minha senha”, sem ter conta nenhuma na sua plataforma — em 5 minutos se tornar o administrador master da sua aplicação. Lendo todos os dados de todos os seus clientes. Editando contratos. Mudando configurações. Trocando senhas.

Foi exatamente isso que encontramos em pentest recente de um SaaS B2B brasileiro estabelecido, com base ativa de centenas de clientes e milhões em ARR. A cadeia tem 7 elos. Cada elo, sozinho, parece pequeno. Em sequência, viram catástrofe.

Esse post é a análise técnica anonimizada do que aconteceu — porque os 7 elos se repetem em SaaS B2B brasileiro com uma frequência preocupante. Se você opera uma plataforma web, vale leitura.

O cenário (anonimizado)

  • Aplicação: SaaS B2B em produção, base ativa, contratos enterprise
  • Stack: PHP + Adianti Framework (framework brasileiro popular em ERPs e plataformas administrativas)
  • Banco: MySQL multi-tenant
  • Infra: servidor compartilhado, PHP 8.x, Apache
  • Severidade consolidada do engagement: 53 achados 12 críticos, 17 altos, 8 médios, 9 baixos, 7 informativos

O cliente já havia passado por outras auditorias antes. “Estava limpo”, segundo eles. Em pesquisa adversarial focada, encontramos 53 vulnerabilidades distintas. Esse post foca em um dos 12 críticos: a cadeia de 7 elos que vira ATO admin master pre-auth. Outros achados críticos serão tema de posts próprios.

A cadeia em 1 minuto

#EloSeveridade isoladaFunção na cadeia
1Serviço de upload de arquivos acessível sem autenticaçãoMédioPorta de entrada
2Validação de extensão fraca (aceita .phar)MédioEngana o filtro
3Diretório de upload dentro do webroot + execução PHP permitidaMédioPermite executar o que subiu
4Arquivo application.ini legível pelo processo webAltoExpõe segredos
5Hash de senhas em MD5 sem saltAltoPermite forjar credencial
6API REST validando token por segredo compartilhado (não JWT assinado)MédioPossibilita criar sessão admin
7Sessão PHP baseada em filesystem, sem rotação de ID em loginMédioSequestro de sessão admin

Cada linha é “média” isolada. Combinadas Crítica catastrófica.

A história, passo a passo

Elo 1 — A porta dos fundos sem chave

A primeira descoberta foi um endpoint:

POST /engine.php?class=AdiantiUploaderService

O Adianti Framework expõe certas classes como “públicas” via um arquivo de configuração. O time de desenvolvimento marcou o serviço de upload como público — provavelmente para permitir upload de avatar em signup. Resultado: qualquer pessoa na internet podia fazer upload de arquivos pra dentro do servidor. Sem login. Sem token. Sem nada.

O equivalente físico: uma porta nos fundos do escritório, sem fechadura, e ninguém olhando.

Elo 2 — O filtro que filtra mal

O serviço validava a extensão do arquivo enviado. Bloqueava .php. Mas aceitava .phar — Phar é um formato de arquivo PHP que serve como executável empacotado. O servidor não diferenciava.

O equivalente físico:a porta dos fundos tinha um cartaz “proibido entrar de tênis”, mas aceitava sandália. Mesmo problema, vestido diferente.

Elo 3 — A pasta onde tudo executa

O upload caía em /var/www/html/tmp/. Por padrão do Apache, tudo nessa pasta podia ser executado como PHP — incluindo o .phar que acabamos de subir.

Resultado: o atacante sobe um arquivo, depois acessa esse arquivo pela URL, e o servidor roda o código que ele escreveu.

1. POST /engine.php?class=AdiantiUploaderService   ← sobe payload.phar
2. GET  /tmp/payload.phar                           ← servidor executa
3. Atacante agora roda comandos no servidor        ← RCE confirmado

Tradução pra leigo: o atacante agora roda código no seu servidor como se fosse seu próprio servidor.

Elo 4 — O cofre de segredos sem porta

Com RCE em mãos, o atacante lê o arquivo de configuração da aplicação:

[general]
seed = "abc123def456..."           ← usado pra assinar tokens
rest_key = "789xyz..."             ← chave pra API REST
db_password = "..."

Esses segredos deveriam ficar protegidos. Mas o processo PHP que serve o site tem permissão de leitura nesse arquivo (precisa, pra rodar). Como o atacante agora roda como o processo PHP, lê tudo.

Tradução pra leigo: o intruso achou o caderninho do dono da empresa, com todas as senhas anotadas.

Elo 5 — Senhas que viraram açúcar molhado

O hash das senhas no banco usava MD5 sem salt. MD5 é algoritmo de hash de 1992 — quebrado para uso em senhas desde ~2010. Sem salt, qualquer senha comum aparece em rainbow tables (tabelas pré-computadas) em segundos.

Pior: com a “seed” do application.ini em mãos, o atacante consegue forjar a senha do admin diretamente sem precisar quebrar nada. Conhece o algoritmo + tem a chave = consegue inventar o hash que quiser.

Tradução pra leigo: as senhas dos seus usuários estavam guardadas com um cadeado de bicicleta dos anos 90. Qualquer um abre.

Elo 6 — A API que confiava no segredo compartilhado

A aplicação tinha uma API REST autenticada por segredo compartilhado(não por JWT assinado, não por OAuth — só “manda o segredo certo, eu confio”). Com o rest_key em mãos (vazado no elo 4), o atacante chama a API como se fosse o servidor falando com ele mesmo.

A API permite criar uma sessão de admin — porque é o jeito que o admin master entra. Atacante agora tem um session_id válido de admin master.

Tradução pra leigo:o intruso achou a senha do interfone interno da empresa, ligou pra recepção, e disse “manda a chave-mestra aqui pro meu apartamento”. A recepção mandou.

Elo 7 — A sessão que não rotaciona

O atacante pega o session_id recém-criado e cola num navegador anônimo. Como a aplicação não rotaciona o ID de sessão entre login e estado autenticado, o ID criado pela API serve direto no navegador.

Atacante recarrega a página → está dentro como admin master. Lê todos os dados. Cria contratos falsos. Apaga registros. Tudo que o admin master pode fazer, ele pode.

Tradução pra leigo: a credencial que ele forjou no telefone funcionou direto na catraca. Sem perguntas.

O impacto se explorado por atacante real

Estimativa que apresentamos pro cliente:

  • Vazamento de dado pessoal sensível (LGPD Art. 5º + Art. 11) de toda a base de clientes
  • Multa LGPD potencial: até 2% do faturamento ou R$ 50M por incidente (cap)
  • Quebra de contratos enterprise: SLA, DPA, cláusulas de segurança
  • Comunicação obrigatória à ANPD em prazo razoável (interpretado em ~7 dias úteis)
  • Comunicação aos titulares afetados (toda a base)
  • Churn pós-incidente: 4 em cada 10 consumidores brasileiros não voltam após incidente (Akamai, 2024)
  • Custo de resposta: equipe de incidente, advocacia, comunicação, forense, retenção de cliente
  • Reputação: anos de recuperação

A cadeia foi reportada, validada com PoC reproduzível em 10 passos (Postman collection), e corrigida pelo cliente em ~72h. Nunca foi explorada por atacante real, pelo que se sabe.

Por que isso passou batido em auditorias anteriores

3 motivos práticos:

1. Scanner não monta cadeia

Cada elo isolado é médio— ou seja, scanner automatizado geraria 5 alertas “médios” desconectados, que o time provavelmente despriorizaria (“temos coisa pior pra resolver”). Nenhum scanner conecta “upload sem auth” + “extensão .pharaceita” + “execução no webroot” + “config.ini legível” + “MD5 sem salt” + “API REST com segredo compartilhado” + “sessão não rotaciona” e diz “isso vira ATO admin”.

2. Auditoria de checklist olha por categoria, não por chain

Auditorias estilo “ISO 27001 controls check” olham se a empresa tem controles em cada categoria, não se os controles encadeados sobrevivem a um atacante criativo. Resultado: empresa marcaria 90% dos checks como verde e ainda assim teria a chain ativa.

3. Adianti Framework expõe muito por default

Adianti tem padrões legados (de 2014–2018) que faziam sentido pra ERPs em rede interna. Em SaaS multi-tenant exposto na internet pública em 2026, esses defaults viram superfície de ataque. Quem não sabe que “AdiantiUploaderService público sem auth” é vulnerabilidade, não procura. Adianti tem milhares de instalações brasileiras com esses mesmos defaults.

Como auditar você mesmo (10 minutos)

Se sua plataforma usa Adianti (ou qualquer framework PHP), valide os 7 elos:

  1. Lista todas as classes “públicas” do seu framework. Quais são acessíveis sem autenticação? Cada uma é porta de entrada potencial.
  2. Para serviços de upload: valide extensões em allowlist (não blocklist). Inclua .phar, .phtml, .pht, .svg, .html na blocklist explícita.
  3. Diretório de upload: está fora do webroot? Se dentro, execução PHP está desabilitada (.htaccess ou nginx config)?
  4. Arquivos de configuração: application.ini / .env / config.php — qual a permissão? Quem pode ler? Se PHP web pode ler, atacante com RCE pode ler.
  5. Hash de senhas: está usando password_hash() (PHP nativo, bcrypt/argon2)? Ou MD5/SHA1?
  6. APIs internas: autenticação é por JWT assinado ou segredo compartilhado? Se compartilhado, vaza junto com config.
  7. Sessões: seu framework rotaciona session_id em cada mudança de estado de auth? PHP nativo NÃO rotaciona por default — precisa session_regenerate_id(true).

Cada item leva ~1-2 minutos pra verificar. Se 3+ estão vulneráveis, você está exposto a essa categoria de chain.

A lição mais importante

A diferença entre o time vulnerável e o time seguro não é talento. É processo de validação adversarial:

  • Code review focado em chains, não em bugs isolados
  • Pentest periódico que valida o “como” o atacante encadeia
  • Atualização de defaults legados de framework
  • Testes automatizados que validam toda a chain de autorização

Se sua plataforma é PHP + framework brasileiro (Adianti, Laravel, Symfony, CodeIgniter), ou qualquer stack legada, vale auditar especificamente esse padrão antes de descobrir do jeito difícil.

O que fazer hoje

  1. Mapeie classes/endpoints públicos do seu framework. Qual cada um faz?
  2. Audite endpoints de upload com os 7 testes acima.
  3. Se você não tem pentest documentado nos últimos 12 meses, não sabe se sua plataforma está exposta. Sabe apenas que ainda não foi atacada.
  4. Se descobrir 1+ elo vulnerável, contrate pentest focado em chain.

Para conversa sobre pentest focado em ATO chains:

Se quer pular pra ação: solicitar pentest. NDA bilateral em 24h.

Compartilhar

WhatsAppLinkedInX

Próximo passo

Quer aplicar isso ao seu sistema?

A No Vuln faz pentest profundo com a mesma metodologia descrita neste artigo. Solicite uma proposta — NDA bilateral em 24h, escopo definido em call técnica.