漏洞概述
漏洞细节
public class SUMCommunicationServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession httpSession = request.getSession();
response.setStatus(200);
DataOutputStream dos = new DataOutputStream(response.getOutputStream());
if (httpSession == null) {
dos.writeInt(1000);
} else {
SUMHttpRequestHandler requestHandler = (SUMHttpRequestHandler)httpSession.getAttribute("requestHandler");
if (requestHandler == null) {
dos.writeInt(1000);
} else {
byte[] responseData = requestHandler.process(request.getInputStream());
[...]
}
}
dos.flush();
}
}
public class SUMHandShakeServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
int requestId = ois.readInt();
HttpSession httpSession;
if (requestId == 1002) {
httpSession = request.getSession(true);
SUMHttpRequestHandler reqHandler = new SUMHttpRequestHandler(request.getRemoteHost());
httpSession.setAttribute("requestHandler", reqHandler);
[...]
}
}
}
public byte[] process(InputStream is) {
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] dataa = new byte[4096];
int lengthx;
while((lengthx = bis.read(dataa, 0, dataa.length)) > 0) {
bos.write(dataa, 0, lengthx);
}
DataInputStream ois = new DataInputStream(new ByteArrayInputStream(bos.toByteArray()));
int length = ois.readInt();
byte[] data = new byte[length];
ois.readFully(data, 0, length);
byte[] processedData = this.processSumPDU(data);
[ ]
private byte[] processSumPDU(byte[] pduData) throws Exception {
if (pduData == null) {
return null;
} else if (pduData == SUMPDU.CLOSE_SESSION) {
this.cleanUp();
return null;
} else {
SUMPDU sumpdu = SUMPDU.deSerializePDU(pduData);
public static SUMPDU deSerializePDU(byte[] b) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(b));
return (SUMPDU)ois.readObject();
}
工具链
-
攻击者控制的ObjectInputStream中的对象数组被写入属性队列。
-
在第8行调用heapify函数,以通过自定义比较器对数组进行排序。
-
然后,在第13行调用shiftDown。
-
我们将提供一个自定义比较器siftDownUsingComparator,并在第19行调用。
-
最后,自定义比较器的compare函数在第31行被调用。
private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
var1.defaultReadObject();
var1.readInt();
this.queue = new Object[this.size];
for(int var2 = 0; var2 < this.size; ++var2) {
this.queue[var2] = var1.readObject();
}
this.heapify();
}
private void heapify() {
for(int var1 = (this.size >>> 1) - 1; var1 >= 0; --var1) {
this.siftDown(var1, this.queue[var1]);
}
}
private void siftDown(int var1, E var2) {
if (this.comparator != null) {
this.siftDownUsingComparator(var1, var2);
} else {
this.siftDownComparable(var1, var2);
}
}
private void siftDownUsingComparator(int var1, E var2) {
int var4;
for(int var3 = this.size >>> 1; var1 < var3; var1 = var4) {
var4 = (var1 << 1) + 1;
Object var5 = this.queue[var4];
int var6 = var4 + 1;
if (var6 < this.size && this.comparator.compare(var5, this.queue[var6]) > 0) {
var4 = var6;
var5 = this.queue[var6];
}
}
}
import org.apache.commons.collections.comparators.ComparableComparator;
public class BeanComparator implements Comparator, Serializable {
private String property;
private Comparator comparator;
public BeanComparator(String property, Comparator comparator) {
this.setProperty(property);
if (comparator != null) {
this.comparator = comparator;
} else {
this.comparator = ComparableComparator.getInstance();
}
}
public int compare(Object o1, Object o2) {
if (this.property == null) {
return this.comparator.compare(o1, o2);
} else {
Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.comparator.compare(value1, value2);
}
}
}
public synchronized Properties getOutputProperties() {
return this.newTransformer().getOutputProperties();
}
public synchronized Transformer newTransformer() throws TransformerConfigurationException {
TransformerImpl var1 = new TransformerImpl(this.getTransletInstance(), this._outputProperties, this._indentNumber, this._tfactory);
[...]
}
private Translet getTransletInstance() throws TransformerConfigurationException {
if (this._class == null) {
this.defineTransletClasses();
}
AbstractTranslet var1 = (AbstractTranslet)this._class[this._transletIndex].newInstance();
var1.postInitialization();
var1.setTemplates(this);
var1.setServicesMechnism(this._useServicesMechanism);
var1.setAllowedProtocols(this._accessExternalStylesheet);
if (this._auxClasses != null) {
var1.setAuxiliaryClasses(this._auxClasses);
}
return var1;
}
END
本文始发于微信公众号(SecTr安全团队):ManageEngine OPManager中的预认证RCE漏洞
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论