コード例 #1
0
        def get_resources(pe):
            resources = []
            if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
                count = 1
                for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
                    try:
                        resource = {}

                        if resource_type.name is not None:
                            name = str(resource_type.name)
                        else:
                            name = str(pefile.RESOURCE_TYPE.get(resource_type.struct.Id))

                        if name is None:
                            name = str(resource_type.struct.Id)

                        if hasattr(resource_type, 'directory'):
                            for resource_id in resource_type.directory.entries:
                                if hasattr(resource_id, 'directory'):
                                    for resource_lang in resource_id.directory.entries:
                                        data = pe.get_data(resource_lang.data.struct.OffsetToData,
                                                           resource_lang.data.struct.Size)
                                        filetype = get_type(data)
                                        md5 = get_md5(data)
                                        language = pefile.LANG.get(resource_lang.data.lang, None)
                                        sublanguage = pefile.get_sublang_name_for_lang(
                                            resource_lang.data.lang, resource_lang.data.sublang)
                                        offset = ('%-8s' % hex(resource_lang.data.struct.OffsetToData)).strip()
                                        size = ('%-8s' % hex(resource_lang.data.struct.Size)).strip()

                                        resource = [count, name, offset, md5, size, filetype, language, sublanguage]

                                        # Dump resources if requested to and if the file currently being
                                        # processed is the opened session file.
                                        # This is to avoid that during a --scan all the resources being
                                        # scanned are dumped as well.
                                        if (self.args.open or self.args.dump) and pe == self.pe:
                                            if self.args.dump:
                                                folder = self.args.dump
                                            else:
                                                folder = tempfile.mkdtemp()

                                            resource_path = os.path.join(
                                                folder, '{0}_{1}_{2}'.format(__sessions__.current.file.md5, offset,
                                                                             name))
                                            resource.append(resource_path)

                                            with open(resource_path, 'wb') as resource_handle:
                                                resource_handle.write(data)

                                        resources.append(resource)

                                        count += 1
                    except Exception as e:
                        self.log('error', e)
                        continue

            return resources
コード例 #2
0
ファイル: pe.py プロジェクト: asymptotic/viper
        def get_signed_samples(current=None, cert_filter=None):
            db = Database()
            samples = db.find(key='all')

            results = []
            for sample in samples:
                # Skip if it's the same file.
                if current:
                    if sample.sha256 == current:
                        continue

                # Obtain path to the binary.
                sample_path = get_sample_path(sample.sha256)
                if not os.path.exists(sample_path):
                    continue

                # Open PE instance.
                try:
                    cur_pe = pefile.PE(sample_path)
                except:
                    continue

                cur_cert_data = get_certificate(cur_pe)

                if not cur_cert_data:
                    continue

                cur_cert_md5 = get_md5(cur_cert_data)

                if cert_filter:
                    if cur_cert_md5 == cert_filter:
                        results.append([sample.name, sample.md5])
                else:
                    results.append([sample.name, sample.md5, cur_cert_md5])

            return results
コード例 #3
0
        def get_signed_samples(current=None, cert_filter=None):
            db = Database()
            samples = db.find(key='all')

            results = []
            for sample in samples:
                # Skip if it's the same file.
                if current:
                    if sample.sha256 == current:
                        continue

                # Obtain path to the binary.
                sample_path = get_sample_path(sample.sha256)
                if not os.path.exists(sample_path):
                    continue

                # Open PE instance.
                try:
                    cur_pe = pefile.PE(sample_path)
                except:
                    continue

                cur_cert_data = get_certificate(cur_pe)

                if not cur_cert_data:
                    continue

                cur_cert_md5 = get_md5(cur_cert_data)

                if cert_filter:
                    if cur_cert_md5 == cert_filter:
                        results.append([sample.name, sample.md5])
                else:
                    results.append([sample.name, sample.md5, cur_cert_md5])

            return results
