How a serious Apache vulnerability struts its stuff

Last week’s vulnerability news was full of web technologies with intriguing names, including Apache, Struts, Java, Jakarta and OGNL.

(In case you’re wondering, OGNL is short for Object-Graph Navigation Language, which is hard to explain briefly even to people who are familiar with it, but we’ll get back to that in a moment.)

We’ll start with a quick glossary:

  • Apache HTTPD is a popular, open source web server that is very widely used. Quite how widely depends on whom you ask and how you measure, but it’s a fair guess that somewhere between a third and a half of the world’s websites use it.
  • Java, not to be confused with JavaScript, is a popular programming language, best known for writing business applications, browser applets (although these are rarely used these days) and servlets, which are stripped-down programs that generate customised web pages on the fly as users browse your site.

    LISTEN NOW

    (Audio player not working? Download the MP3, listen on Soundcloud, or get it from iTunes.)

  • Struts is an add-on to Apache that lets you use Java servlets to manage and deliver the content of your site. Note that Struts is a server-side technology: it isn’t about what runs in your users’ browsers, but about what runs on your server to generate the web pages that Apache serves up.
  • Jakarta is the umbrella name for a number of Java-based programming projects that were run for the community by Apache.
  • OGNL is a curious beast that is intended to let you specify how the contents of your web pages are derived from various databases stored behind the scenes. But OGNL is as good as a programming language in its own right, because it can be used to specify Java and other commands that are used in the process.

Last week’s media confabulation of all these names was a security vulnerability that goes by the unassuming name of CVE-2017-5638, or “Possible Remote Code Execution when performing file upload based on Jakarta Multipart parser”.

Simply put, web servers using the Struts 2 software include a component to deal with web uploads, which is typically what happens when a user fills in a web form on your site and clicks [Submit]:

Web form uploads are usually delivered using an HTTP request called a POST.

(As the name suggests, a POST is essentially the opposite of a GET request, which is how you download webpages, files and other content.)

For example, a web page containing a form like this…

…will produce a multipart/form-data reply in which each input field in the form is packaged and uploaded in a section of its own, in much the same way that multipart emails (e.g. messages with attachments) are formatted:

The theory is that posting the submitted data, and encoding it into its separate fields before submitting it, is less error prone that packaging it into some sort of all-in-one binary blob and uploading that.

The part of Struts 2 server-side software that deals with web requests of this sort is referred to by Apache as the Jakarta based file upload Multipart parser, and its job, greatly simplified, is to check for a Content-Type header of multipart/form-data, and then to tease the POSTed data into its multiple parts.

If the Content-Type is incorrect, the Jakarta parser is supposed to respond with an error message that explains what was wrong, which means taking the invalid Content-Type data and processing it in some way to extract information that would be helpful in fixing the problem.

Untrusted remote content

You can probably guess where this is going: a bug in the processing of erroneous, untrusted remote content, leading to an exploitable vulnerability.

It turns out that if the Content-Type header is a fragment of OGNL code, the Jakarta parser processes it not as text but as an OGNL “program”, and OGNL code can contain components that specify commands that should be run on the server itself when dealing with the data.

In other words, you can embed server commands in a Struts 2 form POST header, thus deliberately triggering an error, and the server will run your commands, ironically while trying to deal gracefully with the error.

That sort of exploit is aptly known as RCE, or Remote Code Execution, which means exactly what it says and always spells trouble, in this case with a capital T.

Without logging in, without fetching the original web form page in the first place, and without even having any form data to upload, a crook may be able trigger this bug simply by visiting the web page listed in the action field of any of your web forms.

For example, the well-known command-line web clients WGET and cURL can generate POST requests with headers of your choice like this:

The malformed Content-Type header you need is not trivial to figure out by yourself, but unfortunately you don’t need to, because working examples written in what you might call OGNL’s “pseudo-Java” source code have already been furnished on many websites:

What to do?

Patch early, patch often!

If you use Struts 2 somewhere in your network, and still haven’t applied the latest patch, you really ought to, because this vulnerability is easy to exploit by anyone who wants to try.

Sadly, experience suggests that there are often wannabe hackers out there who fancy their “15 minutes of fame”, even if they don’t have any explicit criminal aims and wouldn’t show the same sort of vandalistic tendencies against traditional property.

The Canada Revenue Agency (CRA), for example, discovered this the hard way back in 2014, when a 19-year-old student was accused of turning the Heartbleed vulnerability against the Agency’s website.

He allegedly extracted 90 social insurance numbers over a six-hour period, just to prove he could.

This time, the CRA acted quickly, taking its systems down to apply the vital patch over the previous weekend, even though it’s tax season in Canada.

If Canada Revenue can find a way to accommodate an unscheduled outage of this sort, you can, too!