Last week, we disclosed a CSRF-style vulnerability in Spring Social Core to Pivotal. Today, we will talk about a denial of service vulnerability in the Amazon AWS SDK for Java. This official AWS SDK is used by Java developers to integrate with various AWS services including interaction with the Amazon APIs for storing and retrieving files from S3 buckets. The releases 1.8.0 to 1.10.34 of the AWS Java SDK are affected by this vulnerability. The current latest release 1.10.36 is not affected.
This vulnerability can be exploited in a web service that uses the AWS Java SDK to process files stored on Amazon S3. An attacker can upload a file to the S3 bucket which when subsequently processed by the web service using the SDK would lead to an infinite loop causing denial of service.
Given that the AWS Java SDK is the default and standard way for Java applications to interact with Amazon services, this vulnerability has a large potential impact. For example, Nuxeo a popular open-source, content management platform uses Amazon AWS S3 SDK for storing files. A large number of business applications built using the Nuxeo platform may be affected by this issue. (Correction: We received further information from Nuxeo that they do not read the InputStream
or call the skip()
method. Thus, users of Nuxeo are not affected by this particular issue. I apologize for the confusion.)
We disclosed the issue privately to the Amazon AWS security team. Amazon was prompt and swift in fixing the issue and a new version of the SDK was released on Maven Central last week. The code changes can be viewed in this commit.
If you are a SourceClear customer, you are already protected against this issue. You can use our agent, terminal application, Maven or Gradle plugins to scan and detect this vulnerability in your projects.
Overview
The issue is related to the skip
method in the SdkDigestInputStream
class in the SDK. By contract, it should return the number of bytes skipped, but in some cases it returns -1
. The skip
method was added to the class as a fix for another issue on Jun 21, 2014. Before that, the SdkDigestInputStream
did not override the skip
method.
Teardown
If we look at the official Java docs for the skip
method of InputStream
class, it says that the method should return the actual number of bytes skipped. If no bytes are skipped or if the input is negative the skip
method can return zero. However, it is not expected that the skip
method may return a negative number under any condition.
At line 75 of SdkDigestInputStream.java in the original commit available at https://github.com/aws/aws-sdk-java/commit/257dd4908cf99ec1982feed247fd2253589c222a#diff-97412a92b5fccaea1893be646257fa3b, it is possible for the skip
method to return -1
:
This negative return value can cause problems for the callers of this method as they can assume that the skip
method will never return a negative number. As an example, have a look at the IOUtils
class in the popular Apache Commons Compress library. It implements a skip
method that in-turn calls the skip
method on the underlying InputStream
:
This method has the following while
loop where the value returned by the skip
is used to compute the condition to exit the loop.
while (numToSkip > 0) {
long skipped = input.skip(numToSkip);
if (skipped == 0) {
break;
}
numToSkip -= skipped;
}
When the underlying input
stream is read from a S3 bucket using the Amazon S3 SDK, the skip method may return -1
. That value is stored in the skipped
variable. Thus, at the end of the loop numToSkip -= skipped
becomes numToSkip -= -1
. This will end up incrementing numToSkip
variable and the loop will continue forever.
Note: The Apache Commons Compress library is only used as an example. The same problem can arise when using other libraries that use InputStream
or in an application directly if it calls the skip
method.
Walkthrough
The attack scenario for this vulnerability existing during the processing of stored files from S3 buckets using the AWS SDK. The Apache Commons Compress library is a popular library used to process archives in Java.
A web service using Amazon S3 to store say .tar
files is susceptible to denial of service. The attacker needs to create an archive with extra padding (empty bytes) after an entry and upload to the web site.
Then, while reading the file the inputStream
created using the AWS S3 SDK will be passed to the TarArchiveInputStream
class in the Apache Commons Compress library. To skip over the extra padding the skipRecordPadding
method is called:
That method calls the skip
method at line 335 which would go into an infinite loop and the web service will get stuck at processing that file, potentially denying service to other users.
Remediation
An updated version of AWS SDK for Java has been released and is on Maven Central. We recommend updating to this version immediately.
If one cannot update their version the instructions below will remediate the issue.
If you are calling the skip
method directly, you can check if the output is >=0
. Otherwise, if needed you can copy the inputStream
from the AWS S3 SDK into a byte array before passing it around in your application. For example, to use the Apache Commons Compress library to process a .tar
file stored on Amazon S3 one can use the following code:
// Assuming that input is the inputStream obtained from the AWS S3 SDK
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(input, baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
TarArchiveInputStream tarStream = new TarArchiveInputStream(bais);
Context
The vulnerability arises because the overridden skip
method in the AWS SDK does not adhere to the contract expected by the interface in the InputStream
. This creates a problem as the callers of skip
method may make assumptions about its behavior based on the documentation of the standard InputStream
interface. In this particular issue, the assumption that skip
may never return a negative value is exploited to create an infinite loop that can lead to a denial of service attack.
Other good examples of a contract violation that lead to a denial of service vulnerability are the recent security issues in the BIND program - CVE-2015-5477 and CVE-2015-5722. The use of assertions in a design-by-contract approach can prevent some of these issues by causing failures early in the program.