Kubernetes: Multiple issues in aws-iam-authenticator
Kubernetes AWS IAM integration (https://github.com/kubernetes-sigs/aws-iam-authenticator/) is implemented
on top of the sts:GetCallerIdentity AWS API (https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html). A client
authenticates by pre-signing a request to the API endpoint and forwarding it to the server as an
Auth token. The server decodes the token and forwards the request to the AWS STS server.
The server side part of this code is implemented in the Verify method in pkg/token/token.go
(https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/pkg/token/token.go).
Looking at this method there are a couple of issues:
1. Host regexp is too lax: The server needs to ensure that the presigned URL received from the
client actually points to a real STS server. Otherwise, the auth mechanism is easy to bypass by
pointing the request at an attacker controlled server. aws-iam-authenticator uses
`^sts(\\.[a-z1-9\\-]+)?\\.amazonaws\\.com(\\.cn)?$` to enforce that the URL host
component points to an STS server. However, this regex is not strict enough and allows requests to
a wide range of AWS services. The most interesting one is probably S3, where URLs like
sts.s3.amazonaws.com, sts.s3-us-gov-west-1.amazonaws.com or sts.s3-control.cn-north-1.amazonaws.com.cn
point at S3 buckets named STS that can be owned by an arbitrary AWS customer.
Luckily I was not able to find a simple way to exploit this as S3 does not
allow you to host user controlled content on the \"/\" path. If that changes, you can somehow trick
the AWS query parser or an additional AWS service with a similar domain scheme launches, this could
become exploitable. FWIW I'm also slightly concerned about the complete lack of region isolation
here. It seems unexpected to me that the owner of a random amazonaws.com.cn subdomain can login
into arbitrary EKS clusters.
2. HTTP client follows redirects: The code uses the standard Golang HTTP client in its default
configuration which follows HTTP redirects. This might make 1. easier to exploit if an attacker can
find an open redirect issue on a host that matches the hostname regex.
3. URL.Query vs ParseQuery: The function enforces an allowlist of valid query values by iterating
through the parameter map returned by URL.Query(). However, Query() silently drops parameters that
Go considers invalid. This could become a problem if the AWS URL parser and Go disagree. The
ParseQuery() method additionally returns an error if it encounters invalid parameters and should
probably be used instead.
4. Request smuggling for Go version < 1.12: Older versions of Golang are vulnerable to request
smuggling issues when requesting malformed URLs containing spaces and newlines
(https://github.com/golang/go/issues/22907). As Go reuses TCP connections for the default HTTP
client, this can be used to bypass most of the request filtering implemented in token.go and
potentially to leak parallel request from other clients. Current official releases of
aws-iam-authenticator are not built with a vulnerable Go version, but it might be useful to verify
if this is a problem for older clusters. (https://amazon-eks.s3.us-west-2.amazonaws.com/ lists a
couple of binaries that are affected by this, but I'm not sure if they would still be used
somewhere)
Credits: Felix Wilhelm of Google Project Zero
This bug is subject to a 90 day disclosure deadline. After 90 days elapse, the bug report will
become visible to the public. The scheduled disclosure date is 2020-10-13. Disclosure at an earlier
date is also possible if agreed upon by all parties
Found by: fwilhelm@google.com