- We thought we found arbitrary command execution due to an absence of class-whitelisting.
- We actually found several un-hardened Hudson deployments.
- Hudson/Jenkins CI instances are deployed insecure by default, with opt-into hardening.
- The operational reality of opt-in hardening is that it doesn’t happen nearly as much as it should.
In broad and liberally scoped penetration tests there is a lot of value in triaging discovered web applications and in performing time-boxed (15 minutes here or there) application assessments on promising apps that you come across, as you might score a quick shell.
During an internal network penetration test a while ago, Nima and I came across Hudson (A Continuous Integration build system). After some clicking around we came across the following page:
If you found the above page during a pentest and had no prior knowledge of Hudson or Jenkins, you’d probably get excited, and you’d be right to -that appears to be a console that will execute arbitrary Groovy script. If you’ve written any Java before, the provided Groovy script example will look familiar; and the next step would likely be to see whether there are any constraints placed on what you can execute…
So Nima and I spent five minutes or so playing with the console and soon realized that we could invoke Runtime’s exec method. From there we did the obvious: we used a Java reverse shell, gained access to the server, pilfered some credentials, and continued on with our pentest.
After the excitement of this freebie had long since worn off and the reports were well on their way to completion, I reached out to the folks at Hudson and Jenkins to report what we’d found.
I’ll preface the remainder of the story with this: I don’t come from a development background, and prior to this encounter I had no experiences with Hudson/Jenkins.
=And this is why this article is not entitled Exploiting Hudson/Jenkins=
After I filed a security ticket with Jenkins, Kohsuke responded and patiently explained that a user who had access to the Script Console would also be able to launch arbitrary processes on the system anyway, simply by configuring a new job; and of course as I’d find out, he was right:
The command execution we’d found in the Script Console, was already a built-in feature of job creation. When I filed the ticket, I’d mentioned that the Java Google App Engine uses class white-listing to mitigate this type of attack. In light of the functionality deliberately exposed through the Execute shell option, class-whitelisting in this context might be pretty crippling –I guess it depends on what devs are actually using the Groovy Console for.
Kohsuke pointed out that on a secured deployment of Jenkins, only users that have administrative access to the application can access this functionality; and as there is a mechanism that provides the ability to restrict access to sensitive parts of the application, this isn’t really a vulnerability.
Winston from Hudson similarly noted that he was surprised that we found an open Script Console in the wild, and that you require admin authentication to access it, as it is available from within the Hudson Management Dashboard.
This is generally true in circumstances where users have followed the post-installation hardening steps (http://wiki.hudson-ci.org/display/HUDSON/Securing+Hudson); however, as the first paragraph of this guide put it:
“In the default configuration, Hudson does not perform any security check. This means any person accessing the website can configure Hudson and jobs, and perform builds. While this configuration is normally acceptable for intranet use, Hudson can be also configured to authenticate users and enforce access control so that it can be exposed to the untrusted environment, such as the internet.”
Kohsuke also pointed out in his response that the security mechanism is not enabled by default as there is no sensible default to ship with, due to the fact that everyone uses differing identity sources; and it’s hard to disagree with that latter point.
The operational reality that I’ve come to understand is that it’s not uncommon for ops folks to perform the minimum amount of work necessary to get a product/service running, and additional steps where hardening or security features are provided on an opt-in basis can often fall by the wayside. While our reasonable judgment may tell us that deploying Hudson and neglecting to harden it is obviously a bad idea; I’m confident its a far more common occurrence than we would like to believe.
By the time our pentest was over, Nima and I had found four unhardened instances of Hudson, and were able to use each to get a shell on the affected host.
Similarly to how JBoss remediated its exposed admin interface issue by creating a secure by default deployment, and then providing users with a crutch that they can use: –b 0.0.0.0 to “get things going for you. However, you are strongly advised to secure your JBoss instance” (https://community.jboss.org/wiki/JBoss42FAQ?_sscc=t) Everyone has a million things on their plate; if your deployment process requires additional post-installation hardening steps, or you provide a shortcut to get things operational, you’re going to find vulnerable instances of the deployment in the wild.
There are eight fewer vulnerable instances of Hudson/Jenkins than when I first started writing this post.