Sí, está completamente abierto a la inyección de SQL, por ejemplo, a través de validUsername' injectionPayload %23
, lo que le daría esta consulta (el #
(codificado como %23
cortes del '
restante):
SELECT * FROM users WHERE name='validUsername' injectionPayload #'
En Outfile
dependiendo de los derechos del usuario, puede escribir contenido en un archivo con esta carga útil:
-1' UNION ALL SELECT 'injected string' INTO OUTFILE '/path/to/file.php' #
Inyección ciega (con credenciales de usuario válidas)
Con su código actual, es difícil obtener datos directamente de la base de datos. Solo utiliza la contraseña y el nombre, y ambos deben ser correctos, ya que de lo contrario su código no funcionará.
Pero este es un script de inicio de sesión, por lo que creará un resultado diferente para las credenciales de usuario válidas y para las no válidas, ¿correcto?
Como ese es el caso, se puede usar la inyección de SQL ciego estándar (si tiene credenciales de usuario válidas). Las cargas útiles se verían así:
// mysql 4 or 5?
validUsername' AND substring(version(), 1, 1)='5
validUsername' AND substring(version(), 1, 1)='4
// is first char of database hash smaller than ascii 100?
validUsername' AND ascii(substring((SELECT password FROM mysql.user LIMIT 0,1),1,1))<100 #
[...]
Y así sucesivamente. Lo que sucede es que combina la consulta con una pregunta booleana. Por ejemplo, does the database version start with a 5?
. Si la respuesta es true
, entonces todo funciona normalmente y usted está conectado. Si la respuesta es false
, no iniciará sesión, ya que la consulta no devolverá los datos y, por lo tanto, $numrows == 1
es falso.
Crea muchas solicitudes (especialmente para un script de inicio de sesión), pero es posible extraer datos.
Anulación de inicio de sesión
También debería ser posible omitir la página de inicio de sesión (inicie sesión como cualquier usuario si conoce el nombre de usuario pero no la contraseña):
-1' UNION ALL SELECT name, md5('password') FROM users WHERE name='attackedUser' #
No probé esto, pero qué debería suceder: el -1
elimina los resultados legítimos de su consulta, el union
agrega los resultados de la consulta inyectada, y la consulta inyectada obtiene el nombre de un usuario atacado y establece la contraseña en password
para esta solicitud (y usted envía password
como el valor POST para la contraseña).
Inyección ciega (sin credenciales de usuario válidas)
Como hemos visto en la sección anterior, realmente podemos establecer la contraseña, por lo que no necesitamos credenciales válidas para una inyección ciega. Puedes combinar el primer y el segundo atacante descritos, o puedo imaginar algo como esto:
-1' UNION ALL SELECT 1,md5(user) FROM mysql.user LIMIT 0,1 #
Esto es solo una cadena simplificada para mostrar la idea: nuevamente, elimina los datos válidos con -1
, agrega su consulta y selecciona como la contraseña los datos que desea extraer (md5 con hash, como el que se proporciona) la contraseña será hash). Luego, como la contraseña que envía a través de POST, envía el valor que adivina (por ejemplo, root
). Esos dos valores serán comparados a través de $password == $dbpass
. Si ha iniciado sesión, su conjetura es correcta, si no, entonces es incorrecto. Para adivinar los hashes de contraseña, puede utilizar el enfoque de subcadena desde arriba.
Conclusión
Incluso si piensa que la inyección de SQL que tiene no divulga ninguna información, debe usar declaraciones preparadas, ya que podría haber alguna forma de divulgar la información. E incluso si no existe en este momento, su código podría cambiar en el futuro.