Bridging The Security Gap
During our penetration testing activities, we are often confronted with environments that are constructed using off-the-shelf or open source third-party components / frameworks. Although off-the-shelf or open source may suggest a certain level security, we always advise to include such elements in the scope of the test, as you never know what you may find.
To raise awareness of the importance of including third party components in penetration tests or security assessments, we’re starting a series of blog posts about real life vulnerabilities we have found in third party components. Of course, we do not intend to put anybody unnecessarily at risk, so we will only post details on vulnerabilities after following a responsible disclosure procedure and giving vendors a reasonable oppertunity to fix the issue and inform their customers.
Today, we’ll be looking at a vulnerability we found in the Telerik UI for ASP.NET AJAX, which has been assigned CVE-2014-2217.
For those who are too lazy to read the entire post and just want the facts:
- Affected control: RadAsyncUpload
- Affected versions: Release Q3 2012 SP1 and earlier
- Attack method: Path Traversal
- Impact: arbitrary file write (append mode)
- Fix: Telerik had silently fixed this issue in Q3 2012 SP2. After our vulnerability report and subsequent communication about its impact, Telerik has created updated versions of previous Service Packs for customers who wish to maintain their current version (as Telerik UI is not fully backwards compatible).
For everybody else, the whole story:
As we were going through an applications wihtin one of our penetration test, we came upon a file upload functionality. Although uploading seemed to fail for our user, we still decided that it might be interesting to have a look at how it worked and try to understand what was failing. Perhaps if we understood what prevented us from uploading, we might be able to circumvent it and escalate our privileges.
So we started looking at the HTML and the requests and found out that we were working with a Telerik RadAsyncUpload control, which is part of their UI for ASP.NET AJAX.
For those who don’t know, Telerik is a company that develops products for (web) application developers, focusing largely on UI components for a variety of development platforms. According to their webpage:
‘Telerik’s products are used by 1M+ developers at 100K+ ISVs, corporations and educational, governmental and non-profit organizations in 94 countries.’
UI for ASP.NET AJAX is pretty much exactly what it says on the can: as a part of their UI series, it is a set of User Interface controls that can be used in the creation of fancy ASP.NET AJAX web applications. The various controls it offers are also known as RadControls and their presence in a webapplication can be easily detected by looking at the HTML of a webpage and looking for any class names starting with “Rad”:
(The above code snippet is taken from Telerik’s demo for the RadAsyncUpload control, running in one of our lab environments. Although the issue was found in a live environment, we will use this lab environment throughout this post to protect our client’s privacy.)
So, now that we knew what we were talking with, it was time to determine how it worked.
Step 1: dissecting the upload request.
When we tried to upload a file using a RadAsyncUpload control, the browser sent an HTTP POST request to the Telerik handler called Telerik.Web.UI.WebResource.axd. This POST request included several parameters:
- rauPostData, which contained two base64 encoded strings, separated by an ampersand (&)
- file, which contained our uploaded file
- fileName, which contained the name of our uploaded file
- contentType, which contained the MIME type of our file
- metadata, which contained some metadata about our asynchronous upload, such as an upload id, chunk index and total number of chunks.
The response to this request was a JSON object, which reflected our filename, content-type, content-length and chunk index, and added a base64-encoded ‘metadata’ string.
Decoding the various base64 encoded strings, we found that they contain some interesting data:
- The decoded rauPostData contains a JSON object with two interesting base64 encoded strings called TargetFolder and TempTargetFolder, which (when decoded) point to directories on the web server.
- The decoded ‘metadata’ from the response contains a JSON object with a string called TempFileName, which corresponds with the “UploadID” value that was sent in the metadata parameter of our request.
So this suggests two things:
- Our uploaded chunks are stored as files in a directory that is specified by our rauPostData
- The filename that is used to store these chunks are directly specified by the UploadID in the metadata parameter
If one or both of these suggestions are true, then we might be able to manipulate the location where our files are written, along with their name.
Step 2: verifying our suspicions
To verify whether we are dealing with an exploitable component, we first started manipulating the rauPostData parameter. Sadly, this was not as easy as it would seem.
As can be seen in the Burp screenshot, the JSON object is surrounded by some non-printable bytes and includes a PublicKeyToken. This suggests that the control uses some sort of signature scheme. And indeed, as soon as we started manipulating the (base64 encoded) contents of the JSON object, our requests started failing.
Although we could have tried to attack the signature scheme (as these are easy to get wrong), we decided to move on and focus on the metadata parameter.
To verify whether the metadata UploadID is indeed used to specify our target file and we can be used to do some exploitation, we first tried to specify a filename that would result in a harmless file that would be accessible from the webroot. To create this filename, we used our knowledge of the TempTargetFolder, together with a previously found information leakage that disclose the location of the webroot.
In the case of our demo environment, we had to go from:
so we used:
as our UploadID.
Then, after sending the request, we checked whether the TempFileName in the response included our specified directories. When we saw that the directories were used, we tried downloading our little egg.txt and found that we had succesfully written to the webroot.
From here, we knew that we had found a nice little path traversal bug and we were in business.
After some more tests, we found that path traversal wasn’t even necessary, as we could also specify absolute paths (instead of just relative paths). As ASP.NET applications usually live on a Windows platform, this increased the impact of this little bug. With relative paths / regular path traversal attacks in Windows, you are restricted to whichever drive the current working directory lives in (C:\, D:\, etc.). That is because Windows doesn’t allow you to switch drive through relative paths. So, if our upload directory had been located on a different drive, we wouldn’t have been able to traverse to the webroot with just a relative path. Instead, we’d have to set our UploadID directly to C:\inetpub\wwwroot\RadAsyncUploadTest.
Step 3: Profit!
Now that we knew we could upload files, we just had to test whether the there were any components in place that filtered specific extensions or file contents. Although there did seem to be some filtering, we soon found a format in which we could upload our own little aspx web shell and gained code execution on the server. Together with all the juicy connection strings in the application’s web.config files, this gave us a nice foothold to attack the rest of the network, which ultimately led to a full compromise of environment.
The post Arbitrary file write in Telerik UI for ASP.NET AJAX appeared first on ITQ.