/nov 23, 2015

Amazon AWS Java SDK Vulnerability Disclosure

By Asankhaya Sharma

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:

image of skip method

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:

image of IOUtils's skip method

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:

image of skipRecordPadding method

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.

Related Posts

By Asankhaya Sharma

Dr. Asankhaya Sharma is the Director of Software Engineering at Veracode. Asankhaya is a cyber security expert and technology leader with over a decade of experience in creating security products for industry, academia and open-source community. He is passionate about building high performing teams and taking innovative products to market. He is also an Adjunct Professor at the Singapore Institute of Technology.