Skip to content

Commit

Permalink
Handle stack overflow of CVE-2022-41966.
Browse files Browse the repository at this point in the history
  • Loading branch information
joehni committed Dec 23, 2022
1 parent ee088ee commit e9151f2
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 4 deletions.
106 changes: 106 additions & 0 deletions xstream-distribution/src/content/CVE-2022-41966.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<html>
<!--
Copyright (C) 2022 XStream committers.
All rights reserved.
The software in this package is published under the terms of the BSD
style license a copy of which has been included with this distribution in
the LICENSE.txt file.
Created on 24. November 2022 by Joerg Schaible
-->
<head>
<title>CVE-2022-41966</title>
</head>
<body>

<h2 id="vulnerability">Vulnerability</h2>

<p>CVE-2022-41966: XStream is vulnerable to a Denial of Service attack due to stack overflow.</p>

<h2 id="affected_versions">Affected Versions</h2>

<p>All versions until and including version 1.4.19 are affected, if using the version out of the box.</p>

<h2 id="description">Description</h2>

<p>The processed stream at unmarshalling time contains type information to recreate the formerly written objects.
XStream creates therefore new instances based on these type information. An attacker can manipulate the processed
input stream and replace or inject objects, that result in a stack overflow calculating a recursive hash set causing a
denial of service.</p>

<h2 id="reproduction">Steps to Reproduce</h2>

<p>Create a simple HashSet and use XStream to marshal it to XML. Replace the XML with following snippet and
unmarshal it with XStream:</p>
<div class="Source XML"><pre>&lt;set&gt;
&lt;set&gt;
&lt;set&gt;
&lt;set&gt;
&lt;set&gt;
&lt;set&gt;
&lt;set&gt;
&lt;string&gt;a&lt;/string&gt;
&lt;/set&gt;
&lt;set&gt;
&lt;string&gt;b&lt;/string&gt;
&lt;/set&gt;
&lt;/set&gt;
&lt;set&gt;
&lt;string&gt;c&lt;/string&gt;
&lt;set reference='../../../set/set[2]'/&gt;
&lt;/set&gt;
&lt;/set&gt;
&lt;/set&gt;
&lt;/set&gt;
&lt;/set&gt;
&lt;/set&gt;
</pre></div>
<div class="Source Java"><pre>XStream xstream = new XStream();
xstream.fromXML(xml);
</pre></div>

<p>As soon as the XML gets unmarshalled, the recursive hash calculation is entered and the executing thread is
aborted with a stack overflow error.</p>

<h2 id="impact">Impact</h2>

<p>The vulnerability may allow a remote attacker to terminate the application with a stack overflow error resulting
in a denial of service only by manipulating the processed input stream.</p>

<h2 id="workarounds">Workarounds</h2>

<p>A simple solution is to catch the StackOverflowError in the client code calling XStream.</p>

<p>If your object graph does not use referenced elements at all, you may simply set the NO_REFERENCE mode:</p>

<div class="Source Java"><pre>XStream xstream = new XStream();
xstream.setMode(XStream.NO_REFERENCES);
</pre></div>

<p>If your object graph contains neither a Hashtable, HashMap nor a HashSet (or one of the linked variants of it) then you
can use the security framework to deny the usage of these types:</p>

<div class="Source Java"><pre>XStream xstream = new XStream();
xstream.denyTypes(new Class[]{
java.util.HashMap.class, java.util.HashSet.class, java.util.Hashtable.class, java.util.LinkedHashMap.class, java.util.LinkedHashSet.class
});
</pre></div>

<p>Unfortunately these types are very common. If you only use HashMap or HashSet and your XML refers these only as default
map or set, you may additionally change the default implementation of java.util.Map and java.util.Set at unmarshalling time:</p>

<div class="Source Java"><pre>xstream.addDefaultImplementation(java.util.TreeMap.class, java.util.Map.class);
xstream.addDefaultImplementation(java.util.TreeSet.class, java.util.Set.class);
</pre></div>

<p>However, this implies that your application does not care about the implementation of the map and all elements are comparable.</p>

<p>There is no known workaround to prevent this error except by catching the error in the code calling XStream.</p>

<h2 id="credits">Credits</h2>

<p>Lai Han of nsfocus security team found and reported the issue to XStream and provided the required information to reproduce it.</p>

