WideByesInjection
Basic
UTF-8
UTF-8第一字节的取值范围是:00-7F、C2-F4
Mysql的utf8其实是阉割版utf-8编码,Mysql中的utf8字符集最长只支持三个字节,所以F0-F7也会无法被识别1
2三字节时, 首字节范围是[E0-EF][80-BF][80-BF]
四字节时, 首字节范围是[F0-F7][80-BF][80-BF][80-BF]
utf8mb4编码方式支持四字节的utf-8
mysql的字符解析
GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象,即将两个ascii字符误认为是一个宽字节字符。
1 | mysql> show variables like "character_set%"; |
set names gbk;
以后,character_set_client
、character_set_connection
、character_set_results
等与客户端相关的配置字符集都变成了gbk,但character_set_database
、character_set_server
等服务端相关的字符集还是utf8。
mysql api
mysql_set_charset(“utf8”, $link) (php5.2.3+)
规定当与数据库服务器进行数据传送时要使用的默认字符集,同时会设定好客户端的编码
mysql_query(“SET NAMES ‘UTF8’”);
- character_set_client
- character_set_connection
- character_set_results
mysql_client_encoding($link)
可以看到客户端编码
漏洞点
iconv
(PHP 4 >= 4.0.5, PHP 5, PHP 7)
1 | string iconv ( string $in_charset , string $out_charset , string $str ) |
将字符串 str 从 in_charset 转换编码到 out_charse
- 可以对用户名做如下处理
1 | $username = iconv('GBK', 'UTF-8', $_GET['para']); |
- 在character_set_client为binary情况下,只有借助其它函数的转换如iconv等来引入特殊字符。
mb_convert_encoding
1 | string mb_convert_encoding ( string $str , string $to_encoding [, mixed $from_encoding = mb_internal_encoding() ] ) |
$from_encoding用 “auto” 表示成 “ASCII,JIS,UTF-8,EUC-JP,SJIS” */
$str = mb_convert_encoding($str, “EUC-JP”, “auto”);
1 | $username = mb_convert_encoding($_GET['para'], 'utf-8', 'gbk'); |
mysql_real_escape_string+SET NAMES gbk
real_escape会根据客户端的设定进行过滤,但仅仅SET NAMES并不会改变客户端的编码,要mysql_set_charset才行
创建table时
create table … character_set=..
还有就是数据库创建或更改的时候改了服务器端的编码
PDO prepare预编译
https://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html
PHP<5.3.6时,还是存在WideByteInj的,本地模拟prepare后,再把完整的语句发送到mysql服务器
应该用ATTR_EMULATE_PREPARES来禁用prepare本地模拟
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
1 | $db=new PDO("mysql:host=localhost; dbname=demo", "user", "pass"); |
Exploit
服务器端解析为宽字符
和反斜杠一起解释成宽字节
绕过加上反斜杠的过滤addslashes等
client: utf8 — server: gbk
!! 如果一个字符uft8无法解码,则会去转化为ascii(255位版),但python的decode不会自动这样
1 | df5c |
客户端解析为宽字符
传入宽字符但被拆开
传入宽字符在server端被拆开成单字节,从而可以传入末尾以反斜杠结尾的字符来绕过
client big5 — server utf8
DDCTF2018 Web3 注入的奥妙
闭合单引号
1 | A45C |
payload:
1 | /well/getmessage/1豹' and 2=1 uniunionon select `id`,`pattern` COLLATE utf8_general_ci,`action` COLLATE utf8_general_ci from route_rules – – |
utf8_general_ci表示大小写不敏感