Tema destacado: Suscripción al boletín mensual de elhacker.net
Autor
|
Tema: SQL Injection (Leído 6,061 veces)
|
kfault
Desconectado
Mensajes: 88
|
Pues voy a abrir una web y estoy haciendo muchas cosas en php y mysql entre ellas un sistema de miembros. Ahora, tengo una duda. En el codigo que hice para loguearte hice esto: <?php
include("connect.php");
if (isset($_POST['user'])) { $user = $_POST['user']; $pass = $_POST['pass']; if ($user == NULL || $pass == NULL) { echo "Faltan datos en el formulario."; } $pass_enc = md5($pass); $query = "SELECT * FROM users WHERE user = '$user' AND pass = '$pass_enc'"; $result = mysql_query($query); $count = mysql_num_rows($result); if ($count > 0) { echo "Logged in.<br />"; session_start(); $_SESSION['s_user'] = $user; $_SESSION['auth'] = true; header("Location: index.php"); } else { echo "Usario/Password Incorrecto."; die(); } }
?>
Bueno, segun lo que he leido de SQL Injection (quiero hacer mis aplicaciones seguras) la manera en que programe esto es vulnerable a algo como a' or 'a'='a creo yo que eso deberia de funcionar pero no funciona, siempre me da el mensaje de Usuario/Password Incorrecto. Quisiera saber si realmente es vulnerable y como lo puedo arreglar pues no quiero llevarme sorpresas despues cuando la web este en el servidor. Muchas Gracias y haber si alguien me puede ayudar. P.D. Olvide mencionar que este archivo es login2.php, en login.php tengo una forma con la action puesta en login2.php. Me refiero a que esta pagina procesa la informacion mandada por la forma.
|
|
|
|
|
En línea
|
|
|
|
Ertai
Ex-Staff
Desconectado
Mensajes: 2.026
Ralph Wiggum
|
No limpias la variable 'user', por allí te pueden meter algo. Te explico rápido. Si tienes... SELECT * FROM users WHERE user = '$user' AND pass = '$pass' Y supongamos que ahora meto de usuario admin y password ' or 'a'='a. Fijate como queda la query: SELECT * FROM users WHERE user = 'admin' AND pass = '' or 'a'='a' Lo ves?? Así te saltas la protección, porque inyectas un or de algo que siempre es cierto. Que es cierto? Que a=a. Espero que lo entiendas y veas la necesidad de limpiar la variable user. Leete las funciones ereg y eregi de PHP en www.php.net.Saludos.
|
|
|
|
|
En línea
|
Si la felicidad se comprara, entonces el dinero sería noble. void rotar_by_ref(int& a, int& b) { /* Quien dijo que no se podia sin una variable temporal? */ *a = *a ^ *b; *b = *a ^ *b; *a = *a ^ *b; }
|
|
|
Rentero
Ex-Staff
Desconectado
Mensajes: 1.163
La paciencia es la madre de la ciencia.
|
Algunas cosas mas: if ($user == NULL || $pass == NULL) { echo "Faltan datos en el formulario."; } Si el usuario o la contraseña no existen deberias de detener la ejecución del script. Sino no te sirve de nada mostrar un mensaje advirtiendo de eso. Para eso usa exit() o die() que son lo mismo xD. { echo "Logged in.<br />"; session_start(); $_SESSION['s_user'] = $user; $_SESSION['auth'] = true; header("Location: index.php"); } Cuando imprimes por pantalla algun mensaje como por ejemplo ese Logged in.<br /> no puedes volver a enviar cabeceras HTML. las funciones session_start() y header() deben de ir antes de que cualquier entidad HTML llegue al navegador. De todas forma no tiene sentido que muestres un mensaje de logueado y acto seguido redirecciones a index.php sin dar tiempo a que el usuario lea este mensaje  La parte de la seguridad, como te ha dicho Ertai, en la variable $pass no hay mucho riesgo puesto que usas md5() y da igual que datos maliciosos metan...siempre va a dar un hash como resultado. Pero no pasa lo mismo con $user. Tienes que filtrarla, puedes hacer uso de funciones como addslashes() para escapar las comillas y demas. Pero debes de tener cuidado de que magic_quotes_gpc no esté a ON porque sino te los escapará varias veces. Por ejemplo: <?php $apellido = "O'neil";
//con magic_quotes_gpc OFF echo addslashes($apellido); //devuelve O\'neil
//con magic_quotes_gpc ON echo addslashes($apellido); //devuelve O\\\'neil ?> Para sacarte del apuro puedes usar stripslashes() antes de addslashes() y así mas o menos solucionamos el problema de las magic_quotes. Después de toda esta tonteria te dejo un ejemplo  <?php session_start(); include_once("./connect.php");
function escapar($texto) { $texto = stripslashes($texto); $texto = addslashes($texto);
return $texto; }
if (isset($_POST["user"])) { if (empty($_POST["user"]) || empty($_POST["pass"])) die("Faltan datos en el formulario.");
$query = sprintf("SELECT * FROM users WHERE user = '%s' AND pass = '%s'", escapar($_POST["user"]), md5($_POST["pass"])); $result = mysql_query($query);
if (mysql_num_rows($result) == 1) { $_SESSION['s_user'] = escapar($_POST["user"]); $_SESSION['auth'] = true; header("Location: index.php"); }else die("Ese user/pass no existe en la base de datos."); } ?> No creo haberme equivocado, pero aún asi...es un ejemplo para mostrar lo que he dicho y para que te apolles en él xD. Saludos 
|
|
|
|
« Última modificación: 18 Abril 2006, 18:28 por Rentero »
|
En línea
|
Firmado.
|
|
|
kfault
Desconectado
Mensajes: 88
|
Muchas gracias a los dos, ya veo todos los errores que cometi. Buscare informacion de las funciones que me comentan y las agregare a mi codigo. Ahora, solo una pregunta, en user yo pongo lo que dijo Ertai (' or 'a'='a). Se supone que me podria loguear no es asi? Por lo menos eso es lo que entendi, y cuando lo pongo se va al mensaje de Usuario/Password Incorrecto, entonces no esta haciendo el SQL Injection o si? Muchas gracias de nuevo. 
|
|
|
|
|
En línea
|
|
|
|
kfault
Desconectado
Mensajes: 88
|
Ertai, busque en el manual de php las funciones ereg() y eregi() y entiendo que hacen pero no mencionan como se usan, me refiero a la sintaxis y demas. Tambien busque en google y para ser sincero no entiendo. Si tienes tiempo, me podrias dar un ejemplo de como se usan?
Muchas Gracias.
|
|
|
|
|
En línea
|
|
|
|
Rentero
Ex-Staff
Desconectado
Mensajes: 1.163
La paciencia es la madre de la ciencia.
|
ereg() y eregi() son funciones para el manejo de expresiones regulares. Que son las Expresiones Regulares
Las expresiones regulares son una serie de carácteres que forman un patrón, normalmente representativo de otro grupo de carácteres mayor, de tal forma que podemos comparar el patrón con otro conjunto de carácteres para ver las coincidencias. Si quieres aprender sobre EERR leete este texto...es muy interesante =) http://www.ignside.net/man/php/regex.phpNo tengo tiempo para responderte lo otro :S, si nadie te lo aclara luego te pongo un ejemplo...aunque te diré que lo que Ertai quiere decir es ponerlo en el password y te da usuario incorrecto puesto que usas md5() con lo cual...pongas lo que pongas siemrpe te va asalir una cadena de 32 bits totalmente distinta  Saludos 
|
|
|
|
|
En línea
|
Firmado.
|
|
|
|
Rey11
|
Pues yo uso esta función de fabricación casera: <?php function limpieza1($valor) { $valor = str_replace('"',"//////",$valor); $valor = str_replace("'","//////",$valor); $valor = str_replace("@","//////",$valor); $valor = str_replace("or","//////",$valor); $valor = str_replace("UNION","//////",$valor); $valor = str_replace("SELECT","//////",$valor); $valor = str_replace("%2527","//////",$valor); $valor = str_replace("%2725","//////",$valor); $valor = str_replace("%20","//////",$valor); $valor = str_replace("%27","/////",$valor); $valor = str_replace("-99","////",$valor); $valor = str_replace("--","////",$valor); $valor = str_replace("*/","////",$valor); $valor = str_replace("null","///////",$valor); $valor = str_replace("*","///////",$valor); return $valor; } ?> Saludos 
|
|
|
|
|
En línea
|
|
|
|
Rentero
Ex-Staff
Desconectado
Mensajes: 1.163
La paciencia es la madre de la ciencia.
|
Ya estoy aquí  Muchas gracias a los dos, ya veo todos los errores que cometi. Buscare informacion de las funciones que me comentan y las agregare a mi codigo. Ahora, solo una pregunta, en user yo pongo lo que dijo Ertai (' or 'a'='a). Se supone que me podria loguear no es asi? Por lo menos eso es lo que entendi, y cuando lo pongo se va al mensaje de Usuario/Password Incorrecto, entonces no esta haciendo el SQL Injection o si? Muchas gracias de nuevo.  NO. Y todo esto contando con que magic_quotes_gpc esté a OFF. Si está a ON escapará las comillas y no podrás hacer la inyección...al menos tan facilmente, ya se escapa de mis conocimientos  Sigo... En tu script inicial... Si pones ' or 'a'='a como usuario tu consulta quedaría así: SELECT * FROM users WHERE user='' or 'a'='a' AND pass='HASH_MD5' Con lo cual no encontraría ninguna coincidencia y $count no sería mayor de 0(cero) y te mostraría el mensaje de Usuario/Password Incorrecto. En cualquier caso...ya que no podemos sacar provecho de la variable $pass(porque usas md5()) podemos intentar sacar provecho de la variable $user(que no la filtras con nada). Podemos probar a insertar lo siguiente como usuario: admin' /* y poner cualquier password(cualquier cosa, por ejemplo: 135654) En este caso la consulta quedaría así: SELECT * FROM users WHERE user='admin' /*' AND pass='HASH_MD5' En este caso...entrariamos como el usuario admin directamente ya que al poner /* hacemos que el resto de la consulta sea un comentario  Bueno, no tengo tiempo para estenderme más...pero aquí tienes información para entretenerte un rato xDD Saludos 
|
|
|
|
|
En línea
|
Firmado.
|
|
|
kfault
Desconectado
Mensajes: 88
|
Muchas gracias, ya entiendo. Pues leere el texto que me diste y ya entiendo por que no funcionaba el sql injection. Ahora corregire mi script para hacerlo seguro.  Gracias de nuevo a todos.
|
|
|
|
|
En línea
|
|
|
|
kfault
Desconectado
Mensajes: 88
|
Jaja, no me lo vas a creer rentero pero el sql injection que pusiste, el de admin' /* tampoco funciona. Bueno sera por que magic_quotes_gpc tal vez este on. Bueno de todos modos corregire mi script.
|
|
|
|
|
En línea
|
|
|
|
Rentero
Ex-Staff
Desconectado
Mensajes: 1.163
La paciencia es la madre de la ciencia.
|
<?php echo get_magic_quotes_gpc(); ?> Si te devuelve 1 es que lo tienes ON, si te devuelve 0(cero) es que lo tienes OFF. - Si lo tienes ON ahí está la respuesta de porque no puedes "inyectar"...
- Si lo tienes OFF el problema puede ser que:
1.- No estas conectando a la base de datos(en tu script no se ve ninguna conexión..supongoq ue conectarás en connect.php jeje) 2.- Estas probando con admin' /* y en la base de datos que lo haces no existe ningún usuario llamado admin. Tienes que probar con un usuario que exista...sino...no estás haciendo nada. 3.- Algo que se escapa de mi escasa sabiduría xD [Añado] Si lo tienes ON y quieres probar para ver como es una inyección de código sql, solo por probar...puedes añadir esto a tu script. Pero recuerda eliminarlo de tu script final, o será vulnerable indudablemente  <?php //... //despues de $user = $_POST["user"]; $user = stripslashes($user); //... ?> Saludos 
|
|
|
|
« Última modificación: 18 Abril 2006, 22:20 por Rentero »
|
En línea
|
Firmado.
|
|
|
kfault
Desconectado
Mensajes: 88
|
Si esta on, era por eso. Y si conecto en connect.php  y estaba probando con un usuario que yo tenia creado. Bueno probare con poner eso en el script para ver como es la inyeccion. Gracias, un saludo.
|
|
|
|
|
En línea
|
|
|
|
kfault
Desconectado
Mensajes: 88
|
Oye rentero y crees que con solo poner el addslashes() y antes el stripslashes() (por si el servidor tiene magic_quotes_gpc = on) sea suficiente para que el script sea seguro? O filtro mas cosas? Gracias. 
|
|
|
|
|
En línea
|
|
|
|
Rentero
Ex-Staff
Desconectado
Mensajes: 1.163
La paciencia es la madre de la ciencia.
|
Oye rentero y crees que con solo poner el addslashes() y antes el stripslashes() (por si el servidor tiene magic_quotes_gpc = on) sea suficiente para que el script sea seguro? O filtro mas cosas? Gracias.  NO. Eso solo te sirve en gran parte para la base de datos. Pero no solo existen ataques de ese tipo. Por ejemplo. Ataques XSS mediante los cuales puedes insertar codigo HTML en tu pagina o incluso javascript. Para esto existen funciones como htmlentities() o htmlspecialchars(). Debes usarlas en todos aquellos lugares donde vallas a imprimir valores(ya sean recojidos desde bases de datos, cookies, variables de URL, etc) que el usuario pueda manipular. Ya tenga acceso directo a ellas o no. Por ejemplo: Imagina que tiene sun sistema de descargas... <?php //... $id = $_GET["id"]; echo "La ID de esta descarga es: $id"; //... ?> Si el usuario modifica la URL de esta forma: pagina.php?id=<script>alert('peligro!!')</script> Al entrar en ese página saltaría una alerta. Eso en principio no tiene peligro...pero podría hacer muchisimas cosas peligrosas coo por ejemplo: guardarse las cookies de los visitantes de esa pagina en una archivo, podría crear bucles infinitos para fastidiar, y muchas mas chorradas... En ese caso, podríamos usar cualquiera de los dos funciones anterior mente citadas para arreglar el error sobre la variable $id. Pero si nos paramos a pensar...vemos que $id queremos que reciba valores UNICA Y EXCLUSIVAMENTE numéricos...en ese caso, la mejor opción sería coprobar si $id es un número con is_int() o mejor aún...podríamos cambiar el tipo de valor de la variable a INT(numero entero) silenciosamente con settype() o intval(). Bueno, que me enroyo... Como he dicho...existen muchisimos tipos de ataques web. En lo que consiste basicamente es en comprobar que las variables que queremos usar contengan lo que nosotros queremos que contengan y en caso de que esto no ocurra tenemos que modificarlas silenciosamente o detener la ejecucion del script. Tengo que irme de nuevo...luego sigo  Saludos 
|
|
|
|
|
En línea
|
Firmado.
|
|
|
Ertai
Ex-Staff
Desconectado
Mensajes: 2.026
Ralph Wiggum
|
Otra vez yo. Te explico mi experiencia programando con PHP. Casi siempre puedes verificar datos usando la siguiente línea: if(!is_numeric($var)){ die(); } Esto lo uso siempre para el tema de los IDs que te comenta Rentero, ya que sobretodo programo sistemas de noticias, y sistemas de administración de contenido. Eso solo es interesante cuando la variable debe ser numérica. Si no lo es, tienes a tu disposición muchísimas funciones que ya se han comentado, pero sigo opinando que la mejor es ereg o eregi  Saludos.
|
|
|
|
|
En línea
|
Si la felicidad se comprara, entonces el dinero sería noble. void rotar_by_ref(int& a, int& b) { /* Quien dijo que no se podia sin una variable temporal? */ *a = *a ^ *b; *b = *a ^ *b; *a = *a ^ *b; }
|
|
|
|
|