</body>
</html>
3 changes: 3 additions & 0 deletions xstream-distribution/src/content/changes.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ <h1 id="upcoming-1.4.x">Upcoming 1.4.x maintenance release</h1>

<p>Not yet released.</p>

<p class="highlight">This maintenance release addresses the security vulnerability
<a href="CVE-2022-41966.html">CVE-2022-41966</a>, causing a Denial of Service by raising a stack overflow.</p>

<h2>Major changes</h2>

<ul>
Expand Down
11 changes: 10 additions & 1 deletion xstream-distribution/src/content/security.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<html>
<!--
Copyright (C) 2014, 2015, 2017, 2019, 2020, 2021 XStream committers.
Copyright (C) 2014, 2015, 2017, 2019, 2020, 2021, 2022 XStream committers.
All rights reserved.
The software in this package is published under the terms of the BSD
Expand Down Expand Up @@ -49,6 +49,15 @@ <h2 id="CVEs">Documented Vulnerabilities</h2>
<th>CVE</th>
<th>Description</th>
</tr>
<tr>
<th>Version 1.4.19</th>
<td></td>
</tr>
<tr>
<th><a href="CVE-2022-41966.html">CVE-2022-41966</a></th>
<td>XStream can cause a Denial of Service by injecting recursive collections or maps based on element's hash
values raising a stack overflow.</td>
</tr>
<tr>
<th>Version 1.4.18</th>
<td></td>
Expand Down
3 changes: 2 additions & 1 deletion xstream-distribution/src/content/website.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--
Copyright (C) 2005, 2006 Joe Walnes.
Copyright (C) 2006, 2007, 2010, 2011, 2014, 2015, 2016, 2017, 2020, 2021 XStream committers.
Copyright (C) 2006, 2007, 2010, 2011, 2014, 2015, 2016, 2017, 2020, 2021, 2022 XStream committers.
All rights reserved.
The software in this package is published under the terms of the BSD
Expand Down Expand Up @@ -63,6 +63,7 @@
</section>
<section>
<name>!Vulnerabilities</name>
<page>CVE-2022-41966.html</page>
<page>CVE-2021-21341.html</page>
<page>CVE-2021-21342.html</page>
<page>CVE-2021-21343.html</page>
Expand Down
6 changes: 5 additions & 1 deletion xstream/src/java/com/thoughtworks/xstream/XStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,11 @@ public Object unmarshal(HierarchicalStreamReader reader, Object root, DataHolder
dataHolder.put(COLLECTION_UPDATE_LIMIT, new Integer(collectionUpdateLimit));
dataHolder.put(COLLECTION_UPDATE_SECONDS, new Integer(0));
}
return marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper);
try {
return marshallingStrategy.unmarshal(root, reader, dataHolder, converterLookup, mapper);
} catch (final StackOverflowError e) {
throw new InputManipulationException("Possible Dneial of Service attack by Stack Overflow");
}
} catch (ConversionException e) {
Package pkg = getClass().getPackage();
String version = pkg != null ? pkg.getImplementationVersion() : null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013, 2014, 2017, 2018, 2020, 2021 XStream Committers.
* Copyright (C) 2013, 2014, 2017, 2018, 2020, 2021, 2022 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
Expand Down Expand Up @@ -404,4 +404,35 @@ public void testDoSAttackWithHashtable() {
assertTrue("Limit expected in message", e.getMessage().indexOf("exceeds 5 seconds") >= 0);
}
}

public void testStackOverflowWithRecursiveHashSet() {
final String xml = ""
+ "<set>\n"
+ " <set>\n"
+ " <set>\n"
+ " <set>\n"
+ " <set>\n"
+ " <set>\n"
+ " <string>a</string>\n"
+ " </set>\n"
+ " <set>\n"
+ " <string>b</string>\n"
+ " </set>\n"
+ " </set>\n"
+ " <set>\n"
+ " <string>c</string>\n"
+ " <set reference=\"../../../set/set[2]\"/>\n"
+ " </set>\n"
+ " </set>\n"
+ " </set>\n"
+ " </set>\n"
+ "</set>";

try {
xstream.fromXML(xml);
fail("Thrown " + InputManipulationException.class.getName() + " expected");
} catch (final InputManipulationException e) {
assertTrue(e.getMessage().indexOf("Stack Overflow") >= 0);
}
}
}

0 comments on commit e9151f2

Please sign in to comment.