Skip to content

Commit a78f211

Browse files
Split SpringExporterUnsafeDeserialization.ql
1 parent 891b975 commit a78f211

11 files changed

+122
-40
lines changed

java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.qhelp renamed to java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.qhelp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ The following example shows how a vulnerable HTTP endpoint can be defined
4646
using <code>HttpInvokerServiceExporter</code> and Spring annotations:
4747
</p>
4848
<sample src="SpringExporterUnsafeDeserialization.java" />
49-
<p>
50-
The next examples shows how the same vulnerable endpoint can be defined in a Spring XML config:
51-
</p>
52-
<sample src="SpringExporterUnsafeDeserialization.xml" />
5349
</example>
5450

5551
<references>

java/ql/src/experimental/Security/CWE/CWE-502/SpringExporterUnsafeDeserialization.ql renamed to java/ql/src/experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,13 @@
66
* @kind problem
77
* @problem.severity error
88
* @precision high
9-
* @id java/spring-exporter-unsafe-deserialization
9+
* @id java/unsafe-deserialization-spring-exporter-in-configuration-class
1010
* @tags security
1111
* external/cwe/cwe-502
1212
*/
1313

1414
import java
15-
import semmle.code.java.frameworks.spring.SpringBean
16-
17-
/**
18-
* Holds if `type` is `RemoteInvocationSerializingExporter`.
19-
*/
20-
private predicate isRemoteInvocationSerializingExporter(RefType type) {
21-
type.getASupertype*()
22-
.hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter")
23-
}
24-
25-
/**
26-
* Holds if `method` belongs to a Spring configuration.
27-
*/
28-
private predicate isInConfiguration(Method method) {
29-
method.getDeclaringType().hasAnnotation("org.springframework.context.annotation", "Configuration")
30-
}
15+
import UnsafeSpringExporterLib
3116