コード例 #4
0
ファイル: swf.py プロジェクト: uk-gov-mirror/ukncsc.viper
    def decompress(self, dump_dir):

        # Check if the file type is right.
        # TODO: this might be a bit hacky, need to verify whether malformed
        # Flash exploit would get a different file type.
        if 'Flash' not in __sessions__.current.file.type:
            self.log(
                'error',
                "The opened file doesn't appear to be a valid SWF object")
            return

        # Retrieve key information from the opened SWF file.
        header, version, size, data = self.parse_swf()
        # Decompressed data.
        decompressed = None

        # Check if the file is already a decompressed Flash object.
        if header == 'FWS':
            self.log('info', "The opened file doesn't appear to be compressed")
            return
        # Check if the file is compressed with zlib.
        elif header == 'CWS':
            self.log('info',
                     "The opened file appears to be compressed with Zlib")

            # Open an handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + zlib.decompress(
                compressed.read())
        # Check if the file is compressed with lzma.
        elif header == 'ZWS':
            self.log('info',
                     "The opened file appears to be compressed with Lzma")

            # We need an third party library to decompress this.
            if not HAVE_PYLZMA:
                self.log(
                    'error',
                    "Missing dependency, please install pylzma (`pip install pylzma`)"
                )
                return

            # Open and handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress with pylzma and reconstruct the Flash object.
            ## ZWS(LZMA)
            ## | 4 bytes       | 4 bytes    | 4 bytes       | 5 bytes    | n bytes    | 6 bytes         |
            ## | 'ZWS'+version | scriptLen  | compressedLen | LZMA props | LZMA data  | LZMA end marker |
            decompressed = 'FWS' + compressed.read(5)
            compressed.read(4)  # skip compressedLen
            decompressed += pylzma.decompress(compressed.read())

        # If we obtained some decompressed data, we print it and eventually
        # dump it to file.
        if decompressed:
            # Print the decompressed data
            # TODO: this prints too much, need to find a better wayto display
            # this. Paginate?
            self.log('', cyan(hexdump(decompressed)))

            if dump_dir:
                # Dump the decompressed SWF file to the specified directory
                # or to the default temporary one.
                dump_path = os.path.join(
                    dump_dir, '{0}.swf'.format(get_md5(decompressed)))
                with open(dump_path, 'wb') as handle:
                    handle.write(decompressed)

                self.log('info',
                         "Flash object dumped at {0}".format(dump_path))

                # Directly open a session on the dumped Flash object.
                __sessions__.new(dump_path)
