
🌐 También en: English · Deutsch · Français
Se supone que la carpetauploads de WordPress guarda tus fotos de
vacaciones y algún que otro PDF. Lo que desde luego no se supone es que
albergue una web shell en PHP – pero ese «se supone» carga con mucho peso. El
directorio de subidas es, con diferencia, el sitio más habitual donde un
WordPress comprometido acaba ejecutando código del atacante, porque tiene permisos
de escritura, es accesible desde la web y todo el mundo se olvida de él. Así que
le puse nariz al mío: un antivirus que olfatea la carpeta de subidas cada noche y
me manda un correo en cuanto huele algo raro. 👃 Y como un detector de humo que nunca has probado es solo una joya de techo,
también lo hice saltar a propósito. Más sobre eso al final.🎯 El diseño (aburrido a propósito)
- 🌙 Bajo demanda, cada noche. Nada de un demonio de escaneo en acceso en tiempo real – es demasiado pesado para un VPS modesto, y prácticamente soy el único que sube algo. Una pasada por noche es el equilibrio adecuado: en el peor caso, el malware se queda unas horas hasta el correo de la mañana, no semanas.
- 🔇 En silencio salvo que encuentre algo. La misma filosofía que todo lo demás en esta máquina (rkhunter, Monit): un escaneo limpio no envía nada. Por eso, un correo del escáner siempre significa «mira esto ya», nunca «todo bien, como siempre».
- 🔎 Solo detección. Avisa, pero no borra ni pone nada en cuarentena. En un blog personal prefiero revisar un hallazgo con mis propios ojos antes que dejar que un conserje automático se zampe en silencio un falso positivo.
- 🧩 Gestionado con Ansible (rol
blog_clamav), así que es reproducible y está versionado – no es un script «copo de nieve» que olvidaré cómo monté.
📦 Instalación y configuración
En AlmaLinux 9, todo se reduce a ClamAV más su actualizador de firmas:dnf install clamav clamav-updateEl freshclam.conf que viene en el paquete trae una línea de ejemplo
que impide que llegue a ejecutarse nunca – el clásico tropiezo de la primera vez.
Quítala, descarga la base de firmas una vez y activa las actualizaciones
automáticas:# kill the "Example" line or freshclam refuses to start
sed -i '/^Example/d' /etc/freshclam.conf
freshclam # first full signature download
systemctl enable --now clamav-freshclam # keep signatures fresh automaticallyEl escaneo en sí es un pequeño script en /usr/local/sbin/wordpress-clamav-scan.sh. Solo escanea el
directorio de subidas, no molesta al resto de la máquina, se salta los archivos
absurdamente grandes (el malware no se esconde en un vídeo de 300 MB) y – lo
importante – solo envía correo cuando encuentra algo:#!/bin/bash
SCAN_LOG="/var/log/clamav/wordpress-scan.log"
UPLOADS_DIR="/srv/wordpress-www/wp-content/uploads"
nice -n 19 ionice -c3 clamscan --recursive --infected --no-summary
\
--max-filesize=200M --max-scansize=200M
\
"$UPLOADS_DIR" > "$SCAN_LOG" 2>&1
RC=$?
# clamscan exit code 1 = something was found -> mail it, otherwise stay silent
if [ "$RC" -eq 1 ]; then
mail -s "[$(hostname -f)] ClamAV: infected file(s) found in WordPress uploads"
\
me@example.com < "$SCAN_LOG"
fi
exit 0Una entrada de cron lo ejecuta cada noche a las 02:45. El correo sale por el mismo
relay msmtp que usan el resto de mis alertas (rkhunter, Monit), así
que solo hay una ruta de correo que mantener funcionando, no tres.45 2 * * * /usr/local/sbin/wordpress-clamav-scan.sh🧪 Hacerlo ladrar: la prueba EICAR
Aquí viene lo divertido. Para probar un antivirus no se descarga malware real – se usa EICAR, una cadena de prueba estándar del sector de 68 bytes que todos los escáneres del planeta están obligados a detectar, y que es completamente inofensiva (no es malware ejecutable, es una cadena ASCII imprimible diseñada únicamente para disparar la detección). La dejas en la ruta escaneada, ejecutas el script de verdad, ves cómo se dispara toda la cadena y luego la borras:# drop the harmless EICAR test file into uploads
printf 'X5O!P%%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*\n'
\
> /srv/wordpress-www/wp-content/uploads/eicar-test.txt
# run the actual nightly script by hand
/usr/local/sbin/wordpress-clamav-scan.sh
# clean up immediately
rm -f /srv/wordpress-www/wp-content/uploads/eicar-test.txtClamAV la detectó al instante – Eicar-Signature FOUND –,
el script terminó con código de salida 1, disparó el correo y, al momento, esto aterrizó en mi
bandeja de entrada:From: homelab@apt-upgrade.me
Subject: [www.apt-upgrade.me] ClamAV: infected file(s) found in WordPress uploads
/srv/wordpress-www/wp-content/uploads/eicar-test.txt: Eicar-Signature FOUNDY para ser concienzudo, revisé también el log del propio relay de correo, que
confirmó la entrega en lugar de darla simplemente por hecha:host=smtp.strato.de tls=on auth=on ... recipients=you@example.com
smtpstatus=250 ... 'OK queued' exitcode=EX_OKDetección ✔️, ruta de correo del script real ✔️, entrega en mi bandeja de entrada
de verdad ✔️. Esa es la diferencia entre «he configurado un escáner» y «tengo un
escáner que funciona»: al segundo lo has visto pillar algo. 🎯 (Archivo de prueba
borrado justo después, subidas limpias otra vez. Fue un simulacro, no una
intrusión.)⚠️ Limitaciones, con honestidad
- Es un escaneo nocturno, no en tiempo real. Una subida maliciosa se detecta en la siguiente pasada de las 02:45, no en el instante en que llega.
- Escanea las subidas, la carpeta de mayor riesgo – no todo el disco. Para la capa del sistema operativo hay otra herramienta (aquí, ese es el trabajo de rkhunter).
- Detección, no eliminación. El correo es todo el producto; la limpieza es una decisión humana.




