An ever increasing number of modern web applications are created using open source web frameworks and libraries. Open Source Content Management Systems are a popular example for quickly and easily creating and publishing web content with a professional, polished appearance. However, look closely under the hood of a typical CMS-developed site and you’ll often find a mass of (often unintentionally) exposed attack surface.
When I encounter an Open Source framework in a black-box security assessment, I will look into creating a local “reference instance”: a local version of the remote target site/application (or as much of it as possible) that is completely under my control. This effectively moves a large percentage of the assessment from a black-box test to grey-box. Why? Because using this technique I can find a greater number of security bugs in a much shorter timeframe.
However; installing and configuring a local reference can sometimes be quite time consuming. With every minute diverted away from testing often having to be justified, what is required is a means to easily and reliably ‘spin up’ a testing environment containing the targeted web framework/component as quickly as possible.
Where the target OS is Linux-based, I’ll reach for a virtual machine ‘application stack’ like Bitnami; but what about Windows-based frameworks?
Enter Microsoft WebMatrix. WebMatrix is a web application deployment technology that allows users to easily install dynamic web applications. You need a host system with Windows 7 to take full advantage of WebMatrix, however with that you can easily and legally install everything you need to need to create a local instance of more than 50+ web applications falling into seven key categories, namely: blogs, CMS, eCommerce, Forums, Galleries, Tools, and Wiki. The initial install and ensuing patching frenzy can take about an hour to complete. After that, installing and running a new dynamic web application usually takes no more than a few minutes.
Attacking Umbraco – A Real Life Example
Note – The vulnerabilities described below were reported to the vendor and patched in September 2011.
During an engagement last year, I used WebMatrix to create a local instance of the Umbraco CMS and identified a number of vulnerabilities in Umbraco CMS 4.7.0. Two of which, when combined, permitted an unauthorised remote attacker to write arbitrary content into the CMS web root. I then used this to place a simple web shell on the target, resulting in arbitrary remote code execution. What follows is a blow by blow description of the how the issues were found.
Once I have a local WebMatrix instance set up containing the targeted framework, I usually begin by locating any administrative login pages in my local instance and verifying whether these are accessible on the remote target. It’s not uncommon to find a CMS administrative login page located in a subdirectory of an internet-exposed application, and accessible to anyone with knowledge of the right URL.
Once I have identified the location of the CMS directory in the remote target, I enumerate the exposed attack surface by grabbing a file listing of my local instance CMS directory contents, and feeding this into Burp Intruder to identify any pages that are accessible without authentication.
In addition to creating a list of accessible pages (by enumerating requests that result in HTTP status code 200 responses) I also look into responses that return HTTP status 302 and 500 responses. Sometimes you’ll see a ‘long 302’, where the application redirects the browser back to a login page or an error page, but includes sensitive content in the body of the 302 (possibly as a result of an Execute After Redirect vulnerability).
While enumerating functionality exposed to unauthenticated users using the directory listing and Burp Intruder, it became clear that Umbraco was exposing a number of web services. These web services were not apparent during normal use of the “parent” application leveraging the Umbraco functionality.
Each web service published a service description, which provided all the information required to interact with each web service operation. Most of the interesting operations required credentials in the form of a username/password pair.
An operation called SaveDLRScript (published as part of the codeEditorSave web service) caught my eye as it did not require credentials, and received string values for fileName and fileContents parameters. With a few adjustments (thanks to the help of some verbose SOAP error messages), I was able to create a suitable unauthenticated POST request that caused SaveDLRScript to write out a text file on the host:
POST /build/umbraco/webservices/codeEditorSave.asmx HTTP/1.1 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length: 516 SOAPAction: "http://tempuri.org/SaveDLRScript" Connection: close <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <SaveDLRScript xmlns="http://tempuri.org/"> <fileName>test.text</fileName> <oldName>string</oldName> <fileContents> test </fileContents> <ignoreDebugging>1</ignoreDebugging> </SaveDLRScript> </soap:Body> </soap:Envelope></p>
As a result of issuing the POST request, a ‘true’ message was returned. But where was my text file? In a black-box test I’d have to issue a request for test.txt in each sub-directory (a simple problem to solve using Burp Intruder and a target map – but what if the file was written into a directory not exposed to unauthenticated users? Or outside of the web root? In order to minimise any wasted test time, I used my local instance to get a head start and search the file system for test.txt. This is an example of the shortened feedback loops a local instance can provide.
Sure enough, the text file had been written into the /macroscripts/ sub-directory. I then set out to place a web shell on my local instance as a trial run. Once again, having a local instance of the CMS was of great benefit here in that testing could be performed on my local server, and a Proof of Concept attack developed without hitting the client’s systems.
The next problem was that placing web shell code into a POST request parameter resulted in a web shell that wouldn’t execute. This was easily solved within the Burp Repeater by selecting and right clicking on the web shell source code and selecting the HTML encode key characters menu option.
I then hit another problem: unauthenticated users were not allowed to access .aspx or .asp files in the /macroscripts/ directory. The obvious solution was to traverse up out the /macroscripts/ directory, up into the parent /build/ directory, then traverse back down into the /umbraco/ directory; this had to allow unauthenticated users to access .aspx files as it contained the login.aspx page.
I needed a path traversal flaw in the fileName parameter of SaveDLRScript. I reverted back to using a simple text file as the payload. (I generally search for vulnerabilities using benign payloads, which I then switch out for a proper payload once I have a working exploit). Simply naming the file ../test.txt did not have the desired effect. I wanted to perform automated path traversal fuzzing on this code, so I combined two of my favourite things; Burp Intruder and fuzzdb. I set a payload marker prior to the filename within the POST request, loaded the traversals-8-deep-exotic-encoding.txt file into the intruder payloads, and launched the attack.
After a short time, a copy of test.txt appeared in the parent /build/ directory - bingo! Unauthenticated, remote write access to a script-executable directory was within easy reach!
It’s worth noting here that the server response was exactly the same both when the exploit was successful and when it was not: a status response of 500 and an error message. Someone relying wholly upon spotting anomalies in the responses might have missed this vulnerability entirely.
Now I had a new problem: which one of my intruder fuzz strings caused the path traversal to occur? The responses were all the same: a status 500 error. I re-configured the Intruder to use the ‘battering ram’ attack type to write the same payload value both the fileName and the fileContents parameters at the same time; then all I had to do was repeat the Intruder attack, wait for my file to written out to the /build/ directory, and read the content of the file.
Using this method I found that naming the file /......\test.txt caused it to be written to the /build/ directory, from there, I could traverse down to the /umbraco/ directory by simply naming the file /......\umbraco\test.txt
By combining the unauthorised write access offered by the SaveDLRScript operation with the path traversal flaw in the fileName parameter, I was able to write a web shell into the /umbraco/ directory (where unauthenticated users can execute scripts) and hence gain unauthorised remote code execution within the security context of the web server process.
Finally - some advice for Umbraco (and all CMS) administrators: always upgrade to latest version available and apply security patches as soon as possible (obviously, including robust patch and upgrade testing!). The issues described above were rapidly patched after I reported them to the vendor in September 2011. Beyond patching; it’s always a good idea to identify exactly what functionality is publically exposed by your website, review what the requirements are, and impact of, exposing this functionality is, and to restrict access to, or simply remove any unnecessary/dangerous functionality.
So there it is. I’ve introduced the concept of using WebMatrix to quickly create local test reference installations for popular open source web frameworks and components, and I’ve walked through the discovery of a high-impact vulnerability in Umbraco CMS 4.7.0 using Burp and fuzzdb. All of which was made easier and faster via a local reference instance created in 15 minutes.