
So why did this feature exist in the first place?
Seriously, who wanted it and what reason did they give?
It's self-evidently incredibly insecure, and on the face of it doesn't have any non-malicious uses at all.
Last week, version 2.15 of the widely used open-source logging library Log4j was released to tackle a critical security hole, dubbed Log4Shell, which could be trivially abused by miscreants to hijack servers and apps over the internet. That release closed the hole (CVE-2021-44228) by disabling by default the Java library's …
Log4j is an otherwise lightweight, open source logging component built by a group of about 10 entirely-uncompensated volunteer committers. It is not by any stretch of anyone's imagination "enterprise" software.
It's just used in a lot of enterprisey bits. And we enterprisey vendor types never checked what it really does. Because we're cheapskates like that.
It helps to understand how Apache projects work. All development is done on weak consensus. That is any committer can object to a proposal, but this is generally discouraged and a lack of objections is enough to proceed. So ASF projects frequently include features that probably made a whole load of sense to whoever was writing the commit and whoever +1'd it, but really do not in retrospect.
That is the double-edged sword of the ASF model. Stuff gets done without too much bother, but occasionally nobody stops to ask - why? Especially so in the smaller projects without vendor sponsorship.
Well one of the nice things about the ASF model is that deliberations are required to be done in the open and recorded for all to see, so you can be your own judge:
https://issues.apache.org/jira/browse/LOG4J2-313
So developer one articulates a pretty reasonable use case, developer 2 says that doesn't sound unreasonable and thus once the tests pass and the code review is done the work - a modest patch of a few hundred lines - is committed. This is, generally, how software engineering should be done.
How many people can say with a straight face they knew how dangerous JNDI was before this week? I know I did, and I'm pretty sure very few others did, because practically nobody knows what it is or what it is for. Likewise lookups and templating can be dangerous, but how many of us have committed an extension to an existing pattern on the assumption that it's clearly already secure-enough, because it is in active use. Lord knows I have, a lot.
It'd be dangerous, I think, to try and infer motivations on the part of the developer, because we can't be sure and frankly they're probably having a pretty shit week already. If we're going to talk about change it should focus on the ASF process and whether it needs tweaking, on how much mega-corporations have depended on free code they don't vet and how much bloody cruft is hanging around in the JVM that can come up and ruin your day.
It's a classic iceberg problem. The developer saw the peak - a lookup problem - but didn't see the 80+% less obvious danger below the waterline they were inviting.
"any committer can object to a proposal, but this is generally discouraged and a lack of objections is enough to proceed"
This is called the corridor of indifference.
One of the benefits of a benevolent dictator is they have no trouble saying NO.
Exposing the feature to user-supplied content in a way that enables this particular exploit is a fairly natural outcome of the sort of feature-maximization that comes when you give your variable-expansion syntax general purpose function-invoking capabilities. The syntax and effect is not vastly dissimilar from GNU Make variable expansion and function application, and that's been around forever.
The part that executes remote code? That's a built in part of Java that has been there since the beginning. Java has always had the ability to load new classes at run time, and that is part of the object-oriented modelling: if some system that you're communicating with wants to send you data that happens to be of a type that your program doesn't recognize, then it can also send you the code that implements it, because why not? And since the code is write-once, run-anywhere, it'll run anywhere. This is such a core part of java that it is unusual to have ahead-of-time compilation of Java programs to native code, because such code would not be able to perform this particular trick/exploit.
These two come together in the ability of the variable expansion syntax to express JNDI lookup requests to LDAP based databases that can return data with new types and new code from arbitrary servers, where those variable expansions also apply to strings that can be supplied by users (such as user names and browser type).
A classic example of something being more than the sum of its parts: more like the product of its parts...
The thing is that they could've provided the ability to include additional code through correct implementation of Inversion of Control. It's been a standard pattern for a couple of decades and is trivial for both the framework to incorporate and for users of the framework to use.
No need for JNDI (as that can be included if needed by the user of the framework) or LDAP lookups (as those can be included if needed by the user of the framework).
There's always a problem with being able to lookup serialized binary objects across a network. Yes, JNDI RCE is a problem, because it's little bobby tables, so the application needs to do verification of user input just like always.
8u191+ disabled by default the ability to inject classes (e.g. I don't have the class this object refers to, could you give it to me?). However, it is still possible to achieve the same thing if you have a class that's vulnerable already on the classpath.
https://www.veracode.com/blog/research/exploiting-jndi-injections-java
I mean the obvious example is going to be a lookup via LDAP for my identity, if I were to change my name to "rmi://example.com:10977/dodgy" and the login page ended up calling InitialContext.lookup with my dodgy name (and the server was allowed to open up external connections...)
Like all languages, it has its quirks, but after 30 years it's still widely used across industry. Is it perfect? No. Does it work better than most other contenders for its business sector? Evidently, yes, because it keeps getting chosen for projects. It's an enterprise language. If you're putting it in the same category as Shockwave and Flash, you might want to get some money back on your lessons.