Ejemplo n.º 1
0
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')
Ejemplo n.º 2
0
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'))