3217
/**
3318
* A method that initializes a unsafe bean based on `RemoteInvocationSerializingExporter`.
@@ -36,8 +21,8 @@ private class UnsafeBeanInitMethod extends Method {
3621
string identifier;
3722

3823
UnsafeBeanInitMethod() {
39-
isInConfiguration(this) and
4024
isRemoteInvocationSerializingExporter(this.getReturnType()) and
25+
this.getDeclaringType().hasAnnotation("org.springframework.context.annotation", "Configuration") and
4126
exists(Annotation a |
4227
a.getType().hasQualifiedName("org.springframework.context.annotation", "Bean")
4328
|
@@ -51,16 +36,6 @@ private class UnsafeBeanInitMethod extends Method {
5136
string getBeanIdentifier() { result = identifier }
5237
}
5338

54-
from File file, string identifier
55-
where
56-
exists(UnsafeBeanInitMethod method |
57-
file = method.getFile() and
58-
identifier = method.getBeanIdentifier()
59-
)
60-
or
61-
exists(SpringBean bean |
62-
isRemoteInvocationSerializingExporter(bean.getClass()) and
63-
file = bean.getFile() and
64-
identifier = bean.getBeanIdentifier()
65-
)
66-
select file, "Unsafe deserialization in Spring exporter bean '" + identifier + "'"
39+
from UnsafeBeanInitMethod method
40+
select method,
41+
"Unsafe deserialization in a Spring exporter bean '" + method.getBeanIdentifier() + "'"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
<overview>
5+
<p>
6+
The Spring Framework provides an abstract base class <code>RemoteInvocationSerializingExporter</code>
7+
for creating remote service exporters.
8+
A Spring exporter, which is based on this class, deserializes incoming data using <code>ObjectInputStream</code>.
9+
Deserializing untrusted data is easily exploitable and in many cases allows an attacker
10+
to execute arbitrary code.
11+
</p>
12+
<p>
13+
The Spring Framework also provides two classes that extend <code>RemoteInvocationSerializingExporter</code>:
14+
<li>
15+
<code>HttpInvokerServiceExporter</code>
16+
</li>
17+
<li>
18+
<code>SimpleHttpInvokerServiceExporter</code>
19+
</li>
20+
</p>
21+
<p>
22+
These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request
23+
using unsafe <code>ObjectInputStream</code>. If a remote attacker can reach such endpoints,
24+
it results in remote code execution in the worst case.
25+
</p>
26+
<p>
27+
CVE-2016-1000027 has been assigned to this issue in the Spring Framework.
28+
It is regarded as a design limitation, and can be mitigated but not fixed outright.
29+
</p>
30+
</overview>
31+
32+
<recommendation>
33+
<p>
34+
Avoid using <code>HttpInvokerServiceExporter</code>, <code>SimpleHttpInvokerServiceExporter</code>
35+
and any other exporter that is based on <code>RemoteInvocationSerializingExporter</code>.
36+
Instead, use other message formats for API endpoints (for example, JSON),
37+
but make sure that the underlying deserialization mechanism is properly configured
38+
so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced,
39+
consider using global deserialization filters introduced in JEP 290.
40+
</p>
41+
</recommendation>
42+
43+
<example>
44+
<p>
45+
The following examples shows how a vulnerable HTTP endpoint can be defined in a Spring XML config:
46+
</p>
47+
<sample src="SpringExporterUnsafeDeserialization.xml" />
48+
</example>
49+
50+
<references>
51+
<li>
52+
OWASP:
53+
<a href="https://www.owasp.org/index.php/Deserialization_of_untrusted_data">Deserialization of untrusted data</a>.
54+
</li>
55+
<li>
56+
Spring Framework API documentation:
57+
<a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.html">RemoteInvocationSerializingExporter class</a>
58+
</li>
59+
<li>
60+
Spring Framework API documentation:
61+
<a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.html">HttpInvokerServiceExporter class</a>
62+
</li>
63+
<li>
64+
National Vulnerability Database:
65+
<a href="https://nvd.nist.gov/vuln/detail/CVE-2016-1000027">CVE-2016-1000027</a>
66+
</li>
67+
<li>
68+
Tenable Research Advisory:
69+
<a href="https://www.tenable.com/security/research/tra-2016-20">[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization</a>
70+
</li>
71+
<li>
72+
Spring Framework bug tracker:
73+
<a href="https://github.com/spring-projects/spring-framework/issues/24434">Sonatype vulnerability CVE-2016-1000027 in Spring-web project</a>
74+
</li>
75+
<li>
76+
OpenJDK:
77+
<a href="https://openjdk.java.net/jeps/290">JEP 290: Filter Incoming Serialization Data</a>
78+
</li>
79+
</references>
80+
81+
</qhelp>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @name Unsafe deserialization with Spring's remote service exporters.
3+
* @description A Spring bean, which is based on RemoteInvocationSerializingExporter,
4+
* initializes an endpoint that uses ObjectInputStream to deserialize
5+
* incoming data. In the worst case, that may lead to remote code execution.
6+
* @kind problem
7+
* @problem.severity error
8+
* @precision high
9+
* @id java/unsafe-deserialization-spring-exporter-in-xml-configuration
10+
* @tags security
11+
* external/cwe/cwe-502
12+
*/
13+
14+
import java
15+
import semmle.code.java.frameworks.spring.SpringBean
16+
import UnsafeSpringExporterLib
17+
18+
from SpringBean bean
19+
where isRemoteInvocationSerializingExporter(bean.getClass())
20+
select bean, "Unsafe deserialization in a Spring exporter bean '" + bean.getBeanIdentifier() + "'"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import java
2+
3+
/**
4+
* Holds if `type` is `RemoteInvocationSerializingExporter`.
5+
*/
6+
predicate isRemoteInvocationSerializingExporter(RefType type) {
7+
type.getASupertype*()
8+
.hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter")
9+
}

java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.expected

Lines changed: 0 additions & 4 deletions
This file was deleted.

java/ql/test/experimental/query-tests/security/CWE-502/SpringExporterUnsafeDeserialization.qlref

Lines changed: 0 additions & 1 deletion
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| SpringExporterUnsafeDeserialization.java:10:32:10:63 | unsafeHttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean '/unsafeHttpInvokerServiceExporter' |
2+
| SpringExporterUnsafeDeserialization.java:18:41:18:88 | unsafeCustomeRemoteInvocationSerializingExporter | Unsafe deserialization in a Spring exporter bean '/unsafeCustomeRemoteInvocationSerializingExporter' |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-502/UnsafeSpringExporterInConfigurationClass.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| beans.xml:10:5:13:12 | /unsafeBooking | Unsafe deserialization in a Spring exporter bean '/unsafeBooking' |
2+
| beans.xml:15:5:18:12 | org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter | Unsafe deserialization in a Spring exporter bean 'org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter' |

0 commit comments

Comments
 (0)