Wednesday, June 14, 2017

A Look at CVE-2017-8514 --- SharePoint's `Follow` Feature XSS

TL;DR: All your SharePoint installations are belong to us. The XSS (worth $2500) affecting both on-premises and online version looks like ...

http|https://<Any SharePoint URL Goes Here>?FollowSite=0&SiteName='-confirm(document.domain)-'

SharePoint needs no more marketing given it is one of the most popular enterprise content management systems. According to Redmond Magazine: "SharePoint and OneDrive are used by more than 75,000 customers, with more than 160 million users.". I am not a SharePoint MVP but as far as I can see, it comes in two flavors i.e., SharePoint on-premises and SharePoint online. Organizations prefer to use the on-premises model given it is in general only accessible over the intranet or internal network.  

One common use-case that I have seen or experienced in the organization is: There are many teams working in an organization for a day-to-day job e.g., HR, Marketing, Application, Legal and/or Security team etc. In SharePoint, one can have a dedicated site or page for a respective team where they can share relevant stuff (e.g., documents, news etc.) among team members and at the same time sharing outside the team is also possible. SharePoint provides fine-grained permission levels and role-based access control. 

SharePoint is all about sharing. In this line of direction, SharePoint provides a feature called "Follow" a site in order to get updates on site's activity in your newsfeed. One way to follow a site is to click on the "Follow" feature available at the top right of the page. It looks like ...

Follow a Site Feature in SharePoint

At this time, SharePoint sends a POST request to the following end-point: (bbmsft is the tenant name in my case and this will be different in your case). I played around with that POST request but was unable to find something interesting. I observed that this is not the only way to follow a site. You can also share your site(s) with others by using the Share feature available at the top right corner. Once you send out Share invitation, on the receiving end email looks like ...

The "Follow" feature as a part of email's content is now available in the form of a GET request. The URL at that time looks like:

The URL has two GET parameters i.e., FollowSite=1 and SiteName=<AnySiteNameGoesHere>. The FollowSite GET parameter holds a Boolean value of 0 or 1. 0 for not following and 1 for following. It is a sort of flag. The GET parameter SiteName is of our interest. It is reflected back as a part of script context like the following (watch out for the keyword ReflectionHere). In real life, this would be the name of site you want to follow.

<script type="text/javascript">
SP.SOD.executeFunc('followingcommon.js', 'FollowSiteFromEmail', function() { FollowSiteFromEmail('ReflectionHere'); });

As you can see in the above code, the developers're using single quote around ReflectionHere and I found that potentially dangerous characters like ', <> and / etc were not encoded. In order to keep it simple, the XSS payload like '-confirm(document.domain)-' should do the job for you. Further, I noticed that the above inline JavaScript code snippet only appears or  becomes a part of DOM if GET parameters (FollowSite and SiteName) are present in the URL. The screen-shot is given below.

A quick PoC of this XSS on one of the test-bed I had ...

Situation In the Wild:

The XSS looks simple because it only needs a SharePoint URL and simply add two GET parameters with one hold the XSS payload like:

http[s]://<SHAREPOINT URL>?FollowSite=0&SiteName='-confirm(document.domain)-'

Google dorking (inurl:SitePages/Home.aspx?) for SharePoint Home Page shows 19,000+ results. The SharePoint site's home page has a general format like http(s)://<Any SharePoint URL>/SitePages/Home.aspx. Some notable and vulnerable examples I was able to identify quickly from Google Dorks are given below. If you have a SharePoint site and you can see "Follow" feature on the page, than there is a great chance that you are vulnerable. Please keep in mind that following examples (Govt. sites, agencies, universities and colleges) does not include on-premises SharePoint installations.


Timeline and Bounty:

Reported to Microsoft on 20th February 2017
Triaged and Case # Assigned email from 20th February 2017 and Case # was 37482
Case Reproduction Email Confirmation from 28th February 2017
Bounty Qualifying Email from on 9th March 2017.
10th March 2017, email from regarding the bounty amount which was $2500.

