One of the few interesting exploits that I could find includes the ability to download the source code of ASPX pages whose address is known in advance and accessible from outside. This vulnerability exists only in SharePoint 2007, and the exploit is quite simple:
This could be useful, if the website has proprietary code. But you still need to know the address of specific page.
By digging a little deeper, I found that SharePoint contains a number of interesting web services that can be accessed by a user who logged into the website with read rights.
You can find these services and their description in the directory ‘_vti_bin’. Here are a couple of examples of what the path may look like:
This directory and services are bound directly to the website hosted on SharePoint Server. That is, if I have several websites in ‘host/sites/’, then, to take full advantage of this technique, I need to access services within the directory of each website. Describing all these services in this article doesn’t make sense. I will discuss a couple of those that allowed me to successfully grab someone else’s domain account during an internal audit.
So, we have a website on SharePoint, and we can log into it. To grab someone else’s account, it is a good idea to know his/her name and whether he/she represents any interest. Here, you can fight by using an old technique of listing the users, which may look like this:
Increment ID, and read the information about the user (Fig. 2).
But what to do, if the company has ‘over 9000’ users? It is very time-consuming and inconvenient to always increment manually or write your own script and attach to it the functionality of NTLM or KERBEROS domain authentication. In this case, you can rely on services that I have already mentioned. These include a very interesting service ‘UserGroup.asmx’, which allows you to get, at once, the list of all users of the website in the form of XML by using a single query.
This query is quite simple:
POST /sites/testsite1/_vti_bin/UserGroup.asmx HTTP/1.1 Host: host […] <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUserCollectionFromSite xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/" /> </soap:Body> </soap:Envelope>
As a result, we have an XML document with the list of all users (see. Fig. 3).
Fig. 4 and 5 show that we get, at once, the list of all users of the website, including their e-mail addresses, SID, ID, etc.
I mentioned ‘over 9000’ users for a good reason. In my practice, I constantly face such situations and, for me, this method of enumeration is very useful.
A simple search through the user list generally reveals a lot of test accounts. As you probably have noticed, our testing company has a multi-domain structure. It is natural to assume that different RND domains or different users may have different access rights. By using a simple brute force attack, such as ‘uname = pwd’ or ‘pwd = 111111’, we can get access to another domain account (Fig. 6).
This is a seemingly simple feature of SharePoint, but the result is the compromise of the test account. Within the company, a ‘disgruntled employee’ or, as it goes in Hollywood movies, a ‘concerned citizen’ can use a test account to carry out attacks while disguising himself/herself and making his/her detection more difficult.
Similarly, by using this service, you can view a list of groups and check which group includes the user. This may be interesting because grabbing the accounts of the user from the website owner group or the user with permissions to post HTML pages on the website will be a more fascinating task.
Sample query for getting a list of groups may look as follows:
POST /_vti_bin/UserGroup.asmx HTTP/1.1 Host: host […] <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetGroupCollectionFromSite xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/" /> </soap:Body> </soap:Envelope>
As a result, we will receive a list of groups on the website, which, in addition to standard groups, may include custom groups with their permission masks.
Selecting the Tidbits
As I already mentioned, when the “victim” is chosen, we need to know whether it is worth trying to attack his/her password. To do this, you can find out what groups include the selected account. When attacking a password, do not forget about password policy, which could play a nasty trick on the attacker and reveal his/her presence to network administrators.
Here is an example for a system account ‘SHAREPOINT\system’:
POST /_vti_bin/UserGroup.asmx HTTP/1.1 Host: host […] <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetGroupCollectionFromUser xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/"> <userLoginName>SHAREPOINT\system</userLoginName> </GetGroupCollectionFromUser> </soap:Body> </soap:Envelope>
Again, we get back an XML document with information about the list of groups which include the user (see Fig. 9).
As you can see, the account is bound to a large number of interesting groups.
The service ‘Permissions.asmx’ located in the same directory ‘_vti_bin’ is created for working with user permissions. It allows only a few methods (Fig. 10) but all of them are interesting in terms of security or functionality.
For me, the most interesting method was ‘AddPermission’. As any other method, it has been sufficiently well described (msdn.microsoft.com/RU-RU/library/permissions.permissions.addpermission (v = Oct. 12) .aspx) in order to create a query to the service.
In my following query, I try to add the rights for a restricted user:
POST /_vti_bin/Permissions.asmx HTTP/1.1 Host: host […] <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <AddPermission xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/"> <objectName>testsite1</objectName> <objectType>web</objectType> <permissionIdentifier>i:0#.w|ra1d3n\test3</permissionIdentifier> <permissionType>User</permissionType> <permissionMask>-1</permissionMask> </AddPermission> </soap:Body> </soap:Envelope>
A little more details about these parameters:
- ‘testsite1’ — specify the name of the object; in this case, it’s the name of the website;
- ‘web’ — specify the type of the object;
- ‘i:0#.w|ra1d3n\test3’ — specify for whom we want to apply the rights;
- ‘User’ — specify that these rights are for a user;
- ‘-1’ — set the permission mask for the website owner.
I would like to mention that we cannot always know the value of permission mask available on the website but, in my experience, for the website owners, the value is always ‘1’. You can get a permission list for the website by using ‘GetPermissionCollection’ method. However, the restricted user will not always have access to this method.
It is natural to assume that, if you make a query from the context of restricted user, the server will reject it, but if you wriggle a little with ‘XMLHttpRequest’ and use the fact that ‘CORS’ only restricts our use of other hosts, then I think it is clear what vulnerability could be exploited to obtain the required rights. Similarly, this method can be useful, if the user has the rights to post HTML pages on the website.
Today, we covered only a fraction of services that I had tested in my research. It is natural to assume that, after obtaining the administrator rights on a SharePoint website, one might have a great desire not only to read someone else’s data but also to execute the operating system commands. Here the battle requires your skills in mastering C#, ASP and .NET platform. These tricks work in all versions of SP that I was able to test (from 2007 to 2013). Over time, I will prepare some even more interesting tricks but, for now, the disclosure policy restricts me from doing this.