コード例 #5
0
ファイル: pe.py プロジェクト: asymptotic/viper
    def security(self):

        def get_certificate(pe):
            # TODO: this only extract the raw list of certificate data.
            # I need to parse them, extract single certificates and perhaps return
            # the PEM data of the first certificate only.
            pe_security_dir = pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_SECURITY']
            address = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pe_security_dir].VirtualAddress
            #  size = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pe_security_dir].Size

            if address:
                return pe.write()[address + 8:]
            else:
                return None

        def get_signed_samples(current=None, cert_filter=None):
            db = Database()
            samples = db.find(key='all')

            results = []
            for sample in samples:
                # Skip if it's the same file.
                if current:
                    if sample.sha256 == current:
                        continue

                # Obtain path to the binary.
                sample_path = get_sample_path(sample.sha256)
                if not os.path.exists(sample_path):
                    continue

                # Open PE instance.
                try:
                    cur_pe = pefile.PE(sample_path)
                except:
                    continue

                cur_cert_data = get_certificate(cur_pe)

                if not cur_cert_data:
                    continue

                cur_cert_md5 = get_md5(cur_cert_data)

                if cert_filter:
                    if cur_cert_md5 == cert_filter:
                        results.append([sample.name, sample.md5])
                else:
                    results.append([sample.name, sample.md5, cur_cert_md5])

            return results

        if self.args.all:
            self.log('info', "Scanning the repository for all signed samples...")

            all_of_them = get_signed_samples()

            self.log('info', "{0} signed samples found".format(bold(len(all_of_them))))

            if len(all_of_them) > 0:
                self.log('table', dict(header=['Name', 'MD5', 'Cert MD5'], rows=all_of_them))

            return

        if not self.__check_session():
            return

        cert_data = get_certificate(self.pe)

        if not cert_data:
            self.log('warning', "No certificate found")
            return

        cert_md5 = get_md5(cert_data)

        self.log('info', "Found certificate with MD5 {0}".format(bold(cert_md5)))

        if self.args.dump:
            cert_path = os.path.join(self.args.dump, '{0}.crt'.format(__sessions__.current.file.sha256))
            with open(cert_path, 'wb+') as cert_handle:
                cert_handle.write(cert_data)

            self.log('info', "Dumped certificate to {0}".format(cert_path))
            self.log('info', "You can parse it using the following command:\n\t" +
                     bold("openssl pkcs7 -inform DER -print_certs -text -in {0}".format(cert_path)))

        # TODO: do scan for certificate's serial number.
        if self.args.scan:
            self.log('info', "Scanning the repository for matching signed samples...")

            matches = get_signed_samples(current=__sessions__.current.file.sha256, cert_filter=cert_md5)

            self.log('info', "{0} relevant matches found".format(bold(len(matches))))

            if len(matches) > 0:
                self.log('table', dict(header=['Name', 'SHA256'], rows=matches))

        # TODO: this function needs to be better integrated with the rest of the command.
        # TODO: need to add more error handling and figure out why so many samples are failing.
        if self.args.check:
            if not HAVE_VERIFYSIGS:
                self.log('error', "Dependencies missing for authenticode validation. Please install M2Crypto and pyasn1 (`pip install pyasn1 M2Crypto`)")
                return

            try:
                auth, computed_content_hash = get_auth_data(__sessions__.current.file.path)
            except Exception as e:
                self.log('error', "Unable to parse PE certificate: {0}".format(str(e)))
                return

            try:
                auth.ValidateAsn1()
                auth.ValidateHashes(computed_content_hash)
                auth.ValidateSignatures()
                auth.ValidateCertChains(time.gmtime())
            except Exception, e:
                self.log('error', "Unable to validate PE certificate: {0}".format(str(e)))
                return

            self.log('info', bold('Signature metadata:'))
            self.log('info', 'Program name: {0}'.format(auth.program_name))
            self.log('info', 'URL: {0}'.format(auth.program_url))

            if auth.has_countersignature:
                self.log('info', bold('Countersignature is present. Timestamp: {0} UTC'.format(
                        time.asctime(time.gmtime(auth.counter_timestamp)))))
            else:
                self.log('info', bold('Countersignature is not present.'))

            self.log('info', bold('Binary is signed with cert issued by:'))
            self.log('info', '{0}'.format(auth.signing_cert_id[0]))

            self.log('info', '{0}'.format(auth.cert_chain_head[2][0]))
            self.log('info', 'Chain not before: {0} UTC'.format(
                    time.asctime(time.gmtime(auth.cert_chain_head[0]))))
            self.log('info', 'Chain not after: {0} UTC'.format(
                    time.asctime(time.gmtime(auth.cert_chain_head[1]))))

            if auth.has_countersignature:
                self.log('info', bold('Countersig chain head issued by:'))
                self.log('info', '{0}'.format(auth.counter_chain_head[2]))
                self.log('info', 'Countersig not before: {0} UTC'.format(
                        time.asctime(time.gmtime(auth.counter_chain_head[0]))))
                self.log('info', 'Countersig not after: {0} UTC'.format(
                        time.asctime(time.gmtime(auth.counter_chain_head[1]))))

            self.log('info', bold('Certificates:'))
            for (issuer, serial), cert in auth.certificates.items():
                self.log('info', 'Issuer: {0}'.format(issuer))
                self.log('info', 'Serial: {0}'.format(serial))
                subject = cert[0][0]['subject']
                subject_dn = str(dn.DistinguishedName.TraverseRdn(subject[0]))
                self.log('info', 'Subject: {0}'.format(subject_dn))
                not_before = cert[0][0]['validity']['notBefore']
                not_after = cert[0][0]['validity']['notAfter']
                not_before_time = not_before.ToPythonEpochTime()
                not_after_time = not_after.ToPythonEpochTime()
                self.log('info', 'Not Before: {0} UTC ({1})'.format(
                        time.asctime(time.gmtime(not_before_time)), not_before[0]))
                self.log('info', 'Not After: {0} UTC ({1})'.format(
                        time.asctime(time.gmtime(not_after_time)), not_after[0]))

            if auth.trailing_data:
                self.log('info', 'Signature Blob had trailing (unvalidated) data ({0} bytes): {1}'.format(
                        len(auth.trailing_data), auth.trailing_data.encode('hex')))