On 9th June 2017, I received an email regarding fix and patch will be released as a part of June 2017 updates. Here is the link to CVE-2017-8514: Microsoft has also released a fix for a stored XSS I found in SharePoint Project Web App. CVE-2017-8551 is related to that. I will try to do a write-up on that later.    

I think, it's time to go and patch your SharePoint.

Sunday, April 17, 2016

Gone in Few Hours: Infooby's Fake or Questionable Bug Bounty Program

Bug bounty programs are great in many folds: learning perspective, monetary benefits for bug hunters and a step towards safe and secure web applications. Bug bounty programs are a win-win situation for both parties i.e., bug hunter(s) and the organization(s). The bug bounty hunters get money/reward (or entry in a hall of fame) for finding and reporting legitimate bugs, improve their pentesting skills by looking at the live targets and at the same time organizations improve their security by fixing the bugs reported by bug hunters around the world. Please keep in mind that bug hunters have different skills-set, mind-set and culture so organizations receive a variety of reports including high quality stuff. 

I like participating in bug bounty programs in my free and spare time (though I am not very active). Few days ago, when I was reading my Twitter feed, I came across the following Tweet by @disclosedh1.

"Curiosity killed the cat". I thought lets look at Infooby's web application for quick XSSing because in the program announcement (now gone and no more available), they're interested in having XSS reports. Initially, I have no idea that Infooby're acting maliciously and these guys have announced the program only to have the reports so that they can fix it and improve their web application. They wanted to have a win situation but only for them. One aspect of bug bounty program's announcement is marketing stunt or getting a media attention. I think Infooby wants limelight.

In a matter of few minutes, I found 2 XSS issues in their web application and reported these (#130596 & #130733) via Hackerone. One of the XSS is still live. Open the following URL in Firefox browser.

The screen-shot is also given below. The other XSS was here (now I think they fixed it):"><img src=x onerror=prompt(1);>.

I found 2 XSSes in quick time so I thought there're many more and I wanted to continue testing but soon started getting the error message i.e., "Resource limit is reached" and/or 508 status code and/or even site was getting down again and again. It shows that Infooby is not fully prepared for the initial onslaught from the HackerOne's community. The homework from Infooby's side was missing because if you will announce the bug bounty program, there is a great chance that several people will immediately start scanning your web application with the help of automation tools (may be as a part of initial and quick probe). The automation tools mean bombardment of attack payloads. The other testers have also noticed the error message and in the meantime, Infooby awarded someone a 20$ bounty but in the program announcement, they had mentioned the minimum bounty amount will be 50$. Meanwhile the Infooby's main site was going down and up again and again because of ongoing testing from the community.

On the next day, I received an email from HackerOne regarding the status of Infooby's bug bounty program. In short, it was no longer there. The contents of the email can be seen in the screen-shot.

It raises the following questions in my mind and still there are no clear answers. How can we stop this type of thing or fake/questionable bounty program in the future? What mediators or facilitators like HackerOne and BugCrowd can do in this regard? What happened to the bug reports (current status is "Not Applicable") Infooby had received in the meantime and Isn't they will fix bugs for free?
I think we can not stop announcement of fake bug bounty program(s) given if it is announced on the company's own web page. Any web site can do this and no one from outside can ask a question about its credibility given it is the company's sole jurisdiction. The bug bounty mediation/facilitator platforms like HackerOne and BugCrowd still can do something like e.g., "security deposit for guarantee or best practices". The idea is same as we see in real life e.g., if we rent a house or apartment, we used to pay some deposit and at the time of leaving the house, we normally get the money back. HackerOne and BugCrowd should ask for this deposit money in order to make sure that company is serious in bug bounty program and if in case company does some questionable practices, HackerOne and BugCrowd may take the money from this deposit or pool and distribute it to the valid bug submitters. If there will be a pool of money like that (e.g., initially it can be a pool of 5K USD per bug bounty program announcement) than there will be no more free bugs even if the bug bounty program is gone or vanish. This pool of money will motivate both parties to work in a best possible way.

Now a days, in general, we (i.e., bug submitters) participate in a bug bounty program like a race. We try to find bugs (especially low hanging fruits) as soon as possible, immediately after the program announcement, without keeping an eye on how genuine a bounty program is. I think this is the wrong approach at the moment (unless we have a deposit or pool as I mentioned earlier) given we do not know in start how reputable a program is. Believe me, the bugs are there and it is not necessarily to treat it like a race. Trust in your capabilities and you will find bugs given you will have enough motivation. Happy Hunting.

Note: If you guys have any other good idea on how can we stop fake program(s) or wants to share your bad experience(s) with the bug bounty program(s), please feel free to comment.  

Wednesday, April 6, 2016

Pairing Single Quotes

During pentest, I came across an interesting and unusual case where developers're trying to escape a single quote (') via a single quote (') in an script context. Further, I noticed that they were adding ' on the right hand side of the injected single quote. The developers're trying to have single quotes in pair but why? Are they trying to escape or something else? It sounds unfortunately funny and at the same time shows XSSing is not going anywhere in the near future.

The screen-shot given below shows the reflection of our interest. Please keep in mind that I had used the harmless XSS probe string i.e., "xxxxxxxx'yyyyy. The < sign is not part of probe string given site has enabled .NET's XSS protection. The site forcefully redirects me to an error page if I inject < character. 

It can be seen in the screen-shot above that site has added or appended an extra ' for escaping (the apparent reason I can think of) a single quote from the probe string. As you could aware of the fact that \ may be used as an escape character for ' and " quotes in an script context like \' and \" respectively. The site was adding/appending an extra ' as an escape character for the injected ' so payload(s) like '-confirm(1)-' and ');confirm(1);// do not work. Soon I realized during testing that \ is not escaped or controlled or filtered. The attack payload I used to XSS this case is: \');confirm(1);//. It starts with \'.  The screen-shot is given below and later I will explain why the payload works.

The attack payload was \');confirm(1);//. It starts with \' in order to make single quote as an escape character. After that application has added/appended one single quote because application developers want to have or see single quotes in pair. So we have a situation like this: '\''. It is perfectly legit given in a pair of single quotes there is an escaped single quote. After that ) character closes the function call prematurely followed by a semi-colon i.e., ; as a statement terminator. The next is a proof of concept JavaScript function call i.e., confirm(1); followed a single line comment i.e., // in order to avoid syntax error or neutralizes the effect of remaining parts of function call i.e., notyAlert. This XSS shows how one can leverage application's unusual functionality against it.

