Demystifying Java JNDI attacks

How this Java API — rather its implementation could have catastrophic consequences on your application’s security, and what can you do about it?

Ax Sharma: Sample bytecode representation of a Java application class

JNDI-based attacks have wreaked havoc on mission-critical Java applications in the last few years — not because of anything being wrong with this API itself, rather the negligent manner in which developers use it.

What is JNDI? A simple web search reveals:

The Java Naming and Directory Interface (JNDI) is a Java API for a directory service that allows Java software clients to discover and look up data and resources (in the form of Java objects) via a name. Like all Java APIs that interface with host systems, JNDI is independent of the underlying implementation.
- Wikipedia

The famous Equifax breach deemed ‘entirely preventable’ occurred from a vulnerable version of Apache Struts running on the company’s servers. The actual vulnerability (CVE-2015–5638), however relates to JNDI which is why it is prudent to understand the underlying details, as this could happen with any application. For example, just last month Veracode released their own advisory demonstrating multiple Spring Boot actuator endpoints being open to exploitation, with JNDI commands being one of the attack vectors.

Basics

At its core, JNDI is nothing more than an API which lets a developer perform various querying and directory access operations. This StackOverflow post explains it pretty well. Depending on the context of your application, it may be the preferred standard way of accessing services such as LDAP, for example, as opposed to implementing your own solution from scratch.

Essentially, as a Java developer you want your app to access a service without caring about what’s the underlying directory service it’s being retrieved over. That’s where JNDI comes in handy.

Attack Mechanisms

The problem arises due to common negligent mistakes made by the developers and not necessarily the API itself. For example, trusting external input coming from HTTP request headers — essentially what we observe in the case of Struts, files, user-input fields, serialized objects and passing that input directly to various JNDI commands used by your program is a bad practice, as is having an incorrectly configured server.

Veracode: An example of how Spring Boot actuators can be exploited by providing rogue JNDI configuration as XML input.

Prevention

So, how do you prevent JNDI vulnerabilities in your web application?

First things first, doing your due diligence as a developer pays off. Don’t ever trust external input and don’t use it as-it-as within your application without proper escaping and sanitization in place. Just because the input is in a proper format (syntactically valid XML, YAML or a serialized object), or coming from a trustworthy source, does not mean it isn’t malicious. Chances are if your code’s logic is executing system commands, so can a skilled attacker.

One of the reasons I’m proud to be associated with Sonatype is the speed at which we catch up with newly released vulnerabilities — like these ones, in open-source software, often before even they are assigned CVE IDs.
Sonatype customers are likely to detect and mitigate risks associated with vulnerable open-source components very early on and with a much higher precision, compared to those relying entirely on the public NVD website.

© 2019. Akshay ‘Ax’ Sharma. All Rights Reserved.