Situación actual: PHP2Shell. Dos vulnerabilidades críticas de PHP (CVSS 9.2) permiten ejecutar código malicioso sin autenticación. Parches desde el 21/10/2026.Qué hacer ahora →

Reconocer código PHP ofuscado

El código PHP ilegible con eval y base64_decode es una señal clásica de código malicioso inyectado. Qué patrones buscar, cómo encontrarlos sin riesgo y cuándo la ofuscación es legítima.

Actualizado 6 min de lecturaDetección y análisis forense

En resumen: El código PHP ofuscado es código que se ha hecho ilegible a propósito, normalmente mediante codificación y compresión que solo se resuelven en tiempo de ejecución. Los patrones típicos de detección son eval junto con base64_decode, gzinflate o str_rot13, líneas muy largas, cadenas hexadecimales y nombres de función compuestos a partir de piezas. Busque con comandos grep inofensivos, no ejecute nunca el código y contraste los hallazgos con el paquete original.

Por qué los atacantes esconden su código

Quien deja una webshell o una puerta trasera en un servidor quiere que pase mucho tiempo sin ser descubierta. El código legible llamaría la atención de cualquier administrador que abra el archivo, y cualquier escáner lo encontraría. Por eso los atacantes empaquetan su código: se codifica, se comprime y solo al ejecutarlo se recompone y se ejecuta.

Para PHP2Shell no hay indicadores de compromiso confirmados. El código ofuscado no es un rasgo de esta vulnerabilidad, sino una señal general de que alguien ha inyectado código, por el camino que sea. Cómo encontrar y eliminar webshells en conjunto lo describe Reconocer y eliminar webshells. Este artículo se centra en la pregunta de cómo reconocer código ofuscado.

eval, base64 y compañía: los bloques típicos

La ofuscación sigue casi siempre el mismo principio: un bloque de datos ilegible es reconvertido por una o varias funciones en código que luego se ejecuta. Los siguientes bloques aparecen una y otra vez.

Bloque Ejemplos Por qué llama la atención
Ejecución eval, assert con cadena (hasta PHP 7.x), create_function (hasta PHP 7.x) ejecuta texto como código
Decodificación base64_decode, str_rot13, hex2bin, strrev, convert_uudecode vuelve a hacer legibles los datos
Descompresión gzinflate, gzuncompress, gzdecode desempaqueta código incrustado
Composición cadenas de chr(), concatenación de fragmentos cortos, escapes \x oculta nombres de función
Llamada dinámica variables como nombre de función, call_user_func, array_map con cadena la llamada no aparece en ninguna parte en texto claro
Acceso al sistema system, exec, shell_exec, passthru, proc_open, popen comandos en el servidor

Según el manual de PHP, assert() ya no evalúa cadenas como código desde PHP 8.0, y create_function() se eliminó en PHP 8.0. En servidores con versiones antiguas de PHP, ambos siguen siendo términos de búsqueda relevantes.

Un bloque aislado rara vez es sospechoso; base64_decode, por ejemplo, lo usan legítimamente muchas aplicaciones. Resulta sospechosa la combinación: una decodificación cuyo resultado fluye directamente a una ejecución.

Buscar sin riesgo: comandos grep inofensivos

Los siguientes comandos examinan los archivos solo como texto. No ejecutan código PHP. Adapte la ruta.

# Ejecución combinada con decodificación o descompresión
grep -rlE "(eval|assert)\s*\(\s*(base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin)" /var/www --include="*.php*"

# Líneas muy largas (a menudo código empaquetado)
grep -rlE ".{2000,}" /var/www --include="*.php*"

# Muchos escapes hexadecimales o cadenas de chr() en una línea
grep -rlE "(\\\\x[0-9a-fA-F]{2}){20,}" /var/www --include="*.php*"
grep -rlE "(chr\s*\(\s*[0-9]+\s*\)\s*\.\s*){8,}" /var/www --include="*.php*"

# Llamada a función mediante una variable justo después de una asignación a partir de cadenas
grep -rnE "\\\$[a-zA-Z_]+\s*=\s*['\"][a-z_]{4,}['\"]\s*;\s*\\\$[a-zA-Z_]+\s*\(" /var/www --include="*.php*" | head -50

Revise las coincidencias primero con ls -l y la marca de tiempo y ábralas después solo como texto, por ejemplo con less. No llame nunca a archivos sospechosos a través del navegador, porque el servidor los ejecutaría.

Dónde suele estar el código ofuscado

El código ofuscado rara vez está en un archivo propio y llamativo. Con más frecuencia se inserta en archivos existentes, justo al principio o justo al final, a menudo tras muchas líneas en blanco, para que no salte a la vista al abrirlos. Son populares los archivos que se cargan en cada llamada: el index.php central, los archivos de configuración y los archivos de funciones de un tema.