コード例 #6
0
ファイル: pe.py プロジェクト: Sigterm-no/viper
    def security(self):

        def usage():
            print("usage: pe security [-d=folder] [-s]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print("\t--dump (-d)\tDestination directory to store digital signature in")
            print("\t--scan (-s)\tScan the repository for common certificates")
            print("")

        def get_certificate(pe):
            # TODO: this only extract the raw list of certificate data.
            # I need to parse them, extract single certificates and perhaps return
            # the PEM data of the first certificate only.
            pe_security_dir = pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_SECURITY']
            address = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pe_security_dir].VirtualAddress
            size = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pe_security_dir].Size

            if address:
                return pe.write()[address+8:]
            else:
                return None

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hd:s', ['help', 'dump=', 'scan'])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_folder = None
        arg_scan = False

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-d', '--dump'):
                arg_folder = value
            elif opt in ('-s', '--scan'):
                arg_scan = True

        if not self.__check_session():
            return

        cert_data = get_certificate(self.pe)

        if not cert_data:
            print_warning("No certificate found")
            return

        cert_md5 = get_md5(cert_data)

        print_info("Found certificate with MD5 {0}".format(bold(cert_md5)))

        if arg_folder:
            cert_path = os.path.join(arg_folder, '{0}.crt'.format(__sessions__.current.file.sha256))
            with open(cert_path, 'wb+') as cert_handle:
                cert_handle.write(cert_data)

            print_info("Dumped certificate to {0}".format(cert_path))
            print_info("You can parse it using the following command:\n\t" + 
                       bold("openssl pkcs7 -inform DER -print_certs -text -in {0}".format(cert_path)))

        # TODO: do scan for certificate's serial number.
        if arg_scan:
            print_info("Scanning the repository for matching samples...")

            db = Database()
            samples = db.find(key='all')

            matches = []
            for sample in samples:
                # Skip if it's the same file.
                if sample.sha256 == __sessions__.current.file.sha256:
                    continue

                # Obtain path to the binary.
                sample_path = get_sample_path(sample.sha256)
                if not os.path.exists(sample_path):
                    continue

                # Open PE instance.
                try:
                    cur_pe = pefile.PE(sample_path)
                except:
                    continue

                cur_cert_data = get_certificate(cur_pe)

                if not cur_cert_data:
                    continue

                cur_cert_md5 = get_md5(cur_cert_data)
                if cur_cert_md5 == cert_md5:
                    matches.append([sample.name, sample.sha256])

            print_info("{0} relevant matches found".format(bold(len(matches))))

            if len(matches) > 0:
                print(table(header=['Name', 'SHA256'], rows=matches))                
