¿Por qué funcionó esta entrada en particular para la inyección de SQL?

3

Estoy estudiando infosec, comenzando a abrirme camino a través de algunos de los juegos de guerra en línea que hay. Recientemente he estado trabajando en Natas por OverTheWire ( enlace ) y hasta ahora ha sido muy divertido. Mi pregunta está relacionada con uno de los desafíos en el juego.

** SPOILERS PARA EL JUEGO SIGUE **

En uno de los niveles, tengo mi primer encuentro con mysql. El código de fondo se ve así (el juego te permite ver el código php para cada función, al menos al principio):

<?
if(array_key_exists("username", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas14', '<censored>');
mysql_select_db('natas14', $link);

$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
if(array_key_exists("debug", $_GET)) {
    echo "Executing query: $query<br>";
}

if(mysql_num_rows(mysql_query($query, $link)) > 0) {
        echo "Successful login! The password for natas15 is <censored><br>";
} else {
        echo "Access denied!<br>";
}

mysql_close($link);
} else {
?>

<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?> 

Comencé a investigar la inyección de SQL, e intenté algunas cosas básicas como foo OR 1=1 como entrada, pero no conseguí nada. Miré el código e intenté insertar citas con mi entrada, lo que me arrojaría errores cuando tuviera una cantidad impar de citas en la entrada, pero no sabía a dónde ir desde allí.

Finalmente, comencé a trabajar en la página de OWASP sobre las pruebas de inyección de SQL, y durante la prueba de sus ejemplos, encontré algo que se decía que debía intentar:

$username = 1' or '1' = '1
$password = 1' or '1' = '1

Eso no funcionó, pero por alguna razón, mi intuición dijo que cambiara el primer ' a " en la entrada $ username, y el último ' a " en la entrada $ password. Así se convirtió

$username = 1" or '1' = '1 
$password = 1' or '1' = "1'

Y ... funcionó. Satisfecho la condición para este bloque.

if(mysql_num_rows(mysql_query($query, $link)) > 0) {
    echo "Successful login! The password for natas15 is <censored><br>";
} else {
    echo "Access denied!<br>";
}

y me dio la contraseña para el siguiente nivel.

Mi pregunta es ... ¿POR QUÉ? No sé lo suficiente sobre la inyección de SQL ya que obviamente soy un noob, pero no entiendo lo que está sucediendo exactamente en el servidor de SQL con esa entrada en particular.

Para reiterar, la consulta tiene este aspecto (utilicé la función de depuración en el código anterior para imprimirla):

Executing query: SELECT * from users where username="1" or '1' = '1" and password="1' or '1' = "1"'

¿Cuál es el comportamiento de esta consulta, y cómo lo está evaluando sql para darme una salida VERDADERA en ambas entradas (al menos supongo que eso es lo que está haciendo ...)? Siempre que cambio el " a ' en cualquier otra configuración dentro de la consulta, falla. Y el hecho de que haya un número impar de " y ' dentro de la consulta me está volviendo loco.

Cualquier consejo o explicación sería muy apreciado. ¡Siento que realmente no habré pasado este nivel hasta que entienda lo que está sucediendo!

    
pregunta winter 04.02.2018 - 04:39
fuente

2 respuestas

3
  

Cada vez que cambio el " a ' en cualquier otra configuración dentro de la consulta, falla.

Eso sería:

SELECT * from users where
    username = "1' or '1' = '1"
and
    password = "1' or '1' = '1"

Esto falla porque literalmente estás buscando un usuario llamado 1' or '1' = '1 con una contraseña 1' or '1' = '1 . Si quiere escapar de las comillas dobles, necesita usar comillas dobles usted mismo, como lo hizo. Esta es su consulta exitosa reformateada:

SELECT * from users where
    username = "1"
or
    '1' = '1" and password="1'
or
    '1' = "1"

Dado que '1' == "1" , esto se evalúa como verdadero.

  

Y el hecho de que haya un número impar de " y ' dentro de la consulta me está volviendo loco.

En realidad no hay un desequilibrio de citas. En particular, '1" and password="1' es una cadena entre comillas simples que solo tiene espacios y comillas dobles dentro.

    
respondido por el Arminius 04.02.2018 - 14:23
fuente
1

En su consulta:

SELECT * from users where username="1" or '1' = '1" and password="1' or '1' = "1"

username="1" se evalúa como falso

'1' = '1" and password="1' se evalúa como falso, ya que no se confunden con comillas dobles, se tratan como una cadena normal porque están dentro de comillas simples

'1' = "1" se evalúa como verdadero, porque puedes usar comillas simples y comillas dobles, y en ambos lados tienes la misma cadena "1"

Ya que tiene OR entre estas declaraciones, es suficiente que solo una de ellas se evalúe como verdadera, para que coincida con todas las filas. De esta manera, la consulta extrae todas las filas de la tabla, porque 1 = 1 es verdadero para todas las filas, y el script evalúa la primera fila, que en realidad es lo que es interesante.

    
respondido por el Aria 04.02.2018 - 14:25
fuente

Lea otras preguntas en las etiquetas