├── README.md ├── leetlinked.py ├── requirements.txt └── user_agents.txt /README.md: -------------------------------------------------------------------------------- 1 | # L33tLinked 2 | 3 | Hello dear reader! 4 | 5 | Welcome to my modification of CrossLinked (Can be found here: https://github.com/m8r0wn/CrossLinked ). Crosslink/L33tLinked is a LinkedIn scraping tool that utilizes both Google and Bing to grab LinkedIn profiles. Whats the use for this? Well, collecting all known employees in a comapny can be used on a red-team op for searching for employees that are involved in Data Breaches. It's simple enough to take the info you'll recieve here and run the info through the Dehashed/Have I Been Pwned API to determine if the user was affected by a data breach! 6 | 7 | ## Setup 8 | ```bash 9 | git clone https://github.com/Sq00ky/L33tLinked.git 10 | cd LeetLinked 11 | pip3 install -r requirements.txt 12 | ``` 13 | 14 | ## Sample Syntax 15 | ```bash 16 | python3 leetlinked.py microsoft -e microsoft.com -f 1 17 | 18 | 19 | /$$ /$$ /$$ /$$ /$$ /$$ 20 | | $$ | $$ | $$ |__/ | $$ | $$ 21 | | $$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ /$$ /$$$$$$$ | $$ /$$ /$$$$$$ /$$$$$$$ 22 | | $$ /$$__ $$ /$$__ $$|_ $$_/ | $$ | $$| $$__ $$| $$ /$$/ /$$__ $$ /$$__ $$ 23 | | $$ | $$$$$$$$| $$$$$$$$ | $$ | $$ | $$| $$ \ $$| $$$$$$/ | $$$$$$$$| $$ | $$ 24 | | $$ | $$_____/| $$_____/ | $$ /$$| $$ | $$| $$ | $$| $$_ $$ | $$_____/| $$ | $$ 25 | | $$$$$$$$| $$$$$$$| $$$$$$$ | $$$$/| $$$$$$$$| $$| $$ | $$| $$ \ $$| $$$$$$$| $$$$$$$ 26 | |________/ \_______/ \_______/ \___/ |________/|__/|__/ |__/|__/ \__/ \_______/ \_______/ 27 | 28 | Based off of https://github.com/m8r0wn/CrossLinked 29 | @horshark // @Sq00ky 30 | 31 | Email format jsmith@company.xyz chosen 32 | 33 | Scrape Complete! 34 | ``` 35 | 36 | ## Help Menu 37 | ```bash 38 | python3 leetlinked.py --help 39 | positional arguments: 40 | company_name Target company name 41 | 42 | optional arguments: 43 | -h, --help show this help message and exit 44 | -t TIMEOUT Timeout [seconds] for search threads (Default: 25) 45 | -j JITTER Jitter for scraping evasion (Default: 0) 46 | -s, --safe Only parse names with company in title (Reduces false positives) 47 | -e EMAIL_DOMAIN, --email-domain EMAIL_DOMAIN 48 | Include the email domain for email-generation (Example: microsoft.com) 49 | -p HIBP, --hibp HIBP Runs all of the emails through HaveIBeenPwned's API and will list pwned accounts, API key is a required argument. 50 | -f EMAIL_FORMAT, --email-format EMAIL_FORMAT 51 | Generates emails based on various formats, 1=jsmith 2=johnsmith 3=johns 4=smithj 5=john.smith 6=smith.john 7=smith 52 | ``` 53 | 54 | ## Todo: 55 | 56 | - [x] Implement more email formats, lastnamef, firstlast, fl, etc. (Pls create issues to request more) 57 | - [x] Implement HIBP API - Finished 58 | - [ ] Implement DeHashed API - (It's going to cost a fair bit of money to do this because dehash costs $ per query...) 59 | - [ ] Completely re-write tool so it's not based on someone elses 60 | 61 | Modified by Ronnie Bartwitz / Ronald Bartwitz // @Horshark 62 | -------------------------------------------------------------------------------- /leetlinked.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse, requests 3 | import xlwt, xlrd, json 4 | 5 | from sys import exit 6 | from time import sleep 7 | from random import choice 8 | from threading import Thread 9 | from bs4 import BeautifulSoup 10 | import os 11 | requests.packages.urllib3.disable_warnings() 12 | USER_AGENTS = [line.strip() for line in open('user_agents.txt')] 13 | 14 | class bcolors: 15 | HEADER = '\033[95m' 16 | OKBLUE = '\033[94m' 17 | OKGREEN = '\033[92m' 18 | WARNING = '\033[93m' 19 | FAIL = '\033[91m' 20 | ENDC = '\033[0m' 21 | BOLD = '\033[1m' 22 | UNDERLINE = '\033[4m' 23 | 24 | # Printing the banner. 25 | def banner(): 26 | print(bcolors.BOLD + """ 27 | 28 | /$$ /$$ /$$ /$$ /$$ /$$ 29 | | $$ | $$ | $$ |__/ | $$ | $$ 30 | | $$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ /$$ /$$$$$$$ | $$ /$$ /$$$$$$ /$$$$$$$ 31 | | $$ /$$__ $$ /$$__ $$|_ $$_/ | $$ | $$| $$__ $$| $$ /$$/ /$$__ $$ /$$__ $$ 32 | | $$ | $$$$$$$$| $$$$$$$$ | $$ | $$ | $$| $$ \ $$| $$$$$$/ | $$$$$$$$| $$ | $$ 33 | | $$ | $$_____/| $$_____/ | $$ /$$| $$ | $$| $$ | $$| $$_ $$ | $$_____/| $$ | $$ 34 | | $$$$$$$$| $$$$$$$| $$$$$$$ | $$$$/| $$$$$$$$| $$| $$ | $$| $$ \ $$| $$$$$$$| $$$$$$$ 35 | |________/ \_______/ \_______/ \___/ |________/|__/|__/ |__/|__/ \__/ \_______/ \_______/ 36 | 37 | """ + bcolors.OKGREEN + "Based off of https://github.com/m8r0wn/CrossLinked\n" + bcolors.OKBLUE + "@Sq00ky and @Horshark on Github") 38 | 39 | 40 | # ScrapeEngine for google and bing. 41 | class ScrapeEngine(): 42 | URL = {'google': 'https://www.google.com/search?q=site:linkedin.com/in+"{}"&num=100&start={}', 43 | 'bing': 'https://www.bing.com/search?q=site:linkedin.com/in+"{}"&first={}'} 44 | 45 | def __init__(self): 46 | self.linkedin = {} 47 | self.running = True 48 | 49 | def timer(self, time): 50 | sleep(time) 51 | self.running = False 52 | 53 | def search(self, search_engine, company_name, timeout, jitter): 54 | # Define search as "running" after init(), not used in DNS_Enum 55 | self.running = True 56 | 57 | # Start timeout thread 58 | Thread(target=self.timer, args=(timeout,), daemon=True).start() 59 | 60 | # Total Links found by search engine 61 | self.search_links = 0 62 | # Total names found from linkedin 63 | self.name_count = 0 64 | 65 | # Local count to detect when no new names are found 66 | found_names = 0 67 | 68 | while self.running: 69 | if self.search_links > 0 and found_names == self.name_count: 70 | return self.linkedin 71 | 72 | found_names = self.name_count 73 | self.name_search(search_engine, self.search_links, company_name, jitter) 74 | return self.linkedin 75 | 76 | def name_search(self, search_engine, count, company_name, jitter): 77 | url = self.URL[search_engine].format(company_name, count) 78 | 79 | for link in get_links(get_request(url, 3)): 80 | url = str(link.get('href')).lower() 81 | 82 | if (search_engine+".com") not in url and not url.startswith("/"): 83 | self.search_links += 1 84 | 85 | if "linkedin.com/in" in url and self.extract_linkedin(link, company_name) : 86 | self.name_count += 1 87 | sleep(jitter) 88 | 89 | def extract_linkedin(self, link, company_name): 90 | if debug: 91 | print("[*] Parsing Linkedin User: {}".format(link.text)) 92 | 93 | if safe and company_name.lower() not in link.text.lower(): 94 | return False 95 | 96 | try: 97 | x = link.text.split("|")[0] 98 | x = x.split("...")[0] 99 | 100 | # Extract Name (if title provided) 101 | if "–" in x: 102 | name = link.text.split("–")[0].rstrip().lstrip() 103 | elif "-" in x: 104 | name = link.text.split("-")[0].rstrip().lstrip() 105 | elif "|" in x: 106 | name = link.text.split("|")[0].rstrip().lstrip() 107 | else: 108 | name = x 109 | 110 | try: 111 | # Quick split to extract title, but focus on name 112 | title = link.text.split("-")[1].rstrip().lstrip() 113 | if "..." in title: 114 | title = title.split("...")[0].rstrip().lstrip() 115 | if "|" in title: 116 | title = title.split("|")[0].rstrip().lstrip() 117 | except: 118 | title = "N/A" 119 | tmp = name.split(' ') 120 | name = ''.join(e for e in tmp[0] if e.isalnum()) + " " + ''.join(e for e in tmp[1] if e.isalnum()) 121 | 122 | # Catch 1st letter last name: Fname L. 123 | tmp = name.split(' ') 124 | 125 | if len(tmp[0]) <= 1 or len(tmp[-1]) <=1: 126 | raise Exception("\'{}\' Failed name parsing".format(link.text)) 127 | elif tmp[0].endswith((".","|")) or tmp[-1].endswith((".","|")): 128 | raise Exception("\'{}\' Failed name parsing".format(link.text)) 129 | 130 | if name not in self.linkedin: 131 | self.linkedin[name] = {} 132 | self.linkedin[name]['last'] = name.split(' ')[1].lower().rstrip().lstrip() 133 | self.linkedin[name]['first'] = name.split(' ')[0].lower().rstrip().lstrip() 134 | self.linkedin[name]['title'] = title.strip().lower().rstrip().lstrip() 135 | return True 136 | 137 | except Exception as e: 138 | if debug: 139 | print("[!] Debug: {}".format(str(e))) 140 | return False 141 | 142 | 143 | # Requests and links. 144 | def get_links(raw_response): 145 | # Returns a list of links from raw requests input 146 | links = [] 147 | soup = BeautifulSoup(raw_response.content, 'html.parser') 148 | for link in soup.findAll('a'): 149 | try: 150 | links.append(link) 151 | except: 152 | pass 153 | return links 154 | 155 | def get_request(link, timeout): 156 | # HTTP(S) GET request w/ user defined timeout 157 | head = { 158 | 'User-Agent': '{}'.format(choice(USER_AGENTS)), 159 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 160 | 'Accept-Language': 'en-US,en;q=0.5', 161 | 'Accept-Encoding': 'gzip, deflate', 162 | 'DNT': '1', 163 | 'Connection': 'keep-alive', 164 | 'Upgrade-Insecure-Requests': '1'} 165 | return requests.get(link, headers=head, verify=False, timeout=timeout) 166 | 167 | 168 | def main(args): 169 | found_names = {} 170 | search = ['google', 'bing'] 171 | banner() 172 | 173 | # Sets the email format. 174 | if args.email_format == 1: 175 | print(bcolors.HEADER + "Email format jsmith@company.xyz chosen\n") 176 | elif args.email_format == 2: 177 | print(bcolors.HEADER + "Email format johnsmith@company.xyz chosen\n") 178 | elif args.email_format == 3: 179 | print(bcolors.HEADER + "Email format johns@company.xyz chosen\n") 180 | elif args.email_format == 4: 181 | print(bcolors.HEADER + "Email format smithj@company.xyz chosen\n") 182 | elif args.email_format == 5: 183 | print(bcolors.HEADER + "Email format john.smith@company.xyz chosen\n") 184 | elif args.email_format == 6: 185 | print(bcolors.HEADER + "Email format smith.john@company.xyz chosen\n") 186 | elif args.email_format == 7: 187 | print(bcolors.HEADER + "Email format smith@company.xyz chosen\n") 188 | elif args.email_format == 8: 189 | print(bcolors.HEADER + "Email format john@company.xyz chosen\n") 190 | elif args.email_format == 9: 191 | print(bcolors.HEADER + "Email format john_smith@company.xyz chosen\n") 192 | elif args.email_format == 10: 193 | print(bcolors.HEADER + "Email format smith_john@company.xyz chosen\n") 194 | elif args.email_format == 11: 195 | print(bcolors.HEADER + "Email format js@company.xyz chosen\n") 196 | 197 | # Sheet's variables. 198 | q = 1 199 | w = 2 # NOTE: Variable W is for when working within spreadsheet. Python starts at 0 and counts upwards from there. Excel starts at 1, causing there to be a downwards shift in cells within formulas. 200 | wb = xlwt.Workbook() 201 | ws = wb.add_sheet('Scraped LinkedIn Employees', cell_overwrite_ok=True) 202 | compname = args.company_name 203 | compname = compname[:-4] + "Scraped.xls" 204 | 205 | ## Column vars. 206 | col_offset = 10 207 | col_fname = 0 208 | col_lname = 1 209 | col_job = 2 210 | col_email = 3 211 | col_pwned = 4 212 | col_breaches = 5 213 | col_passwords = 6 214 | 215 | # Names. 216 | f_name = "First Name:" 217 | l_name = "Last Name:" 218 | job_name = "Job Title:" 219 | email_name = "Email:" 220 | 221 | pwned_name = "Pwned:" 222 | breaches_name = "Breaches:" 223 | passwords_name = "Passwords Breached:" 224 | 225 | # Write the name of the columns. 226 | ws.write(0, col_fname, f_name) 227 | ws.write(0, col_lname, l_name) 228 | ws.write(0, col_job, job_name) 229 | ws.write(0, col_email, email_name) 230 | 231 | if args.hibp != "": 232 | ws.write(0, col_pwned, pwned_name) 233 | ws.write(0, col_breaches, breaches_name) 234 | ws.write(0, col_passwords, passwords_name) 235 | 236 | # Width of each column, for later adjustment. 237 | f_size = len(f_name) 238 | l_size = len(l_name) 239 | job_size = len(job_name) 240 | email_size = len(email_name) 241 | pwned_size = len(pwned_name) 242 | breaches_size = len(breaches_name) 243 | passwords_size = len(passwords_name) 244 | 245 | 246 | # Main loop. 247 | for site in search: 248 | 249 | # Start the scrape engine. 250 | lkin = ScrapeEngine().search(site, args.company_name, args.timeout, args.jitter) 251 | 252 | if lkin: 253 | # Makes requests. 254 | breaches_pass = [] 255 | hibp_url = "https://haveibeenpwned.com/api/v3/breaches" 256 | response = requests.get(hibp_url, headers={'hibp-api-key':args.hibp}) 257 | response_json = json.loads(response.content) 258 | 259 | # Add every breach that contains password exposition to a list. 260 | for breach in response_json: 261 | if "Passwords" in breach["DataClasses"]: 262 | breaches_pass.append(breach["Name"]) 263 | # For each person.. 264 | for name, data in lkin.items(): 265 | # Get his names, job and email. 266 | fname = data['first'] 267 | lname = data['last'] 268 | job = data['title'] 269 | 270 | if args.email_format == 1: 271 | email = fname[0]+lname+"@"+args.email_domain 272 | # jsmith first_initial last 273 | elif args.email_format == 2: 274 | email = fname+lname+"@"+args.email_domain 275 | # johnsmith first last 276 | elif args.email_format == 3: 277 | email = fname+lname[0]+"@"+args.email_domain 278 | # johns first last_initial 279 | elif args.email_format == 4: 280 | email = lname+fname[0]+"@"+args.email_domain 281 | # smithj 282 | elif args.email_format == 5: 283 | email = fname+"."+lname+"@"+args.email_domain 284 | # john.smith 285 | elif args.email_format == 6: 286 | email = lname+"."+fname+"@"+args.email_domain 287 | # smith.john 288 | elif args.email_format == 7: 289 | email = lname+"@"+args.email_domain 290 | #smith 291 | elif args.email_format == 8: 292 | email = fname+"@"+args.email_domain 293 | #john 294 | elif args.email_format == 9: 295 | email = fname+"_"+lname+"@"+args.email_domain 296 | #john_smith 297 | elif args.email_format == 10: 298 | email = lname+"_"+fname+"@"+args.email_domain 299 | #smith_john 300 | elif args.email_format == 11: 301 | email = lname[0]+fname[0]+"@"+args.email_domain 302 | 303 | # Writes the person's info. 304 | ws.write(q, col_fname, fname) 305 | ws.write(q, col_lname, lname) 306 | ws.write(q, col_job, job) 307 | ws.write(q, col_email, email) 308 | 309 | # Check for the longest width. 310 | if len(fname) > f_size: 311 | f_size = len(fname) 312 | if len(lname) > f_size: 313 | l_size = len(lname) 314 | if len(job) > job_size: 315 | job_size = len(job) 316 | if len(email) > email_size: 317 | email_size = len(email) 318 | 319 | # If Have I Been Pwned option is on. 320 | if args.hibp != "": 321 | # Requests the URL. 322 | hibp_url = "https://haveibeenpwned.com/api/v3/breachedaccount/" 323 | hibp_email = email 324 | hibp_request = hibp_url + hibp_email 325 | 326 | # The API doesn't like getting spammed. 327 | sleep(1.5) 328 | 329 | response = requests.get(hibp_request, headers={'hibp-api-key':args.hibp}) 330 | response_code = response.status_code 331 | 332 | # Prints the result to each email. 333 | if response_code == 200: 334 | print(bcolors.FAIL + "Found in Breach - " + hibp_email) 335 | else: 336 | print(bcolors.OKBLUE + "Not found - " + hibp_email) 337 | # If the response is positive.. 338 | if response_code == 200: 339 | # Writes pwned col to yes. 340 | ws.write(q, col_pwned, "Y") 341 | response_json = json.loads(response.content) 342 | 343 | breaches_string = "" 344 | passwords_string = "" 345 | 346 | breached_n = len(response_json) 347 | 348 | # Adds every breach name to a list. 349 | for i in range(0, breached_n): 350 | breach = response_json[i]["Name"] 351 | 352 | # Adds breach to breach list. 353 | breaches_string += breach 354 | if i != breached_n-1: 355 | breaches_string += ", " 356 | 357 | # If breach contains passwords leak, adds it to pass_breach list. 358 | if breach in breaches_pass: 359 | if len(passwords_string) != 0: 360 | passwords_string += " - " 361 | 362 | passwords_string += breach 363 | 364 | # Checks for the longest width. 365 | if len(breaches_string) > breaches_size: 366 | breaches_size = len(breaches_string) 367 | if len(passwords_string) > passwords_size: 368 | passwords_size = len(passwords_string) 369 | 370 | 371 | # Writes breached services. 372 | ws.write(q, col_breaches, breaches_string) 373 | ws.write(q, col_passwords, passwords_string) 374 | 375 | # Otherwise.. 376 | else: 377 | # Writes no to pwned col. 378 | ws.write(q, col_pwned, "N") 379 | 380 | w = w + 1 381 | q = q + 1 382 | 383 | id = data['first'] + ":" + data['last'] 384 | 385 | if name and id not in found_names: 386 | found_names[id] = data 387 | 388 | # Finally, sets the coiums width to their maximum. 389 | ws.col(col_fname).width = 257 * f_size + col_offset 390 | ws.col(col_lname).width = 257 * l_size + col_offset 391 | ws.col(col_job).width = 257 * job_size + col_offset 392 | ws.col(col_email).width = 257 * email_size + col_offset 393 | ws.col(col_pwned).width = 257 * 8 + col_offset 394 | ws.col(col_breaches).width = 257 * breaches_size + col_offset 395 | ws.col(col_passwords).width = 257 * passwords_size + col_offset 396 | 397 | # Write to the actual file. 398 | wb.save(compname) 399 | currentdir = os.getcwd() 400 | print("Scrape Complete! Results saved to " + currentdir + "/" + compname) 401 | 402 | if __name__ == '__main__': 403 | VERSION = "1.0" 404 | 405 | args = argparse.ArgumentParser(description="", formatter_class=argparse.RawTextHelpFormatter, usage=argparse.SUPPRESS) 406 | 407 | args.add_argument('-t', dest='timeout', type=int, default=25,help='Timeout [seconds] for search threads (Default: 25)') 408 | args.add_argument('-j', dest='jitter', type=float, default=0,help='Jitter for scraping evasion (Default: 0)') 409 | args.add_argument('-s', "--safe", dest="safe", action='store_true',help="Only parse names with company in title (Reduces false positives)") 410 | args.add_argument('-e', "--email-domain", required=True, dest="email_domain", help="Include the email domain for email-generation (Example: microsoft.com) ") 411 | args.add_argument('-p', "--hibp", type=str, required=False, dest="hibp", default="", help="Runs all of the emails through HaveIBeenPwned's API and will list pwned accounts, API key is a required argument.") 412 | args.add_argument('-f', "--email-format", dest="email_format", required=True,type=int,default=1, help="Generates emails based on various formats, 1=jsmith 2=johnsmith 3=johns 4=smithj 5=john.smith 6=smith.john 7=smith, 8=john 9=john_smith 10=smith_john 11=js") 413 | 414 | args.add_argument(dest='company_name', nargs='+', help='Target company name') 415 | 416 | args = args.parse_args() 417 | safe = args.safe 418 | debug = False 419 | args.company_name = args.company_name[0] 420 | 421 | try: 422 | main(args) 423 | except KeyboardInterrupt: 424 | print("[!] Key event detected, closing...") 425 | exit(0) 426 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bs4 2 | unidecode 3 | requests 4 | argparse 5 | xlwt 6 | xlrd 7 | -------------------------------------------------------------------------------- /user_agents.txt: -------------------------------------------------------------------------------- 1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 2 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 3 | Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0 4 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 5 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7 6 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 7 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 8 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 9 | Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0 10 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36 11 | Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0 12 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 13 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 14 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:57.0) Gecko/20100101 Firefox/57.0 15 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36 16 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64 17 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299 18 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7 19 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 20 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 21 | Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0 22 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 23 | Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko 24 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 25 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 26 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36 27 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 28 | Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0 29 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 30 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:57.0) Gecko/20100101 Firefox/57.0 31 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36 32 | Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0 33 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/63.0.3239.84 Chrome/63.0.3239.84 Safari/537.36 34 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5 35 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 36 | Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko 37 | Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0 38 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 39 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7 40 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063 41 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 42 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36 43 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 44 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 45 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OPR/50.0.2762.58 46 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 47 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 48 | Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0 49 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:57.0) Gecko/20100101 Firefox/57.0 50 | Mozilla/5.0 (Windows NT 6.1; rv:57.0) Gecko/20100101 Firefox/57.0 51 | Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0 52 | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 53 | Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0 54 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 55 | Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0 56 | Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko 57 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8 58 | Mozilla/5.0 (iPad; CPU OS 11_2_1 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0 Mobile/15C153 Safari/604.1 59 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 60 | Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Trident/5.0) 61 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 62 | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0 63 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 64 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5 65 | Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 66 | Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; Trident/5.0) 67 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 68 | Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 69 | Mozilla/5.0 (Windows NT 5.1; rv:52.0) Gecko/20100101 Firefox/52.0 70 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 71 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:57.0) Gecko/20100101 Firefox/57.0 72 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8 73 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 74 | Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 75 | Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 76 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 77 | --------------------------------------------------------------------------------