def main(): args = parse_arguments() # Application banner print(BANNER) # Update definitions if hasattr(args, 'perform_update') and args.perform_update: print('[+] Updating definitions') urlretrieve( 'https://raw.githubusercontent.com/bitsadmin/wesng/master/definitions.zip', 'definitions.zip') cves, date = load_definitions('definitions.zip') print('[+] Obtained definitions created at %s' % date) return # Update application if hasattr(args, 'perform_wesupdate') and args.perform_wesupdate: print('[+] Updating wes.py') urlretrieve( 'https://raw.githubusercontent.com/bitsadmin/wesng/master/wes.py', 'wes.py') print('[+] Updated to the latest version. Relaunch wes.py to use.') return # Show tree of supersedes (for debugging purposes) if hasattr(args, 'debugsupersedes') and args.debugsupersedes: cves, date = load_definitions('definitions.zip') productfilter = args.debugsupersedes[0] supersedes = args.debugsupersedes[1:] filtered = [] for cve in cves: if productfilter not in cve['AffectedProduct']: continue filtered.append(cve) debug_supersedes(filtered, supersedes, 0, args.verbosesupersedes) return # Show version if hasattr(args, 'showversion') and args.showversion: cves, date = load_definitions('definitions.zip') print('Wes.py version: %.3f' % VERSION) print('Database version: %s' % date) return # Parse encoding of systeminfo.txt input print('[+] Parsing systeminfo output') systeminfo_data = open(args.systeminfo, 'rb').read() try: productfilter, win, mybuild, version, arch, hotfixes = determine_product( systeminfo_data) except WesException as e: print('[-] ' + str(e)) exit(1) # Parse optional qfe.txt input file if args.qfefile: print('[+] Parsing quick fix engineering (qfe) output') qfe_data = open(args.qfefile, 'rb').read() try: qfe_data = charset_convert(qfe_data) qfe_patches = get_hotfixes(qfe_data) hotfixes = list(set(hotfixes + qfe_patches)) except WesException as e: print('[-] ' + str(e)) exit(1) # Add explicitly specified patches manual_hotfixes = list( set([patch.upper().replace('KB', '') for patch in args.installedpatch])) # Display summary info = '''[+] Operating System - Name: %s - Generation: %s - Build: %s - Version: %s - Architecture: %s''' % (productfilter, win, mybuild, version, arch) if hotfixes: info += '\n - Installed hotfixes (%d): %s' % ( len(hotfixes), ', '.join(['KB%s' % kb for kb in hotfixes])) else: info += '\n - Installed hotfixes: None' if manual_hotfixes: info += '\n - Manually specified hotfixes (%d): %s' % ( len(manual_hotfixes), ', '.join( ['KB%s' % kb for kb in manual_hotfixes])) print(info) # Append manually specified KBs to list of hotfixes hotfixes = list(set(hotfixes + manual_hotfixes)) hotfixes_orig = copy.deepcopy(hotfixes) # Load definitions from definitions.zip (default) or user-provided location print('[+] Loading definitions') try: cves, date = load_definitions(args.definitions) print(' - Creation date of definitions: %s' % date) print('[+] Determining missing patches') filtered, found = determine_missing_patches(productfilter, cves, hotfixes) except WesException as e: print('[-] ' + str(e)) exit(1) # If -d parameter is specified, use the most recent patch installed as # reference point for the system's patching status if args.usekbdate: print('[+] Filtering old vulnerabilities') recentkb = get_most_recent_kb(found) if recentkb: print(' - Most recent KB installed is KB%s released at %s\n' ' - Filtering all KBs released before this date' % (recentkb['BulletinKB'], recentkb['DatePosted'])) recentdate = int(recentkb['DatePosted']) found = list( filter(lambda kb: int(kb['DatePosted']) >= recentdate, found)) if 'Windows Server' in productfilter: print('[+] Filtering duplicate vulnerabilities') found = filter_duplicates(found) # If specified, hide results containing the user-specified string # in the AffectedComponent and AffectedProduct attributes if args.hiddenvuln or args.only_exploits or args.impacts or args.severities: print('[+] Applying display filters') filtered = apply_display_filters(found, args.hiddenvuln, args.only_exploits, args.impacts, args.severities) else: filtered = found # If specified, lookup superseeding KBs in the Microsoft Update Catalog # and remove CVEs if a superseeding KB is installed. if args.muc_lookup: from muc_lookup import apply_muc_filter # ony import if necessary since it needs MechanicalSoup print( "[+] Looking up superseeding hotfixes in the Microsoft Update Catalog" ) filtered = apply_muc_filter(filtered, hotfixes_orig) # Split up list of KBs and the potential Service Packs/Cumulative updates available kbs, sp = get_patches_servicepacks(filtered, cves, productfilter) # Display results if len(filtered) > 0: print('[+] Found vulnerabilities') verb = 'Displaying' if args.outputfile: store_results(args.outputfile, filtered) verb = 'Saved' print_summary(kbs, sp) else: print_results(filtered) print_summary(kbs, sp) print() print('[+] Done. %s %d of the %d vulnerabilities found.' % (verb, len(filtered), len(found))) else: print('[-] No vulnerabilities found\n')
def main(): args = parse_arguments() # Configure output coloring if hasattr(args, 'showcolor') and args.showcolor: configure_color() # Application banner print(BANNER % (colored(TITLE, 'green'), colored( '%.2f' % VERSION, 'yellow'), colored(WEB_URL, 'blue'))) # Update definitions if hasattr(args, 'perform_update') and args.perform_update: print(colored('[+] Updating definitions', 'green')) urlretrieve( 'https://raw.githubusercontent.com/bitsadmin/wesng/master/definitions.zip', 'definitions.zip') cves, date = load_definitions('definitions.zip') print( colored('[+] Obtained definitions created at ', 'green') + '%s' % colored(date, 'yellow')) return # Update application if hasattr(args, 'perform_wesupdate') and args.perform_wesupdate: print(colored('[+] Updating wes.py', 'green')) urlretrieve( 'https://raw.githubusercontent.com/bitsadmin/wesng/master/wes.py', 'wes.py') print( colored( '[+] Updated to the latest version. Relaunch wes.py to use.', 'green')) return # Show tree of supersedes (for debugging purposes) if hasattr(args, 'debugsupersedes') and args.debugsupersedes: cves, date = load_definitions('definitions.zip') productfilter = args.debugsupersedes[0] supersedes = args.debugsupersedes[1:] filtered = [] for cve in cves: if productfilter not in cve['AffectedProduct']: continue filtered.append(cve) debug_supersedes(filtered, supersedes, 0, args.verbosesupersedes) return # Show version if hasattr(args, 'showversion') and args.showversion: cves, date = load_definitions('definitions.zip') print('Wes.py version: %.2f' % VERSION) print('Database version: %s' % date) return # Using the list of missing patches as a base if hasattr(args, 'missingpatches') and args.missingpatches: print(colored('[+] Loading definitions', 'green')) cves, date = load_definitions('definitions.zip') # Obtain IDs of missing patches from file print(colored('[+] Loading missing patches from file', 'green')) missingpatches = [] with open(args.missingpatches, 'r') as f: missingpatches = f.read() missingpatches = list( filter(None, [ mp.upper().replace('KB', '') for mp in missingpatches.splitlines() ])) # Obtain all records matching the IDs of the missing patches found = list(filter(lambda c: c['BulletinKB'] in missingpatches, cves)) os_names, os_name = get_operatingsystems(found, args.operating_system) # Perform filter on operating system if os_name: print( colored('[+] Filtering vulnerabilities for "%s"' % os_name, 'green')) found = list( filter(lambda c: os_name in c['AffectedProduct'], found)) # Deduplicate results ignoring differences in the Supersedes attribute for f in found: f['Supersedes'] = '' found = [ dict(t) for t in {tuple([t for t in d.items()]) for d in found} ] # Append missing patches from missing.txt which are not included in the definitions.zip foundkbs = set([kb['BulletinKB'] for kb in found]) difference = foundkbs.symmetric_difference(missingpatches) for diff in difference: found.append({ 'DatePosted': '', 'CVE': '', 'BulletinKB': diff, 'Title': '', 'AffectedProduct': '', 'AffectedComponent': '', 'Severity': '', 'Impact': '', 'Supersedes': '', 'Exploits': '' }) if os_name and 'Windows Server' in os_name: print(colored('[+] Filtering duplicate vulnerabilities', 'green')) found = filter_duplicates(found) # Prepare variables for summary sp = None kbs = found # Using systeminfo.txt or qfe.txt with list of installed patches as a base else: missingpatches = None cves = None os_names = None # Use input from qfe if hasattr(args, 'qfefile') and args.qfefile: # If an operating_system digit is provided or no OS has been provided, load defitions to # respectively retrieve the OS or show the list of OSs if (hasattr(args, 'operating_system') and args.operating_system and args.operating_system.isdigit()) or \ (not hasattr(args, 'operating_system') or not args.operating_system): # Load definitions to compile list of OSs print(colored('[+] Loading definitions', 'green')) cves, date = load_definitions(args.definitions) print(' - Creation date of definitions: %s' % date) # Propose/select OS name os_names, os_name = get_operatingsystems(cves, args.operating_system) if not args.operating_system: # Print possible operating systems list_operatingsystems(os_names) # Quit script print( colored( '[I] Rerun the script providing the --os parameter and the index or name of the OS you want to filter on.', 'yellow')) exit(0) else: productfilter = os_name # Read KBs from QFE file print( colored('[+] Parsing quick fix engineering (qfe) output', 'green')) with open(args.qfefile, 'rb') as f: qfe_data = f.read() qfe_data = charset_convert(qfe_data) hotfixes = get_hotfixes(qfe_data) # Parse encoding of systeminfo.txt input else: print(colored('[+] Parsing systeminfo output', 'green')) systeminfo_data = open(args.systeminfo, 'rb').read() try: productfilter, win, mybuild, version, arch, hotfixes = determine_product( systeminfo_data) except WesException as e: print(colored('[-] ' + str(e), 'red')) exit(1) # Add explicitly specified patches manual_hotfixes = list( set([ patch.upper().replace('KB', '') for patch in args.installedpatch ])) # Display summary # OS info info = colored('[+] Operating System', 'green') if hasattr(args, 'systeminfo') and args.systeminfo: info += ('\n' ' - Name: %s\n' ' - Generation: %s\n' ' - Build: %s\n' ' - Version: %s\n' ' - Architecture: %s') % (productfilter, win, mybuild, version, arch) elif os_name: info += '\n - Selected Operating System: %s' % os_name # Hotfixes if hotfixes: info += '\n - Installed hotfixes (%d): %s' % ( len(hotfixes), ', '.join(['KB%s' % kb for kb in hotfixes])) else: info += '\n - Installed hotfixes: None' if manual_hotfixes: info += '\n - Manually specified hotfixes (%d): %s' % ( len(manual_hotfixes), ', '.join( ['KB%s' % kb for kb in manual_hotfixes])) print(info) # Append manually specified KBs to list of hotfixes hotfixes = list(set(hotfixes + manual_hotfixes)) hotfixes_orig = copy.deepcopy(hotfixes) # Load definitions from definitions.zip (default) or user-provided location # Only in case they haven't been loaded yet when the --qfe parameter has been provided if not cves: print(colored('[+] Loading definitions', 'green')) cves, date = load_definitions(args.definitions) print(' - Creation date of definitions: %s' % date) # Determine missing patches try: print(colored('[+] Determining missing patches', 'green')) filtered, found = determine_missing_patches( productfilter, cves, hotfixes) except WesException as e: print(colored('[-] ' + str(e), 'red')) exit(1) # If -d parameter is specified, use the most recent patch installed as # reference point for the system's patching status if args.usekbdate: print(colored('[+] Filtering old vulnerabilities', 'green')) recentkb = get_most_recent_kb(found) if recentkb: print(' - Most recent KB installed is KB%s released at %s\n' ' - Filtering all KBs released before this date' % (recentkb['BulletinKB'], recentkb['DatePosted'])) recentdate = int(recentkb['DatePosted']) found = list( filter(lambda kb: int(kb['DatePosted']) >= recentdate, found)) if 'Windows Server' in productfilter: print(colored('[+] Filtering duplicate vulnerabilities', 'green')) found = filter_duplicates(found) # If specified, hide results containing the user-specified string # in the AffectedComponent and AffectedProduct attributes if args.hiddenvuln or args.only_exploits or args.impacts or args.severities: print(colored('[+] Applying display filters', 'green')) filtered = apply_display_filters(found, args.hiddenvuln, args.only_exploits, args.impacts, args.severities) else: filtered = found # In case the list of missing patches is specified, # we don't need to search for supersedes in the MS Update Catalog if not args.missingpatches: # If specified, lookup superseded KBs in the Microsoft Update Catalog # and remove CVEs if a superseded KB is installed. if args.muc_lookup: from muc_lookup import apply_muc_filter # ony import if necessary since it needs MechanicalSoup print( colored( '[!] Looking up superseded hotfixes in the Microsoft Update Catalog', 'yellow')) filtered = apply_muc_filter(filtered, hotfixes_orig) # Split up list of KBs and the potential Service Packs/Cumulative updates available kbs, sp = get_patches_servicepacks(filtered, cves, productfilter) # Display results if len(filtered) > 0: print(colored('[!] Found vulnerabilities!', 'yellow')) if args.outputfile: store_results(args.outputfile, filtered) verb = 'Saved' print_summary(kbs, sp) else: print_results(filtered) verb = 'Displaying' print_summary(kbs, sp) if not args.operating_system and os_names and len(os_names) > 1: # Print possible operating systems list_operatingsystems(os_names) print( colored( '[I] Additional filter can be applied using the --os parameter', 'yellow')) print( colored('[+] Done. ', 'green') + '%s %s of the %s vulnerabilities found.' % (verb, colored(len(filtered), 'yellow'), colored(len(found), 'yellow'))) else: print(colored('[-] Done. No vulnerabilities found\n', 'green'))