コード例 #7
0
    def security(self):
        def get_certificate(pe):
            # TODO: this only extract the raw list of certificate data.
            # I need to parse them, extract single certificates and perhaps return
            # the PEM data of the first certificate only.
            pe_security_dir = pefile.DIRECTORY_ENTRY[
                'IMAGE_DIRECTORY_ENTRY_SECURITY']
            address = pe.OPTIONAL_HEADER.DATA_DIRECTORY[
                pe_security_dir].VirtualAddress
            #  size = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pe_security_dir].Size

            if address:
                return pe.write()[address + 8:]
            else:
                return None

        def get_signed_samples(current=None, cert_filter=None):
            db = Database()
            samples = db.find(key='all')

            results = []
            for sample in samples:
                # Skip if it's the same file.
                if current:
                    if sample.sha256 == current:
                        continue

                # Obtain path to the binary.
                sample_path = get_sample_path(sample.sha256)
                if not os.path.exists(sample_path):
                    continue

                # Open PE instance.
                try:
                    cur_pe = pefile.PE(sample_path)
                except:
                    continue

                cur_cert_data = get_certificate(cur_pe)

                if not cur_cert_data:
                    continue

                cur_cert_md5 = get_md5(cur_cert_data)

                if cert_filter:
                    if cur_cert_md5 == cert_filter:
                        results.append([sample.name, sample.md5])
                else:
                    results.append([sample.name, sample.md5, cur_cert_md5])

            return results

        if self.args.all:
            self.log('info',
                     "Scanning the repository for all signed samples...")

            all_of_them = get_signed_samples()

            self.log('info',
                     "{0} signed samples found".format(bold(len(all_of_them))))

            if len(all_of_them) > 0:
                self.log(
                    'table',
                    dict(header=['Name', 'MD5', 'Cert MD5'], rows=all_of_them))

            return

        if not self.__check_session():
            return

        cert_data = get_certificate(self.pe)

        if not cert_data:
            self.log('warning', "No certificate found")
            return

        cert_md5 = get_md5(cert_data)

        self.log('info',
                 "Found certificate with MD5 {0}".format(bold(cert_md5)))

        if self.args.dump:
            cert_path = os.path.join(
                self.args.dump,
                '{0}.crt'.format(__sessions__.current.file.sha256))
            with open(cert_path, 'wb+') as cert_handle:
                cert_handle.write(cert_data)

            self.log('info', "Dumped certificate to {0}".format(cert_path))
            self.log(
                'info', "You can parse it using the following command:\n\t" +
                bold("openssl pkcs7 -inform DER -print_certs -text -in {0}".
                     format(cert_path)))

        # TODO: do scan for certificate's serial number.
        if self.args.scan:
            self.log('info',
                     "Scanning the repository for matching signed samples...")

            matches = get_signed_samples(
                current=__sessions__.current.file.sha256, cert_filter=cert_md5)

            self.log('info',
                     "{0} relevant matches found".format(bold(len(matches))))

            if len(matches) > 0:
                self.log('table', dict(header=['Name', 'SHA256'],
                                       rows=matches))

        # TODO: this function needs to be better integrated with the rest of the command.
        # TODO: need to add more error handling and figure out why so many samples are failing.
        if self.args.check:
            if not HAVE_VERIFYSIGS:
                self.log(
                    'error',
                    "Dependencies missing for authenticode validation. Please install M2Crypto and pyasn1 (`pip install pyasn1 M2Crypto`)"
                )
                return

            try:
                auth, computed_content_hash = get_auth_data(
                    __sessions__.current.file.path)
            except Exception as e:
                self.log('error',
                         "Unable to parse PE certificate: {0}".format(str(e)))
                return

            try:
                auth.ValidateAsn1()
                auth.ValidateHashes(computed_content_hash)
                auth.ValidateSignatures()
                auth.ValidateCertChains(time.gmtime())
            except Exception as e:
                self.log(
                    'error',
                    "Unable to validate PE certificate: {0}".format(str(e)))
                return

            self.log('info', bold('Signature metadata:'))
            self.log('info', 'Program name: {0}'.format(auth.program_name))
            self.log('info', 'URL: {0}'.format(auth.program_url))

            if auth.has_countersignature:
                self.log(
                    'info',
                    bold('Countersignature is present. Timestamp: {0} UTC'.
                         format(
                             time.asctime(time.gmtime(
                                 auth.counter_timestamp)))))
            else:
                self.log('info', bold('Countersignature is not present.'))

            self.log('info', bold('Binary is signed with cert issued by:'))
            self.log('info', '{0}'.format(auth.signing_cert_id[0]))

            self.log('info', '{0}'.format(auth.cert_chain_head[2][0]))
            self.log(
                'info', 'Chain not before: {0} UTC'.format(
                    time.asctime(time.gmtime(auth.cert_chain_head[0]))))
            self.log(
                'info', 'Chain not after: {0} UTC'.format(
                    time.asctime(time.gmtime(auth.cert_chain_head[1]))))

            if auth.has_countersignature:
                self.log('info', bold('Countersig chain head issued by:'))
                self.log('info', '{0}'.format(auth.counter_chain_head[2]))
                self.log(
                    'info', 'Countersig not before: {0} UTC'.format(
                        time.asctime(time.gmtime(auth.counter_chain_head[0]))))
                self.log(
                    'info', 'Countersig not after: {0} UTC'.format(
                        time.asctime(time.gmtime(auth.counter_chain_head[1]))))

            self.log('info', bold('Certificates:'))
            for (issuer, serial), cert in auth.certificates.items():
                self.log('info', 'Issuer: {0}'.format(issuer))
                self.log('info', 'Serial: {0}'.format(serial))
                subject = cert[0][0]['subject']
                subject_dn = str(dn.DistinguishedName.TraverseRdn(subject[0]))
                self.log('info', 'Subject: {0}'.format(subject_dn))
                not_before = cert[0][0]['validity']['notBefore']
                not_after = cert[0][0]['validity']['notAfter']
                not_before_time = not_before.ToPythonEpochTime()
                not_after_time = not_after.ToPythonEpochTime()
                self.log(
                    'info', 'Not Before: {0} UTC ({1})'.format(
                        time.asctime(time.gmtime(not_before_time)),
                        not_before[0]))
                self.log(
                    'info', 'Not After: {0} UTC ({1})'.format(
                        time.asctime(time.gmtime(not_after_time)),
                        not_after[0]))

            if auth.trailing_data:
                self.log(
                    'info',
                    'Signature Blob had trailing (unvalidated) data ({0} bytes): {1}'
                    .format(len(auth.trailing_data),
                            auth.trailing_data.encode('hex')))
