Tenable originally published the details of CVE-2016-8519, a Java deserialization vulnerability in HPE Operations Orchestrations, in TRA-2017-05. The short version is that HPE Operations Orchestrations 10.60 was vulnerable to Java deserialization attacks through its web interface due to certain endpoints using HttpInvokerServiceExporter.
In order to fix CVE-2016-8519, HPE replaced their usage of HttpInvokerServiceExporter with a new class called SecureHttpInvokerServiceExporter. This new class creates a wrapper around the incoming ObjectInputStream to create a LookAheadObjectInputStream. At first glance, this LookAheadObjectInputStream appears to follow guidelines laid out by Pierre Ernst in the article Look-ahead Java deserialization. Specifically, LookAheadObjectInputStream contains an overridden resolveClass that has logic to verify the object that's about to be deserialized is of the type RemoteInvocation. However, the code is a little weird.
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException
{
if (logger.isDebugEnabled())
{
logger.debug("Entering resolveClass: firstTime=[" + this.firstTime + "] name=[" + desc.getName() + "]");
}
if ((this.firstTime) &&
(!StringUtils.equals(desc.getName(), RemoteInvocation.class.getName())))
{
String message = "Unauthorized de-serialization attempt for class " + desc.getName();
logger.error(message);
throw new InvalidClassException(message);
}
this.firstTime = false;
return super.resolveClass(desc);
}
Look at how the boolean member variable firstTime is used. This resolveClass implementation will only verify the first Object and after that it doesn't care. But maybe this isn't a mistake? Maybe RemoteInvocation won't ever have any inner objects to deserialize? Wrong.
public class RemoteInvocation implements Serializable
{
/** use serialVersionUID from Spring 1.1 for interoperability */
private static final long serialVersionUID = 6876024250231820554L;
private String methodName;
private Class<?>[] parameterTypes;
private Object[] arguments;
private Map<String, Serializable> attributes;
An attacker can stick arbitrary serializable objects into the RemoteInvocation attributes map. Which means the resolveClass implementation in the LookAheadObjectInputStream is arbitrary to bypass. Furthermore, an exploitable Apache Commons BeanUtils is on the classpath. Therefore, a remote unauthenticated attacker can still achieve remote code execution by sending HTTP POST requests to /oo/backwards-compatibility/wsExecutionBridgeService.