Sunday, February 28, 2016

Stored, Reflected and DOM XSS in Google for Work Connect (GWC)

Google for Work Connect (GWC) is "a community for system/application administrators and partners". GWC is in scope for Google bug bounty program though Google considers it a low priority application as far as reward amount is concerned. It is not about reward all the time. This blog (i.e., Respect XSS) is about XSS. Some time ago, I found Stored, Reflected and DOM XSS in GWC. 

Stored XSS

In GWC community, application administrators can share their ideas and help each other. The application allows users to create a document/posting/thread/message and among other features (e.g., mark as question, tags and category etc), the posting has a title or name and message body. The title of posting is of our interest in this case. The site was doing good in encoding < character into &lt; (if found in the title) (see screen-shot).

As you can see in the above screen-shot that < is encoded in an HTML context (i.e., <a> tag around reflection), so no need to waste time here. The site has another feature where one can do the same stuff but via Google Drive. The feature is labelled as "Add a file from Google Drive". In that case, at that time (now site has been updated and things may be bit different), the name of Google Drive file becomes the title of the post. The screen-shot shows the site's behavior when a file has been added from Google Drive. Please keep in mind that in Google Drive, I had first created a file named "xxxxxxxx'yyyyy</img>.PNG so that I can used that file here in GWC.

The screen-shot above shows reflection in GWC and and it can be seen that reflection was in script context in general and as a part of var declaration (i.e., object literal) in particular. The developers were using " for holding the title of file and at the same time, " and </ were not controlled or filtered or escaped. The XSS is now pretty straight forward, Please make sure that you have a file in Google Drive named </script><script>confirm(document.domain)</script>

