
Analisador gratuito de comprometimento de logs de acesso: interações com webshell, padrões de exploração e rajadas de força bruta nos seus logs do Apache/nginx - severidade, confiança, remediação. Somente leitura.
Os logs do seu servidor web já sabem se você foi atacado. O weblogchecker os lê.
O phpscan informa se o seu PHP está exposto. O phpscan hunt procura por shells no
webroot. O weblogchecker responde à terceira pergunta — alguém
realmente os utilizou? — a partir do único registro que a maioria dos sites já possui e que ninguém
lê: o log de acesso.
Ele processa em streaming logs de acesso do Apache e do nginx que você possui, encontra as interações que importam — um webshell respondendo a requisições, uma rajada de força bruta que termina em um redirecionamento, um padrão de exploit que obteve um 200 — e reporta cada uma com severidade, confiança, as linhas reais do log como evidência e o que fazer a respeito.
weblogchecker analyze /var/log/apache2/access.log
Códigos de saída: 0 = nenhum indicador, 1 = indicadores encontrados, 2 = erro de uso.
Adicione --format json para saída legível por máquina, --since 2026-10-01 para
limitar a janela. Logs .gz são lidos diretamente; - lê da entrada padrão.
Novo na 0.2.0 — diff de linha de base. Listas de assinaturas só conhecem shells que já têm nomes. O shell que chega ao seu site tem um nome aleatório. Forneça ao weblogchecker um log antigo confiável do mesmo site e ele reporta os executáveis que nunca estiveram lá antes:
weblogchecker analyze access.log --baseline access.log.last-month
Todo caminho executável (.php, .phtml, .cgi, .asp, .jsp…) que aparece pela
primeira vez é pontuado com base em cinco sinais fracos apenas a partir do log —
respondido com 2xx/3xx, POST/PUT utilizado, sem referrer, acessado por no máximo 2 IPs,
localizado sob um diretório de upload/cache/temp — e reportado como NEW
com os sinais, contagens e linhas de log como evidência. Apenas a primeira aparição é
uma nota de baixa severidade; a severidade aumenta apenas à medida que os sinais se acumulam (detalhes
abaixo), de modo que um plugin que você instalou na semana passada não é lido como um
incidente.
Uma linha, a partir do PyPI (Python 3.11+, apenas biblioteca padrão — zero dependências):
pip install weblogchecker
Primeira versão no PyPI pendente. Até que o trusted publisher do PyPI seja configurado, instale o código idêntico a partir do GitHub:
pip install git+https://github.com/PHPatch/weblogchecker.git(ou baixe o tarball da versão assinada abaixo). A linhapip install weblogcheckeracima funciona assim que a primeira versão no PyPI for publicada.
Em sistemas que recusam com "externally-managed-environment" (Pythons do Debian/Ubuntu e do Homebrew), use pipx em vez disso:
python3 -m pip install --user pipx # if you don't have pipx yet
pipx install weblogchecker
As versões assinadas (sdist + wheel + assinaturas PGP + SBOM) estão na
página de releases do GitHub.
Verifique as assinaturas com a chave em pgp-key.asc — fingerprint
BAA1 586A AD37 18C0 CE41 D288 FE23 A624 54E3 5307. Consulte SECURITY.md.
| Padrão no seu log | Severidade / confiança | Por que importa |
|---|---|---|
| Webshell conhecida (c99, r57, FilesMan, b374k, WSO) respondendo 2xx | alta / alta | A shell existe e atendeu a uma requisição |
| Os mesmos nomes sondados, mas com 404/403 | baixa / baixa | Alguém procurou; nada encontrado — contexto, não alarme |
eval-stdin.php (phpunit) respondendo | alta / alta | A shell UnitTest da onda php2shell de outubro de 2026 executa código enviado via POST |
Executável (.php etc.) dentro de /uploads/, /media/, /files/… respondendo, esp. POST | alta / alta | Diretórios de upload nunca devem executar código |
| POST/PUT para um arquivo estático (.jpg, .css…) respondido com 2xx | alta / média | Navegadores não fazem POST para imagens; a "imagem" costuma ser um script |
Padrão de exploit na URI (traversal, eval(, php://, token base64 longo) respondido com 2xx | alta / média | A tentativa pode ter funcionado |
| Os mesmos padrões bloqueados / 404 | baixa / baixa | Ruído de fundo; útil apenas como contexto de campanha |
| Rajada de força bruta em wp-login.php / xmlrpc.php (≥20 POSTs / 10 min) | média / média | Um único IP, ritmo desumano |
| Um 302 dentro dessa rajada após falhas repetidas | alta / média | A forma de uma senha correta — possível tomada de controle |
| User-agents de scanners (sqlmap, nuclei, nikto…) | baixa / baixa | Informativo; escanear não é comprometer |
Caminho de executável ausente do seu log --baseline, respondendo a requisições | baixa → alta / ≤ média | A shell de nome desconhecido que nenhuma blocklist conhece; a severidade aumenta com POSTs, referrers ausentes, poucos IPs, diretórios de upload |
Toda classe de achado traz texto de remediação: coloque o arquivo em quarentena, rotacione
credenciais, revise tudo que aquele IP tocou. Achados de webshell apontam para
a ferramenta companheira — phpscan hunt (pip install phpscan,
github.com/PHPatch/phpscan) — que
escaneia o próprio webroot em busca das shells para as quais esses padrões de log apontam.
Esta ferramenta foi construída sob a mesma doutrina do phpscan:
A análise é feita em streaming de linhas: o arquivo nunca é carregado na memória, e a agregação mantém no máximo cinco linhas de evidência por achado. Medido no gerador de fixtures deste projeto (366.306 linhas, 72 MB de log combinado realista): 7,6 segundos, 12,8 MB de RSS de pico em uma VM modesta. Um log de 2 GB usa a mesma memória, com tempo proporcionalmente maior.
$ weblogchecker analyze access.log
weblogchecker 0.2.0 - access-log compromise analysis
Log: access.log
Lines read: 13 | parsed: 13 | unparseable (skipped): 0
Indicators found. These are leads for investigation, not proof of
compromise: work through the findings in severity order ...