CVE-2024-4439 Wordpress存储型XSS

6 分钟

前言

之前在机器人的信息推送中看到了Wordpress存储型的xss漏洞,虽然定义为了中危,并且评分只有5.9,但是这与以往不同的是这次的漏洞出现在了Wordpress本身,而不是它繁多的插件之中,不禁引发出了我的好奇。于是在空闲时间中,简单的看了一下漏洞的成因并做了复现,形成了以下一篇简单的文章。

image-20240509085227270

影响版本

上面阿里云显示的漏洞影响版本只说了一个6.5.2,并没有具体到细节的版本号,但是在wordpress官网中可以找到实际影响的版本,如下:

受影响的版本: 6.5 – 6.5.1、6.4 – 6.4.3、6.3 – 6.3.3、6.2 – 6.2.4、 6.1 – 6.1.5、6.0 – 6.0.7

完全补丁版本: 6.1.6、6.2.5、6.3.4、6.4.4、6.5.2

漏洞分析

这次的漏洞产生点并不能在默认的wordpress中,还需要对wordpress进行一些配置,主要产生存储型XSS的点是在文章评论的作者名称中,因为对文章作者的名称代码不恰当,导致了输入的作者名称没有经过任何的过滤就嵌入到了HTML的属性当中,导致了存储型XSS

关于头像的渲染的处理在wp-includes/blocks/avatar.php文件中,它的render_block_core_avatar对评论处的头像和名称等进行了渲染处理。

image-20240509091310506

这部分代码是对评论信息的一些处理,首先通过get_comment函数传入commentId获取评论的内容,这里是通过数据库中的索引字段commentId获取数据,获取到了内容之后,通过__函数将作者的名称进行翻译,以便于支持多语言。随后通过get_avatar()函数来获取评论者的头像,随后就进入到了if判断之中,当评论中的某些属性不为空,根据下面wordpress评论的一些属性信息,这里的条件检查应该是处理是否可以将评论者的头像作为链接显示,如果链接的目标是可以以_blank新窗口的方式打开,那么就会赋值$label属性。
if ( '_blank' === $attributes['linkTarget'] ) {
            $label = 'aria-label="' . sprintf( esc_attr__( '(%s website link, opens in a new tab)' ), $comment->comment_author ) . '"';
        }
        $avatar_block = sprintf( '<a href="%1$s" target="%2$s" %3$s class="wp-block-avatar__link">%4$s</a>', esc_url( $comment->comment_author_url ), esc_attr( $attributes['linkTarget'] ), $label, $avatar_block );
    }
return sprintf( '<div %1s>%2s</div>', $wrapper_attributes, $avatar_block );
其实这里一开始看并没有看出什么问题,细看会发现esc_attr__函数并没有包裹$comment->comment_author,也就是没有对$comment->comment_author进行处理,最终通过sprintf翻译输出了$comment->comment_author,在下面的代码中直接就将 $label嵌入到了 target="%2$s之后,这就导致了XSS的问题。

看回去esc_attr函数,这个函数的确保字符串在存储或输出前是有效的UTF-8格式,随后就调用了_wp_specialchars进行了处理。

image-20240509094545416

_wp_specialchars函数是进行了一些安全处理的,如果$comment->comment_author能经过这些处理,那么就不会产生xss的问题,因为在这个函数中,对能够造成xss的字符问题进行了实体的编码,防止了xss问题的产生。

function _wp_specialchars( $text, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
    $text = (string) $text;

    if ( 0 === strlen( $text ) ) {
        return '';
    }
    if ( ! preg_match( '/[&<>"\']/', $text ) ) {
        return $text;
    }
    if ( empty( $quote_style ) ) {
        $quote_style = ENT_NOQUOTES;
    } elseif ( ENT_XML1 === $quote_style ) {
        $quote_style = ENT_QUOTES | ENT_XML1;
    } elseif ( ! in_array( $quote_style, array( ENT_NOQUOTES, ENT_COMPAT, ENT_QUOTES, 'single', 'double' ), true ) ) {
        $quote_style = ENT_QUOTES;
    }
    if ( ! $charset ) {
        static $_charset = null;
        if ( ! isset( $_charset ) ) {
            $alloptions = wp_load_alloptions();
            $_charset   = isset( $alloptions['blog_charset'] ) ? $alloptions['blog_charset'] : '';
        }
        $charset = $_charset;
    }

    if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ), true ) ) {
        $charset = 'UTF-8';
    }

    $_quote_style = $quote_style;

    if ( 'double' === $quote_style ) {
        $quote_style  = ENT_COMPAT;
        $_quote_style = ENT_COMPAT;
    } elseif ( 'single' === $quote_style ) {
        $quote_style = ENT_NOQUOTES;
    }

    if ( ! $double_encode ) {
        $text = wp_kses_normalize_entities( $text, ( $quote_style & ENT_XML1 ) ? 'xml' : 'html' );
    }

    $text = htmlspecialchars( $text, $quote_style, $charset, $double_encode );
    if ( 'single' === $_quote_style ) {
        $text = str_replace( "'", '&#039;', $text );
    }

    return $text;
}

因此在修复的版本之中,可以看到wordpress官网只是把两个函数的顺序调换了一下,就完成了修复。感觉这是程序员在编码的时候疏忽大意造成的问题。

image-20240509094935326

漏洞复现

从上文的分析中可以看到,要在$label属性中带有comment->comment_author,需要进入到条件判断中,所以这并非是wordpress默认就能够产生的漏洞。在wordpress的主题编辑器中,点击评论的头像设置可以看到右方有两个属性,链接到用户个人资料和在新窗口打开,把两个按钮勾选上去,就是对应的条件判断。image_17151607843136

随后就可以进行评论,在评论中将作者的名字换成带有xss恶意语句的,这里一定要加上网站地址的信息,不然过不了条件判断。最终复现的结果如下:

image_17151607603655

总结

整个漏洞的成因是因为在评论头像处开启了新窗口和链接的配置后,在对$comment->comment_author的处理函数顺序反了,导致安全处理的函数没有对评论作者名进行实体转义编码处理,直接成为了HTML代码的一个属性,造成了XSS漏洞。

~  ~  The   End  ~  ~


 赏 
承蒙厚爱,倍感珍贵,我会继续努力哒!
logo图像
tips
(*) 8 + 7 =
快来做第一个评论的人吧~