This post concludes our deep dive into the Railo application server by detailing not only one, but two pre-auth remote code execution vulnerabilities. If you’ve skipped the first three parts of this blog post to get to the juicy stuff, I don’t blame you, but I do recommend going back and reading them; there’s some important information and details back there. In this post, we’ll be documenting both vulnerabilities from start to finish, along with some demonstrations and notes on clusterd’s implementation on one of these.
The first RCE vulnerability affects versions 4.1 and 4.2.x of Railo, 4.2.1 being the latest release. Our vulnerability begins with the file
thumbnail.cfm, which Railo uses to store admin thumbnails as static content on the server. As previously noted, Railo relies on authentication measures via the cfadmin tag, and thus none of the cfm files actually contain authentication routines themselves.
thumbnail.cfm first generates a hash of the image along with it’s width and height:
1 2 3
Once it’s got a hash, it checks if the file exists, and if not, attempts to read and write it down:
1 2 3 4 5 6 7 8 9 10 11 12 13
cffile tag is used to read the raw image and then cast it via the
cfimage tag. The wonderful thing about
cffile is that we can provide URLs that it will arbitrarily retrieve. So, our URL can be this:
And Railo will go and fetch the image and cast it. Note that if a height and width are not provided it will attempt to resize it; we don’t want this, and thus we provide large width and height values. This file is written out to
We’ve now successfully written a file onto the remote system, and need a way to retrieve it. The temp folder is not accessible from the web root, so we need some sort of LFI to fetch it. Enter
get, which accepts a single argument
1 2 3 4 5 6 7 8
Let’s tie all this together. Using
thumbnail.cfm, we can write well-formed images to the file system, and using the
<?phpinfo();?> will be discovered and executed; the CFML engine works the same way.
Our attack becomes much more clear: we generate a well-formed PNG file, embed CFML code into the image (metadata), set the extension to
.js, and write it via
thumbnail.cfm. We then retrieve the file via
jsloader.cfc and, because we’re loading it with a CFM file, it will be parsed and executed. Let’s check this out:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
A couple things to note; as you may notice, the module currently requires the Railo server to connect back twice. Once is for the image with embedded CFML, and the second for the payload. We embed only a stager in the image that then connects back for the actual payload.
Sadly, the LFI was unknowingly killed in 4.2.1 with the following fix to
1 2 3 4
arguments.lib variable contains our controllable path, but it kills our ability to traverse out. Unfortunately, we can’t substitute the .. with unicode or utf-16 due to the way Jetty and Java are configured, by default. This file is pretty much useless to us now, unless we can write into the folder that
jsloader.cfc reads from; then we don’t need to traverse out at all.
img.cfm LFI from part 3; by tip-toeing back into the admin-ext-thumbnails folder, we can summon our vulnerable image and execute whatever coldfusion we shove into it. This proves to be an even better choice than
jsloader.cfc, as we don’t need to traverse as far. This bug only affects versions 4.1 – 4.2.1, as
thumbnail.cfm wasn’t added until 4.1.
CVE-2014-5468 has been assigned to this issue.
The second RCE vulnerability is a bit easier and has a larger attack vector, spanning all versions of Railo. As previously noted, Railo does not do per page/URL authentication, but rather enforces it when making changes via the
<cfadmin> tag. Due to this, any pages doing naughty things without checking with the tag may be exploitable, as previously seen. Another such file is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
I mean, this might as well be an upload form to write arbitrary files. It’s stupid simple to get arbitrary data written to the system:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
The tricky bit is where it’s written to; Railo uses a compression system that dynamically generates compressed versions of the web server, contained within
railo-context.ra. A mirror of these can be found under the following:
The compressed data is then obfuscated behind two more folders, both MD5s. In my example, it becomes:
So we cannot simply traverse into this path, as the hashes change every single time a file is added, removed, or modified. I’ll walk the logic used to generate these, but as a precusor, we aren’t going to figure these out without some other fashionable info disclosure bug.
The hashes are calculated in
1 2 3 4 5 6 7 8 9 10 11 12
The first hash is then
cid + "-" + ffile.getAbsolutePath(), where
cid is the randomly generated ID found in the
id file (see part two) and
ffile.getAbsolutePath() is the full path to the classes resource. This is doable if we have the XXE, but 4.1+ is inaccessible.
The second hash is
actLastMode + ":" + ffile.length(), where
actLastMode is the last modified time of the file and
ffile.length() is the obvious file length. Again, this is likely not brute forcable without a serious infoleak vulnerability. Hosts <= 4.0 are exploitable, as we can list files with the XXE via the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
http_test_xxe.py is just a small hack I wrote to exploit the XXE, in which we eventually obtain both valid hashes. So we can exploit this in versions <= 4.0 Express. Later versions, as far as I can find, have no discernible way of obtaining full RCE without another infoleak or resorting to a slow, loud, painful death of brute forcing two MD5 hashes.
The first RCE is currently available in clusterd dev, and a PR is being made to Metasploit thanks to @BrandonPrry. Hopefully it can be merged shortly.
As we conclude our Railo analysis, lets quickly recap the vulnerabilities discovered during this audit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
This does not include the random XSS bugs or post-authentication issues. At the end of it all, this appears to be a framework with great ideas, but desperately in need of code TLC. Driving forward with a checklist of features may look nice on a README page, but the desolate wasteland of code left behind can be a scary thing. Hopefully the Railo guys take note and spend some serious time evaluating and improving existing code. The bugs found during this series have been disclosed to the developers; here’s to hoping they follow through.