コード例 #8
0
ファイル: swf.py プロジェクト: idiom/viper
    def decompress(self, dump_dir):

        # Check if the file type is right.
        # TODO: this might be a bit hacky, need to verify whether malformed
        # Flash exploit would get a different file type.
        if 'Flash' not in __sessions__.current.file.type:
            self.log('error', "The opened file doesn't appear to be a valid SWF object")
            return

        # Retrieve key information from the opened SWF file.
        header, version, size, data = self.parse_swf()
        # Decompressed data.
        decompressed = None

        # Check if the file is already a decompressed Flash object.
        if header == 'FWS':
            self.log('info', "The opened file doesn't appear to be compressed")
            return
        # Check if the file is compressed with zlib.
        elif header == 'CWS':
            self.log('info', "The opened file appears to be compressed with Zlib")

            # Open an handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + zlib.decompress(compressed.read())
        # Check if the file is compressed with lzma.
        elif header == 'ZWS':
            self.log('info', "The opened file appears to be compressed with Lzma")

            # We need an third party library to decompress this.
            if not HAVE_PYLZMA:
                self.log('error', "Missing dependency, please install pylzma (`pip install pylzma`)")
                return

            # Open and handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress with pylzma and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + pylzma.decompress(compressed.read())

        # If we obtained some decompressed data, we print it and eventually
        # dump it to file.
        if decompressed:
            # Print the decompressed data
            # TODO: this prints too much, need to find a better wayto display
            # this. Paginate?
            self.log('', cyan(hexdump(decompressed)))

            if dump_dir:
                # Dump the decompressed SWF file to the specified directory
                # or to the default temporary one.
                dump_path = os.path.join(dump_dir, '{0}.swf'.format(get_md5(decompressed)))
                with open(dump_path, 'wb') as handle:
                    handle.write(decompressed)

                self.log('info', "Flash object dumped at {0}".format(dump_path))

                # Directly open a session on the dumped Flash object.
                __sessions__.new(dump_path)
コード例 #9
0
ファイル: pe.py プロジェクト: vicgc/viper
    def security(self):
        def usage():
            print("usage: pe security [-d=folder] [-s]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print(
                "\t--dump (-d)\tDestination directory to store digital signature in"
            )
            print("\t--all (-a)\tFind all samples with a digital signature")
            print("\t--scan (-s)\tScan the repository for common certificates")
            print("")

        def get_certificate(pe):
            # TODO: this only extract the raw list of certificate data.
            # I need to parse them, extract single certificates and perhaps return
            # the PEM data of the first certificate only.
            pe_security_dir = pefile.DIRECTORY_ENTRY[
                'IMAGE_DIRECTORY_ENTRY_SECURITY']
            address = pe.OPTIONAL_HEADER.DATA_DIRECTORY[
                pe_security_dir].VirtualAddress
            size = pe.OPTIONAL_HEADER.DATA_DIRECTORY[pe_security_dir].Size

            if address:
                return pe.write()[address + 8:]
            else:
                return None

        def get_signed_samples(current=None, cert_filter=None):
            db = Database()
            samples = db.find(key='all')

            results = []
            for sample in samples:
                # Skip if it's the same file.
                if current:
                    if sample.sha256 == current:
                        continue

                # Obtain path to the binary.
                sample_path = get_sample_path(sample.sha256)
                if not os.path.exists(sample_path):
                    continue

                # Open PE instance.
                try:
                    cur_pe = pefile.PE(sample_path)
                except:
                    continue

                cur_cert_data = get_certificate(cur_pe)

                if not cur_cert_data:
                    continue

                cur_cert_md5 = get_md5(cur_cert_data)

                if cert_filter:
                    if cur_cert_md5 == cert_filter:
                        results.append([sample.name, sample.md5])
                else:
                    results.append([sample.name, sample.md5, cur_cert_md5])

            return results

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hd:as',
                                       ['help', 'dump=', 'all', 'scan'])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_folder = None
        arg_all = False
        arg_scan = False

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-d', '--dump'):
                arg_folder = value
            elif opt in ('-a', '--all'):
                arg_all = True
            elif opt in ('-s', '--scan'):
                arg_scan = True

        if arg_all:
            print_info("Scanning the repository for all signed samples...")

            all_of_them = get_signed_samples()

            print_info("{0} signed samples found".format(bold(
                len(all_of_them))))

            if len(all_of_them) > 0:
                print(
                    table(header=['Name', 'MD5', 'Cert MD5'],
                          rows=all_of_them))

            return

        if not self.__check_session():
            return

        cert_data = get_certificate(self.pe)

        if not cert_data:
            print_warning("No certificate found")
            return

        cert_md5 = get_md5(cert_data)

        print_info("Found certificate with MD5 {0}".format(bold(cert_md5)))

        if arg_folder:
            cert_path = os.path.join(
                arg_folder, '{0}.crt'.format(__sessions__.current.file.sha256))
            with open(cert_path, 'wb+') as cert_handle:
                cert_handle.write(cert_data)

            print_info("Dumped certificate to {0}".format(cert_path))
            print_info(
                "You can parse it using the following command:\n\t" +
                bold("openssl pkcs7 -inform DER -print_certs -text -in {0}".
                     format(cert_path)))

        # TODO: do scan for certificate's serial number.
        if arg_scan:
            print_info(
                "Scanning the repository for matching signed samples...")

            matches = get_signed_samples(
                current=__sessions__.current.file.sha256, cert_filter=cert_md5)

            print_info("{0} relevant matches found".format(bold(len(matches))))

            if len(matches) > 0:
                print(table(header=['Name', 'SHA256'], rows=matches))
