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).
Pesquisador de segurança e fundador da No Vuln

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
| # | Elo | Severidade isolada | Função na cadeia |
|---|---|---|---|
| 1 | Serviço de upload de arquivos acessível sem autenticação | Médio | Porta de entrada |
| 2 | Validação de extensão fraca (aceita .phar) | Médio | Engana o filtro |
| 3 | Diretório de upload dentro do webroot + execução PHP permitida | Médio | Permite executar o que subiu |
| 4 | Arquivo application.ini legível pelo processo web | Alto | Expõe segredos |
| 5 | Hash de senhas em MD5 sem salt | Alto | Permite forjar credencial |
| 6 | API REST validando token por segredo compartilhado (não JWT assinado) | Médio | Possibilita criar sessão admin |
| 7 | Sessão PHP baseada em filesystem, sem rotação de ID em login | Médio | Sequestro 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=AdiantiUploaderServiceO 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 confirmadoTraduçã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:
- Lista todas as classes “públicas” do seu framework. Quais são acessíveis sem autenticação? Cada uma é porta de entrada potencial.
- Para serviços de upload: valide extensões em allowlist (não blocklist). Inclua
.phar,.phtml,.pht,.svg,.htmlna blocklist explícita. - Diretório de upload: está fora do webroot? Se dentro, execução PHP está desabilitada (
.htaccessou nginx config)? - 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. - Hash de senhas: está usando
password_hash()(PHP nativo, bcrypt/argon2)? Ou MD5/SHA1? - APIs internas: autenticação é por JWT assinado ou segredo compartilhado? Se compartilhado, vaza junto com config.
- Sessões: seu framework rotaciona
session_idem cada mudança de estado de auth? PHP nativo NÃO rotaciona por default — precisasession_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
- Mapeie classes/endpoints públicos do seu framework. Qual cada um faz?
- Audite endpoints de upload com os 7 testes acima.
- 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.
- 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.
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.