This post discusses WordPress Comment XSS affecting version 4.2 or below. I have outlined the internal working of this specific XSS.

28-Apr-2015: UPDATE: WordPress has released an official fix. https://wordpress.org/news/2015/04/wordpress-4-2-1/

29-Apr-2015: UPDATE2: added detailed Response text for reference purposes and to showcase how it was exploited.

29-apr-2015: Update3: Some more details added

14-may-2015 : update 4 : added baidu link (chinese)

———————————————————————————————————

Today a post was made by Jouko Pynnönen of Klikki Oy Describing a XSS scenario which affects WordPress 4.2, 4.1.2, and 4.1.1, MySQL versions 5.1.53 and 5.5.41 to the least and might have affect over previous version’s also.

Understanding the bug

In short the bug is in the process of xss filtering and storage. The comment is first sent through various filters and at the end is stored in the database. The PoC code validates on all the checks however when it is suppose to be stored in DB the mysql db column for comment data has a hardlimit of 64kb and hence the data is truncated to store only 64kb. This causes the input to be stripped and hence the new payload is able to cause an XSS. This causes the issue when the comment is viewed in the front end. At this point as per my checks its not affecting backend and backend can see comment as is.

Refer to the end of post for a PoC code and response output.

This comment was seen as following at the backend.

In Recent activities section



In Comments page



However on front end you can see that the JavaScript execution takes place.



SOLUTION

I have devised a simple fix for the above problem at a server level.

I have used Nginx server however a similar configuration should be possible at other servers also.

Here is a sample configuration of my test box. Refer to the section “FIX for WordPress Comment XSS”.



server {

listen 80 default_server;

listen [::]:80 default_server ipv6only=on;

client_max_body_size 100M;

root /wordpress;

index index.php;

server_name 172.28.128.11;

location / {

try_files $uri $uri/ /index.php?$args;

}



##

## FIX for WordPress Comment XSS

##

location ~ wp-comments-post.php$ {

client_max_body_size 64K;

try_files $uri =404;

fastcgi_split_path_info ^(.+?\.php)(/.*)$;

if (!-f $document_root$fastcgi_script_name) {

return 404;

}

include fastcgi_params;

fastcgi_pass unix:/var/run/php5-fpm.sock;

}

##

## FIX ends Here

##



location ~ \.php$ {

try_files $uri =404;

fastcgi_split_path_info ^(.+?\.php)(/.*)$;

if (!-f $document_root$fastcgi_script_name) {

return 404;

}

include fastcgi_params;

fastcgi_pass unix:/var/run/php5-fpm.sock;

}

}



This configuration basically applies a hard limit of 64KB over data sent to wp-comments-post.php which is responsible for posting comment. as we already know anything more than 64kb is not going to be retained hence there is no point allowing this request.

Just to be sure that this doesn’t affect any other section i tried uploading a large file and it all went smoothly.

Attack Detection via error_log

If you are concerned about the logs you will start seeing following style logs in your error_log when someone tries this attack.



2015/04/27 09:17:08 [error] 19317#0: *9 client intended to send too large body: 65835 bytes, client: 172.28.128.1, server: 172.28.128.11, request: "POST /wp-comments-post.php HTTP/1.1", host: "172.28.128.11", referrer: "http://172.28.128.11/?p=1"



Also just to emphasis on the fact this issue is already being exploited in wild now.

@ethicalhack3r @BrianHonan @nacin Thanks. I've just emailed security@wordpress.org. It looks like an elaborate version of that 0day. — David Coallier (@davidcoallier) April 27, 2015

If you feel this might be wrong assumption or some workaround is possible for this feel free to suggest alternatives or criticise fix.

Sample PoC

For testing purposes following PoC was used.



<a title='x onmouseover=alert(unescape(/hello%20world/.source))

style=position:absolute;left:0;top:0;width:5000px;height:5000px

AAAAAAAAAAAA [64 kb] ...'></a>



This code results in following response