This was an stored XSS because posting on GWC is available for all logged-in users. The root cause of this stored XSS was that GWC application forgot to control/encode/filter input from other application (i.e., Google Drive) though they were doing good on direct user-supplied input.

Reflected XSS

If somehow you're able to cause an error (e.g., file was not properly uploaded from Google Drive) in GWC then application throws an error message in a GET parameter named "googleDriveError". This GET parameter is vulnerable to a classical reflected XSS. Further if you're able to cause an authentication error, then application throws an error message as a part of GET parameter named "error". Both error related GET parameters were vulnerable and both were using the same code base. The screen-shot shows the reflection of our harmless probe string "xxxxxxxx'yyyyy</img as a part of  "googleDriveError" GET parameter.

It can be seen in the screen-shot that < is not filtered in an HTML context. It is enough of information. The next screen-shot shows reflected XSS in "googleDriveError" GET parameter followed by a reflected XSS in "error" GET parameter.


I also found a DOM XSS in GWC. The culprit for DOM XSS was window.location.hash.substring(1) but the problematic JavaScript code executes only if someone marked/clicked the reply of a posting "Mark as Helpful". The vulnerable dynamic JavaScript code was part of a JavaScript file at that time (site has been updated and you will see a not found message). The vulnerable JavaScript code looks like ...

... {if(window.location.hash){c.scrollTo("a[name='"+window.location.hash.substring(1)+"']")} ...

There are two screen-shots given below. One shows where posting has not been marked "Helpful" and one shows where posting has been marked "Helpful". The DOM XSS payload was part of both cases but executes only in the later case.

GWC received an update recently so there is a great chance that this update has introduced some bugs. Happy Hunting ...  

Sunday, February 14, 2016

Keep An Eye On $.html, $.get and $.ajax Functions

The $.html(), $.get() and $.ajax() are potential XSS venues. Some of you're already aware of this but lets see real life examples from the wild.  Finding a real example from the wild is itself not an easy task but fortunately, I live on the web in general and view-source in particular, so I found one. At the same time, instead of cosmetic bypasses i.e., bypasses based on assumptions or without examples or bypass for the sake of bypass, I am only interested in real cases. It is always good to see how developers use jQuery's features in the wild. Some time ago I did a blog post on third-party jQuery based sinks.


According to jQuery, $.html(htmlString) sets the HTML contents of each element in the set of matched elements. Please open the following URL.

The screen-shot shows the reflection of our interest i.e., in $.html(htmlString) function. The developers're using single quote for holding the HTML contents inside $.html(htmlString) function and it can be seen that ' from the probe string ( i.e., "xxxxxxxx'yyyyy</img) is not controlled.

The XSS in this case should not be a problem. The URL at the time of XSSing is given below and the screen-shot is also there.


According to jQuery, $.get() loads the date from the server via HTTP GET method. Open the following URL (q GET parameter holds our harmless XSS probe string i.e., "xxxxxxxx'yyyyy</img).  The screen-shot shows the reflection of probe string in $.get() function.

It can be seen in the screen-shot that developers're using " for holding the value of first parameter of $.get() function i.e., url and " is not filtered or encoded or escaped. The XSS in this case should not be a problem and it is simple and straight forward. The URL at the time of XSSing is given below and the screen-shot is also there.


It is used to perform asynchronous HTTP request. The screen-shot shows the reflection of XSS probe string inside $.ajax() function. The developers're using ' for the data section of $.ajax() and it can be seen that ' is not controlled. Further </ is also there in its hard-coded form. I would like to refer you to the article for the detailed syntax of $.ajax().

It is an easy and simple task to XSS this case given ' and </ are not controlled in $.ajax() function. The XSS attack payloads like '-confirm(1)-' and </script><script>confirm(1)</script> work here. I already explained in earlier posts how payloads like '-confirm(1)-' or "-confirm(1)-" work. The screen-shot shows an XSS.

Before conclusion, I would like to say that I am still looking at $.post() and $.load() based XSS in the wild ( both are also potential XSS venue ). If I will find one, I will update this post. I conclude on a saying: "Simplicity is natures first step, and the last of art." Philip James Bailey.

Sunday, February 7, 2016

Find The Root Cause

This time instead of publishing a new blog post, I present two real life XSS example cases from the wild. I already XSSed both cases for you. Your job is to find the root cause and explain it in the comment section or send it to me via Twitter or email. The first best detailed explanation of the following two real life example cases will receive a small token of appreciation from my side. 

1) Open the following URL in Firefox browser:

The screen-shot is also given below.

Your task is to explain how this XSS works to a naive user or beginner. A sort of indirect hint is available in one of my earlier blog posts.

2) Open the following URL in Chrome browser:

Isn't my harmless XSS probe string ("xxxxxxxx'yyyyy</img) part of URL :D The screen-shot is also given below.

