Deserialization
The deserialization security feature addresses such attacks by reducing system privileges. This means that for the duration of a deserialization operation, the application operates in a restricted compartment (micro-segment) where specific system privileges are not available. Deserialization operations occur in a non-privileged context. Consequently, any attack (including zero-day attacks) that tries to access or change the state of the system fails. Please refer to another document "Deserialization White Paper" for more details on Waratek approach to deserial mitigation.
The deserialization security feature can be safely enabled in all types of applications in order to be protected against Java and XML deserialization attacks.
Note that JSON deserialization vulnerabilities are not currently supported.
XML deserialization vulnerabilities can be introduced by different XML APIs and libraries. Currently, the only XML API that is supported is java.beans.XMLDecoder.
The deserialization security feature can be used safely and pro-actively on any Java application in order to protect its system resources and components during deserialization. For example, any deserialization exploit that might try to perform the following attacks will fail:
-
execute arbitrary privileged commands (Remote Command Execution)
-
perform Remote Code Injection, change the system’s internal state
-
terminate the JVM or other types of Denial-of-Service attacks
The Denial-of-Service deserialization protection safeguards critical system resources, such as the CPU and memory, by setting default limits to control the interaction frequency of the deserialized objects with the system resources . This way, legitimate serialized objects are allowed to be deserialized while malicious serialized objects that abuse the system resources are blocked. This protection mitigates Denial-of-Service attacks via brute force and resource exhaustion .
Deserial vulnerabilities are covered by
-
CWE-502
-
CWE-250
-
CWE-799
-
CWE-400
Given(Condition)
deserialize | The keyword deserialize is one of two components that must be supplied in the marshal rule with only one being allowed to be configured in a single rule. java and dotnet are the only parameters accepted. |
When(Event)
One of rce
or dos
must be declared in a marshal
rule. Only one of these can exist in a marshal
rule and neither accept any parameter.
rce | Remote Code Execution |
dos | Denial of Service |
Then(Action)
protect | All attempts to deserial are blocked.If configured, a log message is generated with details of the event. |
detect | Monitoring mode: the application behaves as normal.If configured, a log message is generated with details of all attempts to deserial.A log message must be specified with this action. |
As part of the action statement, the user may optionally specify the parameter stacktrace: “full”
. When this parameter is specified, the stacktrace of the location of the attempted exploit is included in the security log entry.
Examples
Protecting the Java
application from the dos
attack.
app("myapp"):
requires(version: ARMR/2.7)
marshal("protect the app from denial-of-service attack"):
deserialize(java)
dos()
protect(message: "the logging message")
endmarshal
endapp
Protecting the .Net
application from rce
attack.
app("myapp"):
requires(version: ARMR/2.7)
marshal("protect the app from remote-code-execution attack"):
deserialize(dotnet)
rce()
protect(message: "the logging message", severity: Low)
endmarshal
endapp
Logging
When the above deserial
rule is triggered a log entry similar to the following is generated:
-
dos
<10>1 2021-03-24T10:14:24.055Z userX_system java 9699 - - CEF:0|ARMR:ARMR|ARMR|2.7|MarshalRule|Execute Rule|High|rt=Mar 24 2021 10:14:24.053 +0000 dvchost=jenkins-qa-secondary-centos.aws.example.org procid=9699 appVersion=1 act=protect msg=Walter limit=100000 reason=CWE-400: Uncontrolled CPU consumption via API abuse methodName=java.util.EnumMap.hashCode()
<10>1 2020-09-10T00:24:50.513Z userX_system java 29417 - - CEF:0|ARMR:ARMR|ARMR|2.7|MarshalRule|Execute Rule|High|rt=Sep 10 2020 00:24:50.512 +0000 dvchost=jenkins-qa-secondary-centos.aws.example.org procid=29417 act=protect msg=Walter limit=100000 reason=CWE-400: Uncontrolled CPU consumption via API abuse methodName=java.util.Hashtable.hashCode() -
rce
<10>1 2021-03-22T12:24:53.327Z userX_system java 28013 - - CEF:0|ARMR:ARMR|ARMR|2.7|MarshalRule|Execute Rule|High|rt=Mar 22 2021 12:24:53.326 +0000 dvchost=jenkins-qa-secondary-centos.aws.example.org procid=28013 appVersion=1 act=protect msg=Walter methodName=java.lang.Runtime.exec() httpRequestUri=/objectinputstream-deserial/examples/deserial-PM-59-test.jsp httpRequestMethod=GET remoteIpAddress=127.0.0.1 httpSessionId=D194C19D465595307BBD2F04F5F7B632
The second example above has extra CEF extensions for httpRequestUri, remoteIpAddress and httpSessionId.
Further Examples
Protecting the Java
application from the dos
attack with the stacktrace also logged.
app("Mod for Marshal dos Rule"):
requires(version: ARMR/2.7)
marshal("Marshal dos Rule"):
deserialize(dotnet, java)
dos()
protect(message: "Testing Marshal dos Rule", severity: Very-High, stacktrace: "full")
endmarshal
endapp
Protecting the Java
application from rce
attack with the stacktrace also logged.
app("Walter"):
requires(version: ARMR/2.7)
marshal("Marshal sys Rule"):
deserialize(java)
rce()
protect(message: "Walter", severity: High, stacktrace: "full")
endmarshal
endapp
Logging
<9>1 2021-03-31T15:38:48.279+01:00 userX_system java 104596 - - CEF:0|ARMR:ARMR|ARMR|2.7|Marshal dos Rule|Execute Rule|Very-High|rt=Mar 31 2021 15:38:48.278 +0100 dvchost=ckang-XPS-15-9570 procid=104596 appVersion=1 act=protect msg=Testing Marshal dos Rule stacktrace=java.util.AbstractSet.hashCode(AbstractSet.java)\ndeserialjar.runners.OverwrittenReadObject.abstractSetHashCode(OverwrittenReadObject.java:434)\ndeserialjar.runners.OverwrittenReadObject.invokeMethod(OverwrittenReadObject.java:375)\ndeserialjar.runners.OverwrittenReadObject.readObject(OverwrittenReadObject.java:57)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\njava.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1170)\njava.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2232)\njava.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2123)\njava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624)\njava.io.ObjectInputStream.readObject(ObjectInputStream.java:464)\njava.io.ObjectInputStream.readObject(ObjectInputStream.java:422)\ndeserialjar.runners.OverwrittenReadObjectRunner.run(OverwrittenReadObjectRunner.java:32)\nMain.main(Main.java:63) limit=100000 reason=CWE-400: Uncontrolled CPU consumption via API abuse methodName=java.util.AbstractSet.hashCode()
<10>1 2021-03-31T15:51:32.787+01:00 userX_system java 105393 - - CEF:0|ARMR:ARMR|ARMR|2.7|Marshal sys Rule|Execute Rule|High|rt=Mar 31 2021 15:51:32.785 +0100 dvchost=ckang-XPS-15-9570 procid=105393 appVersion=1 act=protect msg=Walter stacktrace=deserialjar.runners.OverwrittenReadObject.invokeMethod(OverwrittenReadObject.java:103)\ndeserialjar.runners.OverwrittenReadObject.readObject(OverwrittenReadObject.java:57)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:498)\njava.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1170)\njava.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2232)\njava.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2123)\njava.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624)\njava.io.ObjectInputStream.readObject(ObjectInputStream.java:464)\njava.io.ObjectInputStream.readObject(ObjectInputStream.java:422)\ndeserialjar.runners.OverwrittenReadObjectRunner.run(OverwrittenReadObjectRunner.java:32)\nMain.main(Main.java:63) methodName=java.lang.Runtime.exec()
Protecting the Java
application from dos
deserialization attacks with logging switched OFF. Logging is switched OFF by the omission of the protect action message
attribute.
app("Mod for Marshal dos Rule"):
requires(version: ARMR/2.7)
marshal("Marshal dos Rule"):
deserialize(java)
dos()
protect(severity: Very-High)
endmarshal
endapp
Protecting the Java
application from dos
deserialization attacks. Logging is switched ON by the inclusion of the protect action message
attribute. As the message
attribute is defined as an empty string (""
), a default message will be included in the security event msg
extension. (Optionally, a custom message may be defined in the message
attribute.)
app("Mod for Marshal dos Rule"):
requires(version: ARMR/2.7)
marshal("Marshal dos Rule"):
deserialize(java)
dos()
protect(message: "", severity: Very-High)
endmarshal
endapp
Whitelist
In the rare case where the deserial rule must allow specific privileges in certain environments, an optional property com.waratek.AllowDeserialPrivileges
can be used to whitelist specific deserial privileges.
Setup AllowDeserialPrivileges Flag
-
Open the
<absoulte path to Waratek Agent>/conf_*/waratek.properties
file. -
Add the following flag and make an adjustment according to the real-world requirement.
com.waratek.AllowDeserialPrivileges=<comma-separated-values>
Examples
Whitelist java.lang.SecurityManager.<init>()
com.waratek.AllowDeserialPrivileges=java.lang.SecurityManager.<init>()
Whitelist java.lang.SecurityManager.<init>()
and java.lang.System.getenv()
com.waratek.AllowDeserialPrivileges=java.lang.SecurityManager.<init>(),java.lang.System.getenv()