您当前位置: 首页 » 未分类 » WordPress 4.2.2修复4.2.1中的截断Xss 补丁分析

WordPress 4.2.2修复4.2.1中的截断Xss 补丁分析

2015年5月8日 |

漏洞分析

在该次补丁的描述中,其中一条是修复了在4.2.1版本中的补丁bypass之后的xss问题,借此机会,下面分析一下在针对xss产生过程中所用的不同截断方法多次修复之后目前的具体验证流程。

补丁引入了两个开关变量
wp422/wp-includes/wp-db.php 2612行

 $truncate_by_byte_length = 'byte' === $value['length']['type'];
 $needs_validation = true;

两个开关默认都是true,$truncate_by_byte_length负责是否进行字节长度检测,$needs_validation从字面意思上可以理解为是否需要验证。两个开关可以在分工上做一个区分,如下:

$truncate_by_byte_length : 字节长度合规性验证,评论内容均会经过此验证。

$needs_validation : 针对多字节字符字符是否在合规范围内以及长度合规性验证,只有涉及多字节字符的字段才会经过此验证。

先来介绍第一个$truncate_by_byte_length
wp422/wp-includes/wp-db.php 2626行

 if ( $truncate_by_byte_length ) {
 mbstring_binary_safe_encoding();
 if ( false !== $length && strlen( $value['value'] ) > $length ) {
 $value['value'] = substr( $value['value'], 0, $length );
 }
 reset_mbstring_encoding();
 if ( ! $needs_validation ) {
 continue;
 }
 }

可以看到,该处解决了4.2.1中用mb_strlen来测量实际长度和规定长度上线之间的比较造成的问题,改用了strlen来测量长度,并且对超长的部分进行割舍,则不会产生之前由于长度单位不同而进行比较造成的4.2.1补丁绕过。
具体详情,可参见之前发出的Wordpress 4.2.1存储型xss的补丁绕过文章。

通过该验证之后,会开始进行判断,是否进入$needs_validation所代表的多字节的认证。

wp422/wp-includes/wp-db.php 2506行

protected function check_ascii( $string ) {
if ( function_exists( 'mb_check_encoding' ) ) {
if ( mb_check_encoding( $string, 'ASCII' ) ) {
return true;
}
} elseif ( ! preg_match( '/[^\x00-\x7F]/', $string ) ) {
return true;
}
return false;
}

该函数是用来看编码是否是ASCII或者是单字节字符,对返回结果进行判断后
wp422/wp-includes/wp-db.php 2620行

( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) )
) {
$truncate_by_byte_length = true;
$needs_validation = false;
}

如果是ascii编码或者是单字节字符,则关闭开关$needs_validation,不进行多字符验证过程。
(此处的多字节验证其实是为了防止之前出现的utf8四字节字符在数据库中产生截断,形成的xss)
wp422/wp-includes/wp-db.php 2638行

// utf8 can be handled by regex, which is a bunch faster than a DB lookup.
if ( ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) && function_exists( 'mb_strlen' ) ) {
$regex = '/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xE1-\xEC][\x80-\xBF]{2}
| \xED[\x80-\x9F][\x80-\xBF]
| [\xEE-\xEF][\x80-\xBF]{2}';
if ( 'utf8mb4' === $charset ) {
$regex .= '
| \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
| [\xF1-\xF3][\x80-\xBF]{3}
| \xF4[\x80-\x8F][\x80-\xBF]{2}
';
}
$regex .= '){1,40} # ...one or more times
)
| . # anything else
/x';
$value['value'] = preg_replace( $regex, '$1', $value['value'] );
if ( false !== $length && mb_strlen( $value['value'], 'UTF-8' ) > $length ) {
$value['value'] = mb_substr( $value['value'], 0, $length, 'UTF-8' );
}
continue;
}

可以看出,在这个过程中如果不是utf8mb4(该编码可以存储四字节字符,不会截断),则仅仅会取范围内的小于等于3字节UTF8字符,并且在范围中去掉了一些特殊字符,当取出之后,会按照当前多字节字符的编码长度再次确认。此处是针对小于4.2版本用四字节utf8字符插入数据库截断以及其他特殊字符截断而修补的。

相关链接

[1]http://php.net/manual/zh/function.mb-strlen.php

分类:

未分类

| 标签:

评论关闭。