
Analizador gratuito de compromiso de registros de acceso: interacciones con webshell, patrones de explotación y ráfagas de fuerza bruta en tus registros de Apache/nginx - gravedad, confianza, remediación. Solo lectura.
Los registros de tu servidor web ya saben si fuiste atacado. weblogchecker los lee.
phpscan te dice si tu PHP está expuesto. phpscan hunt busca shells en el
webroot. weblogchecker responde a la tercera pregunta — ¿alguien llegó
realmente a usarlas? — a partir del único registro que la mayoría de los sitios ya tienen y nadie
lee: el log de acceso.
Procesa en streaming los logs de acceso de Apache y nginx que tú posees, encuentra las interacciones que importan — un webshell respondiendo a peticiones, una ráfaga de fuerza bruta que termina en una redirección, un patrón de exploit que obtuvo un 200 — y reporta cada una con severidad, confianza, las líneas de log reales como evidencia y qué hacer al respecto.
weblogchecker analyze /var/log/apache2/access.log
Códigos de salida: 0 = sin indicadores, 1 = indicadores encontrados, 2 = error de uso.
Añade --format json para una salida legible por máquina, --since 2026-10-01 para
limitar la ventana. Los logs .gz se leen directamente; - lee de stdin.
Nuevo en 0.2.0 — baseline diff. Las listas de firmas solo conocen shells que ya tienen nombres. El shell que aterriza en tu sitio tiene uno aleatorio. Proporciona a weblogchecker un log antiguo de confianza del mismo sitio y reporta los ejecutables que nunca estuvieron ahí antes:
weblogchecker analyze access.log --baseline access.log.last-month
Cada ruta ejecutable (.php, .phtml, .cgi, .asp, .jsp…) que aparece por
primera vez se puntúa según cinco señales débiles únicamente a partir del log —
respondida con 2xx/3xx, uso de POST/PUT, sin referrer, accedida por como máximo 2 IPs,
ubicada bajo un directorio de carga/caché/temporal — y se reporta como NEW
con las señales, los recuentos y las líneas de log como evidencia. La primera aparición por sí sola es
una nota de baja severidad; la severidad aumenta solo a medida que se acumulan las señales (detalles
a continuación), por lo que un plugin que instalaste la semana pasada no se interpreta como un
incidente.
Una línea, desde PyPI (Python 3.11+, solo biblioteca estándar — cero dependencias):
pip install weblogchecker
Primera publicación en PyPI pendiente. Hasta que el publicador de confianza de PyPI esté configurado, instala el código idéntico desde GitHub:
pip install git+https://github.com/PHPatch/weblogchecker.git(o descarga el tarball de la versión firmada a continuación). La líneapip install weblogcheckeranterior funciona en cuanto se publique la primera versión en PyPI.
En sistemas que lo rechazan con "externally-managed-environment" (Pythons de Debian/Ubuntu y Homebrew), usa pipx en su lugar:
python3 -m pip install --user pipx # if you don't have pipx yet
pipx install weblogchecker
Las versiones firmadas (sdist + wheel + firmas PGP + SBOM) están en la
página de releases de GitHub.
Verifica las firmas con la clave en pgp-key.asc — huella
BAA1 586A AD37 18C0 CE41 D288 FE23 A624 54E3 5307. Consulta SECURITY.md.
| Patrón en tu log | Severidad / confianza | Por qué importa |
|---|---|---|
| Webshell conocida (c99, r57, FilesMan, b374k, WSO) respondiendo 2xx | alta / alta | La shell existe y sirvió una petición |
| Los mismos nombres sondeados pero con 404/403 | baja / baja | Alguien miró; no encontró nada — contexto, no alarma |
eval-stdin.php (phpunit) respondiendo | alta / alta | La shell UnitTest de la oleada php2shell de octubre de 2026 ejecuta código enviado por POST |
Ejecutable (.php, etc.) dentro de /uploads/, /media/, /files/… respondiendo, esp. POST | alta / alta | Los directorios de subida nunca deben ejecutar código |
| POST/PUT a un archivo estático (.jpg, .css…) respondido con 2xx | alta / media | Los navegadores no hacen POST a imágenes; la "imagen" suele ser un script |
Patrón de exploit en la URI (traversal, eval(, php://, token base64 largo) respondido con 2xx | alta / media | El intento puede haber funcionado |
| Los mismos patrones bloqueados / 404 | baja / baja | Ruido de fondo; útil solo como contexto de campaña |
| Ráfaga de fuerza bruta sobre wp-login.php / xmlrpc.php (≥20 POSTs / 10 min) | media / media | Una IP, ritmo inhumano |
| Un 302 dentro de esa ráfaga tras fallos repetidos | alta / media | La forma de una contraseña correcta — posible toma de control |
| User-agents de escáneres (sqlmap, nuclei, nikto…) | baja / baja | Informativo; escanear no es comprometer |
Ruta de ejecutable ausente de tu log --baseline, respondiendo a peticiones | baja → alta / ≤ media | La shell de nombre desconocido que ninguna lista de bloqueo conoce; la severidad escala con POSTs, referrers ausentes, pocas IPs, directorios de subida |
Cada clase de hallazgo incluye texto de remediación: poner el archivo en
cuarentena, rotar credenciales, revisar todo lo que esa IP tocó. Los hallazgos
de webshell apuntan a la herramienta complementaria — phpscan hunt
(pip install phpscan,
github.com/PHPatch/phpscan) — que
escanea el propio webroot en busca de las shells a las que apuntan estos
patrones de log.
Esta herramienta se construyó bajo la misma doctrina que phpscan:
El análisis es de flujo por líneas: el archivo nunca se carga en memoria y la agregación conserva como máximo cinco líneas de evidencia por hallazgo. Medido en el generador de fixtures de este proyecto (366.306 líneas, 72 MB de log combinado realista): 7,6 segundos, 12,8 MB de RSS máximo en una VM modesta. Un log de 2 GB usa la misma memoria, con un tiempo proporcionalmente mayor.
$ weblogchecker analyze access.log
weblogchecker 0.2.0 - access-log compromise analysis
Log: access.log
Lines read: 13 | parsed: 13 | unparseable (skipped): 0