Created
May 11, 2020 02:38
-
-
Save cetaSYN/4d6c8fa970ac3b8529bb665cca2a222f to your computer and use it in GitHub Desktop.
Finds uids for usernames on CTFtime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""Finds uids for usernames on CTFtime""" | |
# Seriously why is this not easier to do? | |
import argparse | |
import logging | |
import math | |
import re | |
import time | |
import requests | |
logging.basicConfig() | |
log = logging.getLogger(__name__) | |
log.setLevel(logging.INFO) | |
URL = "https://ctftime.org/user/{}" | |
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) \ | |
AppleWebKit/537.36 (KHTML, like Gecko) \ | |
Chrome/81.0.4044.138 Safari/537.36})" | |
failed_attempts = 0 | |
def main(): | |
args = get_init_args() | |
usernames = args.usernames | |
if args.start: | |
i = args.start | |
else: | |
i = get_top_uid() | |
while i > 0 and len(usernames) > 0: | |
resp = delayed_get(URL.format(i), headers={"User-Agent": USER_AGENT}) | |
if not req_success(resp): | |
log.error("Request failed") | |
continue | |
usermatch = has_usernames(resp.content, usernames) | |
if usermatch: | |
print(f"{usermatch} ({i}) - {URL.format(i)}") | |
usernames.remove(usermatch) | |
i -= 1 | |
def has_usernames(content, usernames): | |
"""Returns username if found in title from usernames list""" | |
match = re.search( | |
r"<title>CTFtime.org / ([a-zA-Z0-9@._-]+)</title>", | |
str(content) | |
) # Format may change; not sure regex matches all possibilities | |
if not match: | |
return None | |
title = match.group(1) | |
for username in usernames: | |
log.debug(f"{username.lower()} : {str(title).lower()}") | |
if username.lower() in str(title).lower(): | |
return username | |
return None | |
def get_top_uid(): | |
"""Finds the current maximum uid""" | |
i = 100000 | |
iter_by = 100000 # Multiple of 10 | |
target_code = 404 | |
swap_code = 200 | |
while True: | |
resp = delayed_get(URL.format(i), headers={"User-Agent": USER_AGENT}) | |
log.debug(URL.format(i)) | |
if not req_success(resp): | |
log.error("Request failed") | |
continue | |
if abs(iter_by) == 1: # Final search | |
if resp.status_code == 404: | |
return i - 1 | |
i += 1 | |
else: # Main search | |
if resp.status_code == target_code: | |
target_code, swap_code = swap_code, target_code | |
iter_by = -(math.floor(iter_by/10)) | |
i += iter_by | |
def delayed_get(url, delay=0.5, headers=None): # 2 req/sec default to be nice | |
"""Performs a delayed requests GET to the specified url""" | |
log.debug(f"Waiting for {delay} seconds") | |
time.sleep(delay) | |
log.debug(f"GET: {url}") | |
return requests.get(url, headers=headers) | |
def req_success(resp): | |
"""Returns True if status code represents a desirable status code | |
NOTE: 3 consecutive failures will terminate execution | |
""" | |
global failed_attempts | |
if resp.status_code not in [200, 404]: | |
failed_attempts += 1 | |
if failed_attempts >= 3: # This logic probably doesn't belong here | |
log.critical("Failed 3 consecutive requests") | |
exit(-1) | |
return False | |
failed_attempts = 0 | |
return True | |
def get_init_args(): | |
"""Handles argparse argument processing""" | |
parser = argparse.ArgumentParser(__doc__) | |
parser.add_argument("usernames", nargs="+") | |
parser.add_argument("--start", type=int, help="Starting index") | |
parser.add_argument("--debug", action="store_true") | |
args = parser.parse_args() | |
if args.debug: | |
log.setLevel(logging.DEBUG) | |
log.debug(args) | |
return args | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
requests | |
BS4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example:
Additional Options:
--start <int>
: Index to begin decrementing at--debug
: Output additional debugging information