
Un plugin gratuito de wordpress.org se puede verificar archivo por archivo contra el original publicado por su autor: si alguien le inyectó código, la diferencia salta de inmediato. WP-CLI trae ese comando (wp plugin verify-checksums), pero leer su salida plugin por plugin y cuenta por cuenta es tedioso.
Estos dos scripts lo automatizan: revisar-plugin.sh revisa un plugin y revisar-todos-plugins.sh los revisa todos.
Antes de empezar
- Necesitas un VPS o servidor dedicado con cPanel/WHM y acceso root (desde WHM → Terminal basta).
- Los scripts se probaron en AlmaLinux 10 con cPanel 138, PHP 8.3 de EasyApache (
/opt/cpanel/ea-php83) y WP-CLI instalado en/usr/local/bin/wp. Si tu servidor usa otra versión de PHP, cambia la rutaea-php83en el script. - Pruébalos primero en un horario tranquilo y lee lo que hace cada uno antes de ejecutarlo. Se comparten tal cual, sin garantía: adáptalos a tu servidor.
Qué revisa
- Comparación con wordpress.org: si el plugin está publicado ahí, confirma que sea idéntico al original.
- Si es premium (no está en wordpress.org), revisa su código: marcas de clubes que definas en
MARCAS, código malicioso conocido, archivos raros y enlaces. - Funciones que crean usuarios o inician sesiones, y respaldos de archivos originales (señal de que alguien lo modificó).
- En la cuenta: PHP escondido dentro de
uploads, errores de PHP del día y si el sitio responde.
Instalación
Primero revisar-plugin.sh, porque el segundo script lo usa. Pega cada bloque en WHM → Terminal:
cat > /root/revisar-plugin.sh <<'EOF'
#!/bin/bash
# Revisa un plugin ya instalado. Uso: revisar-plugin.sh CUENTA PLUGIN
# Ejemplo: revisar-plugin.sh micuenta elementor-pro
# Sin PLUGIN, muestra la lista de plugins de la cuenta.
# Marcas de clubes GPL o sitios de plugins no oficiales que quieras detectar (separadas por |)
MARCAS="nombre-del-club|dominio-del-club\.com"
U="$1"; PL="$2"
WPATH="/home/$U/public_html"
[ -f "$WPATH/wp-config.php" ] || { echo "No hay WordPress en la cuenta '$U'"; ls /home | grep -v -E '^(virtfs|cPanelInstall)' ; exit 1; }
W=(sudo -u "$U" -- /opt/cpanel/ea-php83/root/usr/bin/php /usr/local/bin/wp --path="$WPATH" --skip-plugins --skip-themes)
if [ -z "$PL" ]; then echo "Plugins de $U:"; "${W[@]}" plugin list --fields=name,version,status 2>/dev/null; echo "Uso: $0 $U NOMBRE-DEL-PLUGIN"; exit 0; fi
D="$WPATH/wp-content/plugins/$PL"
[ -d "$D" ] || { echo "No existe el plugin '$PL' en $U. Plugins instalados:"; "${W[@]}" plugin list --field=name 2>/dev/null; exit 1; }
MAL=0
echo "===== $PL en $U"; "${W[@]}" plugin get "$PL" --fields=version,status 2>/dev/null | tail -n +2
echo "--- Comparacion con wordpress.org"
V=$("${W[@]}" plugin verify-checksums "$PL" 2>&1)
if echo "$V" | grep -qE "Verified [1-9][0-9]* of [1-9]"; then
echo "OK: identico al original de wordpress.org"
elif echo "$V" | grep -qiE "could not retrieve|skipped|no se pudo"; then
echo "No esta en wordpress.org (premium o del club): se revisa el codigo"
elif echo "$V" | grep -qiE "checksum|should not exist|was added|File "; then
echo "ATENCION: archivos distintos al original:"; echo "$V" | grep -v "^Error: No plugins verified" | head -15; MAL=1
else
echo "No se pudo comparar: $(echo "$V" | tail -1 | cut -c1-150)"
fi
echo "--- Marcas del club"; grep -rlE "$MARCAS" "$D" | sed "s|$D/||"
R=$(grep -rnoE ".{0,40}(eval\s*\(\s*(base64_decode|gzinflate|str_rot13|\\\$_(POST|GET|REQUEST|COOKIE))|(assert|system|passthru|shell_exec|exec|popen)\s*\(\s*\\\$_(POST|GET|REQUEST|COOKIE)|base64_decode\s*\(\s*\\\$_(POST|GET|REQUEST|COOKIE)|\\\\x65\\\\x76\\\\x61\\\\x6c).{0,40}" "$D" --include=*.php | grep -v json_decode | sed "s|$D/||" | head)
echo "--- Codigo malicioso conocido"; [ -n "$R" ] && { echo "$R"; MAL=1; }
echo "--- Crea usuarios o inicia sesiones (en plugins de tienda, foro o membresia puede ser normal)"; grep -rlE "wp_create_user|wp_insert_user|wp_set_auth_cookie" "$D" --include=*.php | sed "s|$D/||" | head
R=$(find "$D" \( -name "*.suspected" -o -name "*.phtml" -o -name "*.phar" -o -name "*.pht" -o -name ".*.php" \) -o -type l | sed "s|$D/||")
echo "--- Archivos raros o enlaces"; [ -n "$R" ] && { echo "$R"; MAL=1; }
echo "--- Respaldos de originales (senal de modificacion)"; find "$D" \( -name "*.bak" -o -name "*.backup" -o -name "*.orig" \) | sed "s|$D/||"
R=$(find "$WPATH/wp-content/uploads" -type f \( -iname "*.php*" -o -iname "*.phtml" \) -size +200c 2>/dev/null | sed "s|$WPATH/||")
echo "--- PHP dentro de uploads"; [ -n "$R" ] && { echo "$R"; MAL=1; }
echo "--- Errores de PHP de hoy"; grep "$(date +%d-%b-%Y)" "$WPATH/error_log" 2>/dev/null | tail -5 | cut -c1-200
DOM=$(grep -m1 '^DNS=' "/var/cpanel/users/$U" 2>/dev/null | cut -d= -f2)
[ -n "$DOM" ] && echo "--- Sitio responde: $(curl -s -o /dev/null -k --resolve $DOM:443:127.0.0.1 -w '%{http_code} %{time_total}s' https://$DOM/)"
echo; [ $MAL = 0 ] && echo "RESULTADO: sin hallazgos graves" || echo "RESULTADO: HAY HALLAZGOS, revisar antes de seguir usando el plugin"
EOF
chmod 700 /root/revisar-plugin.sh && bash -n /root/revisar-plugin.sh && echo SCRIPT_OK
cat > /root/revisar-todos-plugins.sh <<'EOF'
#!/bin/bash
# Revisa todos los plugins de todas las cuentas usando /root/revisar-plugin.sh
# Uso: /root/revisar-todos-plugins.sh (todas las cuentas)
# /root/revisar-todos-plugins.sh micuenta (solo una cuenta)
[ -x /root/revisar-plugin.sh ] || { echo "Falta /root/revisar-plugin.sh"; exit 1; }
MALOS=""
for C in /home/${1:-*}/public_html/wp-config.php; do
[ -f "$C" ] || continue
U=$(stat -c %U "$(dirname "$C")")
echo "======== $U"
for D in /home/$U/public_html/wp-content/plugins/*/; do
P=$(basename "$D")
R=$(/root/revisar-plugin.sh "$U" "$P" 2>/dev/null)
ORIGEN=$(echo "$R" | grep -A1 "Comparacion con wordpress.org" | tail -1 | sed 's/OK: identico al original de wordpress.org/wordpress.org OK/; s/No esta en wordpress.org.*/premium o del club/' | cut -c1-40)
CLUB=$(echo "$R" | sed -n '/--- Marcas del club/,/--- Codigo/p' | grep -vc -- '---')
VER=$(echo "$R" | awk '/^version/{print $2}')
if echo "$R" | grep -q "HAY HALLAZGOS"; then EST="<<< HAY HALLAZGOS"; MALOS="$MALOS $U:$P"; else EST="ok"; fi
printf " %-38s %-10s %-22s %s%s\n" "$P" "$VER" "$ORIGEN" "$EST" "$( [ "$CLUB" -gt 0 ] && echo ' (del club)')"
done
done
if [ -n "$MALOS" ]; then
echo; echo "################ DETALLE DE LOS PLUGINS CON HALLAZGOS"
for X in $MALOS; do /root/revisar-plugin.sh "${X%%:*}" "${X#*:}"; echo; done
else
echo; echo "Ningun plugin con hallazgos."
fi
EOF
chmod 700 /root/revisar-todos-plugins.sh && bash -n /root/revisar-todos-plugins.sh && echo SCRIPT_OK
Cómo usarlos
/root/revisar-plugin.sh CUENTA PLUGIN # un plugin de una cuenta
/root/revisar-plugin.sh micuenta elementor-pro # ejemplo
/root/revisar-plugin.sh micuenta # sin plugin: lista los plugins de la cuenta
/root/revisar-todos-plugins.sh # todos los plugins de todas las cuentas
/root/revisar-todos-plugins.sh micuenta # solo una cuenta
/root/revisar-todos-plugins.sh > /root/plugins-$(date +%F).txt # guardar el reporte
CUENTA es el usuario de cPanel y PLUGIN es el nombre de la carpeta del plugin. Si lo escribes mal, el script te muestra los nombres correctos.
Cómo leer el resultado
- «OK: identico al original de wordpress.org»: verificación fuerte, nadie lo modificó.
- «No esta en wordpress.org (premium o del club)»: no hay original con qué comparar, así que solo se revisó su código.
- «ATENCION: archivos distintos al original»: un plugin gratuito fue modificado; revísalo de inmediato.
- Algunos plugins generan archivos propios al guardar su configuración (por ejemplo, CSS personalizados). Si aparece «File was added» en un
.csso.jscon fecha del día en que guardaste ajustes, probablemente es eso; compáralo con el original para confirmarlo. - En el resumen de todos los plugins, cada línea muestra versión, origen y estado; al final aparece el detalle solo de los que tienen hallazgos.
Cuándo usarlos
revisar-plugin.sh: después de instalar o actualizar un plugin.revisar-todos-plugins.sh: una vez al mes, o después de actualizar varios sitios.