Un camino especialmente discreto pasa por la configuración. Con el ajuste auto_prepend_file, PHP carga un archivo adicional antes de cada script. Si figura en un .user.ini o .htaccess creado por un atacante, su código se ejecuta con cada llamada a una página sin que se haya modificado un solo archivo de la aplicación. El archivo incluido suele llevar una extensión inofensiva como .ico o .png.

# ¿Se carga código adicional antes o después de cada script?
grep -rnE "auto_(prepend|append)_file" /var/www --include=".user.ini" --include=".htaccess" --include="*.conf" 2>/dev/null

# Código PHP en archivos con extensión de imagen o icono
grep -rlE "<\?php" /var/www --include="*.ico" --include="*.png" --include="*.jpg" --include="*.gif" 2>/dev/null

Distinguir la ofuscación legítima del código malicioso

No todo código ilegible es malicioso. Se dan con frecuencia tres casos:

  1. Codificadores comerciales: algunos fabricantes de plugins y software protegen su código con herramientas como ionCube o SourceGuardian. Los archivos son ilegibles, pero suelen remitir al loader necesario. Contrástelos con el paquete original.
  2. Código minificado o generado: las cachés y los motores de plantillas generan líneas largas sin saltos, aunque sin ejecución de texto decodificado.
  3. Datos incrustados: imágenes o fuentes como cadena Base64 en un archivo PHP son inusuales, pero inofensivas mientras el resultado no se ejecute.

La prueba más fiable es la comparación con la fuente: si el archivo procede sin cambios del paquete del fabricante, es legítimo. Si no está en ningún paquete original o difiere de él, debe investigarse.

Importante

No intente descifrar código ofuscado en el servidor de producción, por ejemplo sustituyendo eval por una salida y llamando al archivo. Un solo error ahí ejecuta el código malicioso. El análisis pertenece a un entorno aislado.

Límites de la búsqueda por patrones

Los atacantes conocen los comandos de búsqueda habituales. Dividen los nombres de función, los componen en tiempo de ejecución o trasladan el código real a la base de datos, a archivos de imagen o a entradas de configuración. Una búsqueda por patrones encuentra por ello mucho, pero no todo. Por qué también los escáneres topan aquí con límites lo explica Escáneres de malware para sitios web: qué encuentran y qué no.

Además, un hallazgo rara vez es el único. Los atacantes suelen emplear en varios archivos el mismo bloque, por ejemplo un nombre de variable llamativo o una secuencia de caracteres característica al comienzo del bloque codificado. Tras un hallazgo confirmado, busque por ello de forma dirigida exactamente esa secuencia en todo el directorio web, también en otros sitios web del mismo servidor. Así encontrará hermanos que ninguna de las búsquedas por patrones generales ha captado.

Complete la búsqueda con la comparación con archivos originales y con una mirada a la base de datos, véase Revisar la base de datos en busca de código inyectado. Preventivamente se pueden bloquear las funciones del sistema que no se necesitan, como se describe en la guía Usar correctamente disable_functions.

¿Cómo ayuda PHP SOS en concreto?

  • Buscar: examinamos archivos y base de datos con patrones ampliados y contrastamos con paquetes originales.
  • Analizar: estudiamos el código sospechoso en un entorno aislado, sin poner en peligro su sistema.
  • Limpiar: con la eliminación de malware eliminamos todos los componentes y cerramos la vía de entrada.
  • Proteger: limitamos las funciones de PHP y los permisos de escritura y vigilamos los archivos nuevos o modificados.

Preguntas frecuentes

¿Es siempre código malicioso eval con base64_decode?

No siempre, pero sí muy a menudo. El código legítimo apenas necesita esta combinación. En archivos que no pertenecen a su aplicación ni a un plugin conocido, es una señal de alerta fuerte.

¿Puedo decodificar código ofuscado para leerlo?

Solo sin ejecutarlo y no en el servidor de producción. Incluso una ejecución accidental puede causar daños. En caso de duda, deje el análisis a especialistas que trabajan con entornos aislados.

¿Por qué no encuentra mi escáner de malware el código?

Los escáneres buscan patrones conocidos. Los atacantes modifican su código continuamente, dividen los nombres de función o los componen en tiempo de ejecución. Un análisis vacío no es por ello una prueba de que el servidor esté limpio.

¿Qué pasa con los plugins cifrados comercialmente?

Algunos fabricantes protegen su código con codificadores como ionCube o SourceGuardian. Esos archivos son ilegibles, pero legítimos si proceden del fabricante. Contrástelos con el paquete original.

¿Ayuda disable_functions contra el código ofuscado?

En parte. Funciones como exec o system se pueden bloquear, eval no, porque es una construcción del lenguaje y no una función. El bloqueo dificulta al atacante el siguiente paso, pero no impide todo código malicioso.

Fuentes

Contacto inmediato

Cada hora cuenta. Escríbanos ahora.

Describa brevemente el sistema, la versión de PHP y lo que ha observado. Nos pondremos en contacto, aclararemos la situación y trabajaremos en remoto hasta que el incidente quede cerrado y documentado.

Ayuda inmediata