Your task is to explain this XSS to a naive user or beginner. In fact the root cause of this XSS is: developers often do not follow the very basic and first principle of security.

I hope it would be fun.


-- Serious effort by @Zemnmez:

-- Attempt by @omeriko_9:

Sunday, January 31, 2016

The Magic of Connecting The Dots

Macy's ( calls itself "the magic of macy's" (at least the word magic is mentioned on their main home page logo). It has a global Alexa rank of 241 at the time of writing. It is a high profile web application. I think not from security perspective but from traffic point of view. Let the game begin. Please open the following URL (keyword GET parameter holds our harmless XSS probe string i.e., "xxxxxxxx'yyyyy</img). The following screen-shot shows reflection of our interest and some other cool things.

Lets start connecting few dots ...

The following line (in particular line #1911 in the screen-shot above and I marked it with label "Seems Interesting (3)") of JavaScript code (keywordsearch = kws.replace(/"/g,'\\\"');) replaces the " globally in the input with \\\" i.e., developers try to escape " with the help of three backslashes. Though escaping with three backslashes works fine given developers're using double quotes for holding the input in script context in general. Normally one backslash like \" (for double quotes) or \\ (for backslash) is enough (e.g., see line #21 in the source code in Chrome).

Note: FYI, on YouTube Gaming web site, you will find escaping with single backslash (i.e., \") and escaping with three backslashs (i.e., \\\") on the same page. Please see line #204 and line #200 in the source code in Chrome browser respectively.

So far so good from the application perspective but wait ... What about backslash (\) if injected in the attack payload? Are they escape backslash? Some of you might remember the blog post I did sometime ago and it was related to backslash. At that time I mentioned, my quest for backslash based XSS will continue and I think I am done with it (you will see when you're done reading this post). For example, open the following URL (\) and if you will look into the source code, backslash is not escaped (see screen-shot below).

The following XSS attack attack payload can do the job for us i.e., \"; confirm(1); //. The URL looks like:\";%20confirm(1);%20//. Some of you might be thinking why I started the payload with \. I explain but first look at the screen-shot of injection i.e., \"; confirm(1); //.

The injected XSS payload \"; confirm(1); // becomes \\\\"; confirm(1); // because " is replaced by \\\" in order to make it an escape character and at the same time, \ is not escaped. In short we have four backslashes in the reflection. Further, please remember, we're inside double quotes because developers're using them for keywordsearch variable declaration. The JavaScript code snippet looks like keywordsearch = "\\\\"; confirm(1); //"; How to interpret this code? The number of backslashes as far as one or three or five (i.e., odd number) is concerned, it is fine but if the count is even number i.e., two or four or six ... & so on then it will make the effect of escaping NULL N VOID.

In short, double quote is no more an escaping character because of four backslashes. The browser will consider it a proper closing double quote (in pair) for a variable declaration. In the XSS attack payload, now comes ; which is a statement terminator. It is followed by a proof of concept JavaScript function call i.e, confirm(1);. Last but not the least, we have a single line comment (i.e., //) in order to neutralize the effect of closing ";. It seems all set for an XSS and the following URL will result in an XSS:\";%20confirm(1);%20//. Unfortunately NOT... but why? The game is still on ... It is about connecting some dots.

If you look at one line (i.e., line #1949 because line #1950 is a comment ) above the keywordsearch variable declaration that holds our reflection then you will realize that there is a conditional statement and it is not executed. It means that the control never reaches at the reflection or injection point because the conditional statement evaluates to false at the moment. Why false? The conditional statement is:

if(currentPageUrl.indexOf("cm_kws")!= -1) 

while currentPageUrl is a variable i.e., var currentPageUrl = window.location.href.  The window.location.href returns the current location of the document and assigns it to the variable currentPageUrl. The URL at the moment is\%22;%20confirm(1);%20//. The JavaScript string function indexOf returns the first occurrence of the specified value, otherwise returns -1. The specified value in the indexOf function is "cm_kws". The current URL has no occurrence of "cm_kws". It means inside conditional statement, currentPageUrl.indexOf("cm_kws") evaluates to -1 and we all know that -1 != -1 is false :) The end goal is to make this conditional statement true so that the control reaches at the point of reflection and we will be able to execute JavaScript code of our choice.

I think, it is possible to force conditional statement so that it evaluates to true by appending the specified value i.e., "cm_kws" in the URL given currentPageUrl gets the value from window.location.href as I mentioned earlier and can be seen in the screen-shots. The job can be done by adding a new GET parameter named "cm_kws" like\%22;%20confirm(1);%20//&cm_kws or by simply padding the string "cm_kws" at the end of URL like\%22;%20confirm(1);%20//cm_kws.  In case of adding a new GET parameter "cm_kws", the statement currentPageUrl.indexOf("cm_kws") inside if evaluates to 66 and we all know 66 != -1 is true. In case of padding "cm_kws" at the end of URL, the statement inside if evaluates to 65 and we all know that 65 != -1 is true. The screen-shot given below shows the results of evaluation for better understanding.

It seems all set for an XSS i.e., dots have been connected. The following URL shows a confirm box followed by screen-shot.

For the sake of completeness, I wanted to XSS it with </script><script>confirm(1)</script> given in the reflection (see first screen-shot) </ is not filtered or encoded. The URL looks like ...

It has been blocked by some kind of protection layer. I think WAF or any other protection mechanism (e.g., IPS/IDS) stops the payload. The screen-shot shows Access Denied.

I had seen the same screen-shot on Akamai's site. It makes sense to believe or reasonable to believe that Akamai is not using other vendor's security solutions :) Isn't it? Akamai has its own WAF also i.e., Kona. Builtwith also gives some information that site is using Akamai's hosting services. Further, I am still interested if somebody will tell me or confirm which WAF is in place over there. Your feedback is always welcome.

WAF is meant to bypass and this one is not different. As I said earlier that </script> was blocked but </script%0Aanything> was not blocked. The following are quick bypasses and the screen-shot related to the second URL is also given below.

Before conclusion, I noticed that Macy's allowed to have single (') and double quotes (") in the product name (in case if required). I was thinking that it would not be easy for them to handle single (') and double quotes ("). For example, see the following two products ...

A question came to my mind: what will happen if I will do a search query of the product that have single (') and double quotes (") in their name. How site will treat it? Lets make a search query. I query for the following string i.e., a legit product name having both types of quotes ...

Under Armour Men's Raid Performance 10" Shorts

The resulting URL is:

It returns 3 results at the time of writing. Now lets look at the source code and try to figure out any thing interesting. As expected, site starts breaking itself :) The first thing I noticed is a legit search query breaks the attribute context (see screen-shot below).

The second interesting reflection in that case was in script context. It can be seen in the following screen-shot. The screen-shot shows that " from the product name is not escaped or filtered or encoded.

It means that we can leverage the " from the existing product name in constructing the XSS attack string. The XSS payload looks like (please see that the proof of concept JavaScript code does not start with " because we will use the " from the product name):


Now combine this proof of concept XSS payload with the legit search query we made earlier. The final attack string will be ...

                        Under Armour Men's Raid Performance 10"-confirm(1)-" Shorts

The URL at the time of XSS is given below followed by a screen-shot.

I conclude on a saying: "When You Really Pay Attention, Everything Is Your Teacher." (Ezra Bayda)