コード例 #10
0
ファイル: swf.py プロジェクト: AresTao/viper
    def decompress(self):
        def usage():
            print("usage: swf decompress [-d=folder]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print("\t--dump (-d)\tDump the SWF object to the destination folder (default is /tmp)")
            print("")

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hd', ['help', 'dump'])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_dump = None

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-d', '--dump'):
                if value:
                    arg_dump = value
                else:
                    arg_dump = tempfile.gettempdir()

        if not __sessions__.is_set():
            print_error("No session opened")
            return

        # Check if the file type is right.
        # TODO: this might be a bit hacky, need to verify whether malformed
        # Flash exploit would get a different file type.
        if not 'Flash' in __sessions__.current.file.type:
            print_error("The opened file doesn't appear to be a valid SWF object")
            return

        # Retrieve key information from the opened SWF file.
        header, version, size, data = self.parse_swf()
        # Decompressed data.
        decompressed = None

        # Check if the file is already a decompressed Flash object.
        if header == 'FWS':
            print_info("The opened file doesn't appear to be compressed")
            return
        # Check if the file is compressed with zlib.
        elif header == 'CWS':
            print_info("The opened file appears to be compressed with Zlib")

            # Open an handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + zlib.decompress(compressed.read())
        # Check if the file is compressed with lzma.
        elif header == 'ZWS':
            print_info("The opened file appears to be compressed with Lzma")

            # We need an third party library to decompress this.
            if not HAVE_PYLZMA:
                print_error("Missing dependency, please install pylzma (`pip install pylzma`)")
                return

            # Open and handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress with pylzma and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + pylzma.decompress(compressed.read())

        # If we obtained some decompressed data, we print it and eventually
        # dump it to file.
        if decompressed:
            # Print the decompressed data
            # TODO: this prints too much, need to find a better wayto display
            # this. Paginate?
            print(cyan(hexdump(decompressed)))

            if arg_dump:
                # Dump the decompressed SWF file to the specified directory
                # or to the default temporary one.
                dump_path = os.path.join(arg_dump, '{0}.swf'.format(get_md5(decompressed)))
                with open(dump_path, 'wb') as handle:
                    handle.write(decompressed)

                print_info("Flash object dumped at {0}".format(dump_path))

                # Directly open a session on the dumped Flash object.
                __sessions__.new(dump_path)
コード例 #11
0
ファイル: swf.py プロジェクト: vicgc/viper
    def decompress(self):
        def usage():
            print("usage: swf decompress [-d=folder]")

        def help():
            usage()
            print("")
            print("Options:")
            print("\t--help (-h)\tShow this help message")
            print(
                "\t--dump (-d)\tDump the SWF object to the destination folder (default is /tmp)"
            )
            print("")

        try:
            opts, argv = getopt.getopt(self.args[1:], 'hd', ['help', 'dump'])
        except getopt.GetoptError as e:
            print(e)
            usage()
            return

        arg_dump = None

        for opt, value in opts:
            if opt in ('-h', '--help'):
                help()
                return
            elif opt in ('-d', '--dump'):
                if value:
                    arg_dump = value
                else:
                    arg_dump = tempfile.gettempdir()

        if not __sessions__.is_set():
            print_error("No session opened")
            return

        # Check if the file type is right.
        # TODO: this might be a bit hacky, need to verify whether malformed
        # Flash exploit would get a different file type.
        if not 'Flash' in __sessions__.current.file.type:
            print_error(
                "The opened file doesn't appear to be a valid SWF object")
            return

        # Retrieve key information from the opened SWF file.
        header, version, size, data = self.parse_swf()
        # Decompressed data.
        decompressed = None

        # Check if the file is already a decompressed Flash object.
        if header == 'FWS':
            print_info("The opened file doesn't appear to be compressed")
            return
        # Check if the file is compressed with zlib.
        elif header == 'CWS':
            print_info("The opened file appears to be compressed with Zlib")

            # Open an handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + zlib.decompress(
                compressed.read())
        # Check if the file is compressed with lzma.
        elif header == 'ZWS':
            print_info("The opened file appears to be compressed with Lzma")

            # We need an third party library to decompress this.
            if not HAVE_PYLZMA:
                print_error(
                    "Missing dependency, please install pylzma (`pip install pylzma`)"
                )
                return

            # Open and handle on the compressed data.
            compressed = StringIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress with pylzma and reconstruct the Flash object.
            decompressed = 'FWS' + compressed.read(5) + pylzma.decompress(
                compressed.read())

        # If we obtained some decompressed data, we print it and eventually
        # dump it to file.
        if decompressed:
            # Print the decompressed data
            # TODO: this prints too much, need to find a better wayto display
            # this. Paginate?
            print(cyan(hexdump(decompressed)))

            if arg_dump:
                # Dump the decompressed SWF file to the specified directory
                # or to the default temporary one.
                dump_path = os.path.join(
                    arg_dump, '{0}.swf'.format(get_md5(decompressed)))
                with open(dump_path, 'wb') as handle:
                    handle.write(decompressed)

                print_info("Flash object dumped at {0}".format(dump_path))

                # Directly open a session on the dumped Flash object.
                __sessions__.new(dump_path)
