Poucas situações em produção geram tanta dúvida quanto o desaparecimento repentino de arquivos. Recentemente, precisei investigar um caso real: uma subpasta com arquivos importantes simplesmente deixou de existir no servidor entre os dias 01 e 06 do mês.
A pergunta imediata foi: quem apagou, como apagou e onde está o log dessa ação?
Abaixo, detalho o processo de investigação forense que realizei no servidor cPanel, cobrindo a interface web, os logs de FTP e a camada de aplicação PHP.
1. Primeira camada: o gerenciador de arquivos do cPanel#
A primeira hipótese foi verificar se algum usuário havia deletado os arquivos pelo Gerenciador de Arquivos na interface web do cPanel.
Fiz uma busca inicial no log de acessos do cPanel:
grep "sub.domain.com.br" /usr/local/cpanel/logs/access_log
O retorno apresentou registros como este:
192.0.2.10 - userapp [06/04/2026:14:28:26 -0000] "GET /cpsess6428448619/json-api/cpanel?cpanel_jsonapi_module=Fileman&cpanel_jsonapi_func=listfiles&cpanel_jsonapi_apiversion=2&needmime=1&dir=%2fhome%2fuserapp%2fpublic_html%2fsub.domain.com.br&showdotfiles=1 HTTP/1.1" 200 0 ...
O que essa linha significa?#
- Módulo:
Fileman(File Manager). - Função chamada:
listfiles. - Método HTTP:
GET.
Essa linha não representa deleção. A função listfiles apenas executa leitura de diretório (getdents64 ou stat) para exibir os arquivos na tela.
Para identificar uma exclusão real via interface web ou API, os verbos seriam:
fileop?op=unlink: Exclusão permanente direta.fileop?op=trash: Envio para a lixeira (/home/user/.trash/).Fileman::fileopcomop=trashouop=unlink: chamadas UAPI (v3) — e a v2 legacy que o Gerenciador de Arquivos ainda dispara na prática (cpanel_jsonapi_func=fileop&op=trash|unlink).
Fiz uma varredura procurando por ações de deleção:
grep "06/04/2026" /usr/local/cpanel/logs/access_log | grep "userapp" | grep -E "fileop|delete|unlink|trash"
Repeti a checagem para todo o intervalo de dias. Resultado: nenhum registro. Ninguém apagou os arquivos pela interface do cPanel.
2. Segunda camada: auditoria de FTP (pure-ftpd)#
Se a interface gráfica não registrou a ação, o próximo canal é o FTP. No cPanel com Pure-FTPd, os logs residem em:
/var/log/messages(via syslog)/var/log/xferlog(log posicional de transferências)
No protocolo FTP, a remoção de arquivos é identificada explicitamente pelo comando DELE. No xferlog (log com formato posicional), deleções aparecem como transferências com direção d — o rastro confiável para comandos DELE; o syslog (/var/log/messages) registra conexões e transferências de alto nível, nem sempre gerando linhas para comandos DELE individuais.
Busquei nos logs de sistema:
grep "06/Apr/2026" /var/log/messages | grep "userapp" | grep "DELE"
E no xferlog (onde a flag d isolada indica deleção):
grep "userapp" /var/log/xferlog | grep " d "
Estendi a busca para todos os dias do período. Resultado: nenhum comando DELE. Nenhuma sessão FTP realizou a limpeza.
3. O fator aplicação: execução direta via PHP#
Com o File Manager e o FTP descartados, restava uma pista estrutural: a subpasta apagada ficava aninhada em uma raiz onde rodava uma aplicação WordPress (PHP).
Quando um script PHP remove um arquivo, ele executa a função nativa unlink(), disparando a syscall SYS_unlinkat diretamente no Kernel.
O ponto cego: Como nem o cPanel nem o daemon do FTP participam dessa chamada, a exclusão é 100% invisível no access_log do cPanel e nos logs do Pure-FTPd. O rastro passa a existir apenas nos logs do servidor web (Apache), logs de erro do PHP ou na auditoria do kernel.
4. O roteiro de investigação na camada de aplicação#
Para identificar a causa raiz quando o PHP é o autor da ação:
A. Auditoria de requisições suspeitas no Apache (domlogs)#
Se um plugin, script ou rotina web foi acionado para apagar arquivos, ele gerou uma requisição HTTP (geralmente POST):
grep "06/Apr/2026" /etc/apache2/logs/domlogs/domain.com.br | grep -E "POST|DELETE" | awk '{print $1, $6, $7}' | sort | uniq -c | sort -nr
Procure chamadas POST para arquivos anômalos em pastas públicas (como wp-content/uploads/).
B. Delimitação temporal pelo primeiro HTTP 404#
O domlog do Apache é cronológico e acumula acessos contínuos. Para isolar o momento exato em que os arquivos sumiram sem puxar 404s antigos de semanas anteriores, delimite a janela temporal do incidente antes de extrair os primeiros registros:
awk '$4 >= "[01/Apr/2026:" && $4 < "[07/Apr/2026:" && $8 == "404"' \
/etc/apache2/logs/domlogs/sub.domain.com.br | head -n 10
Com o timestamp do primeiro 404 retornado dentro do intervalo do sumiço, isole a janela de segundos nos logs do Apache para correlacionar qual script estava em execução naquele exato instante.
C. Tarefas agendadas (cronjobs)#
Muitas rotinas de limpeza rodam em segundo plano via cron:
crontab -l -u userapp
ls -la /var/spool/cron/userapp
D. Auditoria de syscalls no kernel (auditd)#
Se o servidor possuir o auditd ativo monitorando o diretório:
ausearch -f /home/userapp/public_html/sub.domain.com.br -i
O auditd registra a syscall no momento da execução, gravando o PID e o executável exato (/usr/bin/php ou /usr/sbin/httpd) que apagou os arquivos.
E. Recuperação de arquivos com descritores abertos (lsof)#
Se os arquivos foram apagados recentemente mas o processo que os lia continua aberto, o inode ainda existe na memória do kernel:
lsof +L1 | grep "userapp"
Se o processo do Apache ou PHP-FPM ainda mantiver o descritor aberto, você pode copiar o conteúdo diretamente de /proc/<PID>/fd/<FD>.
Conclusão: principais lições da investigação#
- listfiles no cPanel é apenas leitura: Navegar pelas pastas na interface web não altera nem remove arquivos.
- Entenda o caminho da Syscall: Quando a exclusão parte do PHP (
unlink), ela vai direto para o kernel, não gerando rastros nos logs de painel ou FTP. - Use o primeiro erro 404 como âncora: O timestamp do primeiro 404 filtrado na janela do incidente nos domlogs do Apache revela o instante exato da remoção, permitindo correlacionar com requisições POST suspeitas ou rotinas de cron.
Este artigo foi útil?
Deixe uma reação rápida para apoiar o conteúdo:
Este post está licenciado sob CC BY-NC.



Comentários
Participe da discussão abaixo.
0 comentários