You’re Running Untrusted Code! – DZone Security

Last December, Log4Shell shortened many people’s nights in the JVM world. Even worse, the use of the earthquake analogy caused many aftershocks to occur after the initial earthquake. I immediately made the connection between Log4Shell and the security manager. At first, I didn’t want to write about it, but I got requests to do so, and I couldn’t get away.

As a reminder, the Oracle team deprecated Security Manager in Java 17. One of the arguments behind its decision was that it was initially designed to protect against applets. The applets were downloaded from the internet, so they had to be considered untrusted code. Hence, we had to run them in a sandbox.

Although they never state it, there is an implicit consequence of this statement: Because applets are now deprecated, we’re only running trusted code. And therefore, we can give up the security manager. It’s an obvious mistake, and I’ll explain why in this post.

The assumption that the code running within your infrastructure can be trusted is dangerous — on-premises or in the cloud. Let me enumerate some arguments in support of this claim.

Libraries can’t be trusted

Wise developers don’t reinvent the wheel: they use existing libraries and/or frameworks.

Obviously, from a security point of view, this means that users of third-party code should scrutinize it carefully. We must look for flaws: both bugs and weaknesses.

In two decades of working in the industry, I have never seen such scrutiny happen.

One could argue in favor of custom code. Unfortunately, it does not solve anything. Custom code suffers from the same issues, bugs, and vulnerabilities. Worse, it doesn’t get the same attention as standard libraries, so researchers can’t spend their time finding these issues, which cost nothing.

Buildings cannot be trusted

Imagine you have all the resources needed to audit your code – time, money, and skills. Imagine, too, that an audit reveals anything suspicious. Finally, imagine that the audit conclusion is 100% reliable.

The problem is that there is no guarantee that the JAR is the result of a build from the source code, even if the build is public. A malicious provider can replace the original JAR with another.

Identities can’t be trusted

The provider can sign the JAR to ensure its authenticity. Signature is based on asymmetric encryption:

  1. The provider signs the JAR with its private key
  2. Creates a public key with the private key
  3. One can read the signature using the public key and check the signature of the provider on the JAR.

Thus, anyone can verify that the JAR is coming from a particular provider.

JDK provides a file jarsigner A tool for signing JARs. Unfortunately, most libraries don’t use it. For example, I checked the following dependencies:

  • org.slf4j:slf4j-api:1.7.32
  • com.fasterxml.jackson.core:jackson-core:2.13.0
  • org.mockito:mockito-core:4.1.0
  • org.junit.jupiter:junit-jupiter-api:5.8.2
  • org.apache.commons:commons-collections4:4.4
  • org.eclipse.collections:eclipse-collections:10.4.0
  • com.google.protobuf:protobuf-java:3.18.0
  • com.itextpdf:itextpdf:5.5.13.2
  • com.zaxxer:HikariCP:5.0.0
  • com.vladmihalcea.flexy-pool:flexy-pool-core:2.2.3
  • org.springframework:spring-beans:5.3.13
  • jakarta.platform:jakarta.jakartaee-api:9.1.0

Of the 12 JARs mentioned above, only one is signed jarsigner. If you’re interested, it’s Eclipse groups.

However, in the face of supply chain attacks, artifact repositories have begun to demand signed artifacts. For example, Sonatype requires a signature for every file uploaded, in another meaning, POM, JAR, JAR sources, JavaDocs JAR, etc.

One can check the signature with Maven:

mvn org.simplify4u.plugins:pgpverify-maven-plugin:show -Dartifact=com.zaxxer:HikariCP:5.0.0

produces the following:

Artifact:
        groupId:     com.zaxxer
        artifactId:  HikariCP
        type:        jar
        version:     5.0.0

PGP signature:
        version:     4
        algorithm:   SHA256withRSA
        keyId:       0x4CC08E7F47C3EC76
        create date: Wed Jul 14 04:49:52 CEST 2021
        status:      valid