コード例 #12
0
ファイル: swf.py プロジェクト: Rafiot/viper
    def decompress(self, dump_dir):

        # Check if the file type is right.
        # TODO: this might be a bit hacky, need to verify whether malformed
        # Flash exploit would get a different file type.
        if 'Flash' not in __sessions__.current.file.type:
            self.log('error', "The opened file doesn't appear to be a valid SWF object")
            return

        # Retrieve key information from the opened SWF file.
        header, version, size, data = self.parse_swf()
        # Decompressed data.
        decompressed = None
        compressed = True

        # Check if the file is already a decompressed Flash object.
        if header == b'FWS':
            self.log('info', "The opened file doesn't appear to be compressed")
            decompressed = data
            compressed = False
        # Check if the file is compressed with zlib.
        elif header == b'CWS':
            self.log('info', "The opened file appears to be compressed with Zlib")

            # Open an handle on the compressed data.
            compressed = BytesIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress and reconstruct the Flash object.
            decompressed = b'FWS' + compressed.read(5) + zlib.decompress(compressed.read())
        # Check if the file is compressed with lzma.
        elif header == b'ZWS':
            self.log('info', "The opened file appears to be compressed with Lzma")

            # We need an third party library to decompress this.
            if not HAVE_PYLZMA:
                self.log('error', "Missing dependency, please install pylzma (`pip install pylzma`)")
                return

            # Open and handle on the compressed data.
            compressed = BytesIO(data)
            # Skip the header.
            compressed.read(3)
            # Decompress with pylzma and reconstruct the Flash object.
            # # ZWS(LZMA)
            # # | 4 bytes       | 4 bytes    | 4 bytes       | 5 bytes    | n bytes    | 6 bytes         |
            # # | 'ZWS'+version | scriptLen  | compressedLen | LZMA props | LZMA data  | LZMA end marker |
            decompressed = b'FWS' + compressed.read(5)
            compressed.read(4)  # skip compressedLen
            decompressed += pylzma.decompress(compressed.read())

        # If we obtained some decompressed data, we print it and eventually
        # dump it to file.
        if decompressed:
            # Print the decompressed data
            # TODO: this prints too much, need to find a better wayto display
            # this. Paginate?
            self.log('', cyan(hexdump(decompressed)))

            if compressed and dump_dir:
                # Dump the decompressed SWF file to the specified directory
                # or to the default temporary one.
                dump_path = os.path.join(dump_dir, '{0}.swf'.format(get_md5(decompressed)))
                with open(dump_path, 'wb') as handle:
                    handle.write(decompressed)

                self.log('info', "Flash object dumped at {0}".format(dump_path))

                # Set the parent-child relation between CWS-FWS
                this_parent = __sessions__.current.file.sha256
                # Directly open a session on the dumped Flash object.
                __sessions__.new(dump_path)

                db = Database()
                # Make sure parents is in database
                if not db.find(key='sha256', value=this_parent):
                    self.log('error', "the parent file is not found in the database. ")
                else:
                    db.add_parent(__sessions__.current.file.sha256, this_parent)