Reproducing an Umbraco Remote Code Execution Vulnerability

During a recent penetration test I came across a website running Umbraco CMS (https://umbraco.com/). Umbraco is an open source content management system for publishing content on the World Wide Web and intranets. It is written in C# and deployed on Microsoft based infrastructure. Doing some research looking for vulnerabilities I found that last year a critical flaw was reported by MWR Labs after doing a security audit on the CMS:

https://umbraco.com/follow-us/blog-archive/2013/4/29/security-vulnerabili…
https://labs.mwrinfosecurity.com/advisories/2013/11/29/umbraco-cms-templ…

Even though they did not go into too much detail about the vulnerability, they mentioned a few key things that fortunately were enough to successfully reproduce the issue locally. I thought it would be interesting to share my findings, and hopefully help web developers as well as security consultants to understand the importance of small details and subtleties that can be overlooked when programming a new piece of code, but that can lead to the compromise of the system.

In the description of the vulnerability they mention that the flaw affects all versions prior to 6.0.4. The Umbraco developers made a good job fixing it promptly, and thus recent versions do not contain this security flaw anymore. For this reason the tests were carried out using an old vulnerable version of the CMS (6.0.3) available for download in the following link.

https://github.com/umbraco/Umbraco-CMS/tree/release-6.0.3

Once we have downloaded the source code, built the project and followed the installation instructions, we will end up with a neat and simple website similar to the one shown below:

image 1

With the knowledge that Umbraco comes with a number of web services enabled by default, we should be able to access their description by just browsing to the adequate .asmx file. As we can see in the image below, the “update” operation of the “templateService” web service is available. This is the operation that was reported to be vulnerable, so we will focus on it from now on.

image 2

If we follow the “update” link we will see another page that shows sample SOAP requests for this operation.

image 3

Before we craft a SOAP request, let’s first take a look behind the scenes and find out what is going on in the server-side code. The source code in charge of handling the TemplateService Web Service can be found at:

./Umbraco-CMS-release-6.0.3/src/umbraco.webservices/templates/templateService.cs

If we open that file and scroll down to the “update” method we will find the following code.

[WebMethod]
        public void update(templateCarrier carrier, string username, string password)
        {
            if (carrier.Id == 0) throw new Exception("ID must be specifed when updating");
            if (carrier == null) throw new Exception("No carrier specified");

            cms.businesslogic.template.Template template;
            try
            {
                template = new cms.businesslogic.template.Template(carrier.Id);
            }
            catch (Exception)
            {
                throw new Exception("Template with ID " + carrier.Id + " not found");
            }

            template.MasterTemplate = carrier.MastertemplateId;
            template.Alias = carrier.Alias;
            template.Text = carrier.Name;
            template.Design = carrier.Design;
            template.Save();

            clearCachedTemplate(template);
        }

As we can see, the method is expecting information about the template to update as well as a username and a password, but they do not use the username and password information anywhere within the method to verify that the user who is requesting the operation is authorized. That makes this operation accessible to unauthorized users, who can overwrite the content of an existing template and add arbitrary content.

To reproduce the vulnerability we will use the previous SOAP template to craft a request to the web service, this is shown below:

image 1

Note that the username and password values are not important, as they are not validated in the server. Also, note that a valid template ID was provided, although this can be easily guessed or brute-forced, for the sake of brevity a valid one was grabbed from the admin panel.

After we send the request, the server returns the following response:

image 1

And if we browse to the homepage…

image 1

Voilà! The main template was modified with the content we sent, and thus the homepage.

To sum up, we have successfully been able to locally reproduce a vulnerability that was relatively recent. This vulnerability takes advantage of a slip in the development that let unauthenticated users make web service requests to overwrite existing files with arbitrary content, and thus potentially gaining control of the server and other internal systems. From the developers and system administrators point of view this is a clear example of how vital it is to develop and deploy all our systems with a security mindset; a little nuance like this one can leave our systems exposed to malicious users. From the penetration tester point of view, it is important to note that whenever possible, and within the time limitations we face during most of the tests we do, we should test every single bit of each application, and not just assume that because the developers have secured a part of the application, they have done the same with everything else.  

 

Find out how we can help with your cyber challenge

Please enter your contact details using the form below for a free, no obligation, quote and we will get back to you as soon as possible. Alternatively, you can email us directly at [email protected]