PGP key:
        version:     4
        algorithm:   RSA (Encrypt or Sign)
        bits:        2048
        fingerprint: 0xF3A90E6B10E809F851AB4FC54CC08E7F47C3EC76
        create date: Wed Sep 18 02:51:23 CEST 2013
        uids:        [Brett Wooldridge (Sonatype) <brett.wooldridge@gmail.com>]

However, none of this amounts to much. The signature does not confirm the identity of the provider. It tells us that a private key with the indicated email was signed by a private key with the indicated email. Nothing prevents the malicious actor from creating another private key with the same email or similar.

Features can’t be trusted

At this point, I think the picture looks pretty bleak. But it’s worse than that. None of the above explains the Log4J vulnerability. The main reason is that it provides features that most developers don’t need or use.

I don’t want to go into too much detail, as it has already been explained in many places. Suffice it to say that Log4J provides lookups. Search is an integration with another system, allowing the history to be enriched beyond just the message. For example, the search Spring Boot allows to get the properties of Spring Boot. It makes sense to enrich the log, for example, with spring.application.name.

In all the available searches, some of them look a little suspicious. For example, environment variables, system properties, or even JNDI. The latter is the root cause of the Log4J vulnerability.

This type of hidden feature is not specific to Log4J. I have learned that there is a Swing based GUI management application inside the H2 database driver. I only learned about it by chance.

The problem is that developers use a library for their basic capabilities, for example, Sign Up. If one stops there, they will never know all the capabilities of the library. Hence, one would be surprised when the library does something it was not supposed to do, for example, read from the remote JNDI resource tree.

The JVM cannot be trusted

I admit the section title is misleading, but I haven’t found a good title that follows the series. It is a continuation of the previous section, and this time it applies to the JVM.

The JVM provides many features, of which I use a handful or two. The most obvious problem is the Attach API. This API, available since Java 1.6, allows a JVM to update bytecode that is already loaded in another JVM. Yes, you read it right: you can change the bytecode for a running application. Even worse, if you restart the JVM, the code will be loaded again, leaving no trace.

It’s a great feature if you want to quickly debug a monkey for an in-production fix.
However:

  • Most people don’t use it
  • Most people don’t know about it
  • The feature must be explicitly disabled. It is on by default.

May I suggest that the first thing you do tomorrow is to check and disable your infrastructure?

Security Manager can be trusted

Hope you understand the problem at this point. A lot of the code you’re running can’t be trusted. Even worse, I only think of normal applications: programs built on plugin architecture run with code that is not trusted by definition.

Security Manager was a component of the JVM that allowed you to define a whitelist of what an application could do, regardless of the application’s code. It solved all of the above issues: you can run any code but you only allowed it to do a limited number of things.

The security manager came up with several flaws; Chief among them is that it was difficult to configure the permissions. However, there are tools for creating the policy file. Since it is automated, you need to review the detected permissions carefully. It’s easier to read about 500 lines of config than it is to read 10,000 or 100,000 lines of code.

Since many were not familiar with the tools, few used Security Manager. But when it did, it was very helpful. To substantiate my claim, you can read this post or jump to the conclusion: Although Elasticsearch includes a vulnerable version of Log4J, it is not vulnerable to Log4Shell!

conclusion

Security is a non-functional requirement. NFRIt does not bring any competitive advantage and costs money. In short, they shift the budget from business requirements to /dev/null. That’s at least what most business departments see.

I think we should approach security through the lenses of risk assessment. It first requires listing all potential risks. I’m afraid that neglecting the security manager will add several lines to this risk, all associated with running untrusted code.

Note that the controversy over the security manager’s depreciation was not civil. Since you sided against Consumption, I was publicly attacked, to the point of obvious bullying. Other voices who supported me received similar treatment.

I don’t expect reactions to this post to be different. However, I must tell the members of the community what happened and what we lost.

.

Leave a Comment