def main(): print('pyEWFmount by Florian Wahl, 03.08.2020') print() parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, help="path to a EWF file which should be mounted") parser.add_argument( '-o', '--output', type=str, help= "Specify the name of the mounted directory (default: /mnt/YYYY.MM.DD_hh.mm)", default=__get_default_name_of_mounting_directory()) arguments = parser.parse_args() if arguments.input is None or len(arguments.input) == 0: parser.print_help() exit() input_path = os.path.abspath(arguments.input) mounting_path = os.path.abspath(arguments.output) if not __is_root(): error(message='The script needs sudo rights. Exiting.') exit() try: program(input_path=input_path, mounting_path=mounting_path) except KeyboardInterrupt: error(message='Keyboard Interrupt. Exiting.')
def extract_attachment(parsed_eml: Message, attachment_number: int, output_path: str or None): print_headline_banner('Attachment Extracting') attachment = None counter = 1 for child in parsed_eml.walk(): if child.get_filename() is not None: if counter == attachment_number: attachment = child break counter += 1 # Check if attachment was found if attachment is None: error('Attachment {} could not be found'.format(attachment_number)) return attachment_filename = _get_printable_attachment_filename( attachment=attachment) info('Found attachment [{}] "{}"'.format(attachment_number, attachment_filename)) if output_path is None: output_path = attachment.get_filename() elif os.path.isdir(output_path): output_path = os.path.join(output_path, attachment_filename) payload = attachment.get_payload(decode=True) output_file = open(output_path, mode='wb') output_file.write(payload) info('Attachment extracted to {}'.format(output_path))
def __try_to_decode(content: bytes, parsed_eml: Message) -> str or None: list_of_possible_encodings = __create_list_of_possible_encodings(parsed_eml=parsed_eml) for encoding_format in list_of_possible_encodings: try: return content.decode(encoding_format) except ValueError: continue error('Payload could not be decoded') return None
def start_scanning(self): try: device = parted.getDevice(self.path_to_input_device) except Exception as exception: error('Input Device could not be read: {}'.format(exception)) self.is_running = False exit() else: self.is_running = True t = Thread(target=self.__start_scanning, args=(device, ), daemon=True) t.start()
def __read_data(self, device): self.number_of_sectors = device.length self.size_of_a_sector = device.sectorSize info('Model of input device: {}'.format(device.model)) info('Number of sectors: {}'.format(self.number_of_sectors)) info('Bytes per sector: {}'.format(self.size_of_a_sector)) try: with open(self.path_to_input_device, mode='rb') as input_file: input_file.seek(0) for sector_i in range(self.number_of_sectors + 1): data_of_new_sector = input_file.read(self.size_of_a_sector) self.buffer.put(data_of_new_sector, block=True) except IsADirectoryError: error('The Input has to be a drive not an directory') self.is_running = False exit()
def main(): flags_to_parse, path_to_file = __parse_cli_arguments() argument_parser = argparse.ArgumentParser( usage='zipAnalyzer FILE [OPTIONS]', description='A cli script to analyze zip archive.') argument_parser.add_argument( '-c', '--crack', help= "Tries to crack the encryption by enumeration over a password list. Extracts the zip archive if the password was found.", action='store_true', default=False) argument_parser.add_argument('--passlist', type=str, help="Path to custom password list", default=None) parsed_arguments = argument_parser.parse_args(flags_to_parse) if path_to_file is None: argument_parser.print_help() exit() path_to_archive = os.path.abspath(path_to_file) try: zip_archive = zipfile.ZipFile(path_to_archive) except Exception as exception: error('Zip file could not be read: {}'.format(exception)) exit() else: if parsed_arguments.crack: password_list = __read_password_list( path_to_custom_password_list=parsed_arguments.passlist) crack_zip_archive(password_list=password_list, zip_archive=zip_archive) else: analyse_zip_archive(zip_archive=zip_archive)
def __final_mount_procedure(source_path: str, target_path: str, partition_number: int): if not os.path.exists(target_path): os.makedirs(target_path) mount_options = list() while True: user_input = input('Mount in readonly mode (y/n) [y]: ') if len(user_input) == 0 or user_input == 'y': mount_options.append('ro') break elif user_input == 'n': break else: error(message='input not valid.') print() mount_options.append('show_sys_files') while True: user_input = input('Mount as NTFS filesystem (y/n) [y]: ') if len(user_input) == 0 or user_input == 'y': mount_options.append('streams_interface=windows') break elif user_input == 'n': break else: error(message='input not valid.') print() # generate mount command mount_options_string = ','.join(mount_options) mount_command = 'mount -o {} "{}" "{}" >/dev/null 2>&1'.format( mount_options_string, __escape_path(source_path), __escape_path(target_path)) if int(os.system(mount_command)) == 0: info(message='Partition {} was mounted under "{}"'.format( partition_number, __escape_path(target_path))) else: error('An Error occurred. Partition could not be mounted')
def main(): argument_parser = argparse.ArgumentParser( usage='emlAnalyzer [OPTION]... -i FILE', description= 'A cli script to analyze an E-Mail in the eml format for viewing the header, extracting attachments etc.' ) argument_parser.add_argument('-i', '--input', help="path to the eml-file (is required)", type=str) argument_parser.add_argument('--header', action='store_true', default=False, help="Shows the headers") argument_parser.add_argument( '-x', '--tracking', action='store_true', default=False, help= "Shows content which is reloaded from external resources in the HTML part" ) argument_parser.add_argument('-a', '--attachments', action='store_true', default=False, help="Lists attachments") argument_parser.add_argument('--text', action='store_true', default=False, help="Shows plaintext") argument_parser.add_argument('--html', action='store_true', default=False, help="Shows HTML") argument_parser.add_argument('-s', '--structure', action='store_true', default=False, help="Shows structure of the E-Mail") argument_parser.add_argument( '-u', '--url', action='store_true', default=False, help="Shows embedded links and urls in the html part") argument_parser.add_argument('-ea', '--extract', type=int, default=None, help="Extracts the x-th attachment") argument_parser.add_argument('--extract-all', action='store_true', default=None, help="Extracts all attachments") argument_parser.add_argument( '-o', '--output', type=str, default=None, help= "Path for the extracted attachment (default is filename in working directory)" ) arguments = argument_parser.parse_args() if arguments.input is None or len(arguments.input) == 0: warning('No Input specified') argument_parser.print_help() exit() # get the absolute path to the input file path_to_input = os.path.abspath(arguments.input) # read the eml file try: with open(path_to_input, mode='r') as input_file: eml_content = input_file.read() except Exception as e: error('Error: {}'.format(e)) error('File could not be loaded') info('Existing') exit() # parse the eml file try: parsed_eml = message_from_string(eml_content) except Exception as e: error('Error: {}'.format(e)) error('File could not be parsed. Sure it is a eml-file?') info('Existing') exit() # use default functionality if no options are specified is_default_functionality = not (arguments.header or arguments.tracking or arguments.attachments or arguments.text or arguments.html or arguments.structure or arguments.url or arguments.extract is not None) if is_default_functionality: arguments.structure = True arguments.url = True arguments.tracking = True arguments.attachments = True if arguments.header: show_header(parsed_eml=parsed_eml) if arguments.structure: show_structure(parsed_eml=parsed_eml) if arguments.url: show_urls(parsed_eml=parsed_eml) if arguments.tracking: check_tracking(parsed_eml=parsed_eml) if arguments.attachments: show_attachments(parsed_eml=parsed_eml) if arguments.text: show_text(parsed_eml=parsed_eml) if arguments.html: show_html(parsed_eml=parsed_eml) if arguments.extract is not None: extract_attachment(parsed_eml=parsed_eml, attachment_number=arguments.extract, output_path=arguments.output) if arguments.extract_all is not None: extract_all_attachments(parsed_eml=parsed_eml, path=arguments.output)
def main(): flags_to_parse, path = __parse_cli_arguments() parser = argparse.ArgumentParser( usage='lad [OPTION]... [FILE]...', description= 'Lists information about the FILEs (the current directory by default) including Alternate Data Streams.', add_help=False) parser.add_argument('-h', '--human-readable', dest="human_readable", help="print sizes like 1K 234M 2G etc.", action='store_true', default=False) parser.add_argument('--help', dest='help', help="prints the help text", action='store_true', default=False) parser.add_argument('-R', '--recursive', dest="recursive", help="list subdirectories recursively", action='store_true', default=False) parser.add_argument('--full-time', dest="full_time", help="Shows the complete timestamp", action='store_true', default=False) parser.add_argument('-n', '--numeric-uid-gid', dest="numeric_uid_gid", help="list numeric user and group IDs", action='store_true', default=False) parser.add_argument( '-F', dest="filter_files_with_ads", help="Show only files which include Alternate Data Streams", action='store_true', default=False) parser.add_argument( '--no-warning', dest="no_warning", help="Suppress warnings (e.g. if the filesystem is not NTFS)", action='store_true', default=False) parsed_arguments = parser.parse_args(flags_to_parse) if parsed_arguments.help: parser.print_help() exit() base_path = os.path.abspath(path) if not os.path.exists(base_path): error('Path "{}" does not exist'.format(path)) exit() output = list() if os.path.isfile(path): # the path points to a file # check the filesystem and collect the alternate data streams if path_is_an_ntfs_filesystem(path=base_path): alternate_data_streams = get_alternate_data_streams_of_file( path_to_file=base_path) else: alternate_data_streams = list() if not parsed_arguments.no_warning: warning(WARNING_TEXT_WRONG_FILE_SYSTEM_PATH) output.extend( __generate_output_single_file( arguments=parsed_arguments, path_to_file=base_path, file_name=path, file_info=os.stat(base_path), alternate_data_streams=alternate_data_streams)) elif not parsed_arguments.recursive: # the path points to a directory (recursive flag is not set) if path_is_an_ntfs_filesystem(path=base_path): search_alternate_data_streams = True else: search_alternate_data_streams = False if not parsed_arguments.no_warning: warning(WARNING_TEXT_WRONG_FILE_SYSTEM_PATH) for x in os.scandir(base_path): file_name = x.path.replace(base_path, '') file_info = x.stat() if search_alternate_data_streams and x.is_file(): alternate_data_streams = get_alternate_data_streams_of_file( path_to_file=x.path) else: alternate_data_streams = list() generated_output = __generate_output_single_file( arguments=parsed_arguments, path_to_file=x.path, file_name=file_name, file_info=file_info, alternate_data_streams=alternate_data_streams) output.extend(generated_output) else: # the path points to a directory (recursive flag is set) # to faster the scan apply getfattr recursively on the directory and parse the complete output if not parsed_arguments.no_warning and not path_is_an_ntfs_filesystem( base_path): warning(WARNING_TEXT_WRONG_FILE_SYSTEM_BASE_PATH) alternate_data_streams_dict = get_alternate_data_streams_recursively( path_to_directory=base_path) def scan_directory(path_to_dir): for x in os.scandir(path_to_dir): file_name = x.path.replace(base_path, '') try: file_info = x.stat() except OSError: warning(message='File {} could not be analyzed'.format( file_name)) continue alternate_data_streams = alternate_data_streams_dict.get( x.path, list()) generated_output = __generate_output_single_file( arguments=parsed_arguments, path_to_file=x.path, file_name=file_name, file_info=file_info, alternate_data_streams=alternate_data_streams) output.extend(generated_output) if parsed_arguments.recursive and x.is_dir(): scan_directory(path_to_dir=x.path) scan_directory(path_to_dir=base_path) # Find maximum width of each column to print the table nicely max_width_for_each_column = defaultdict(int) for line in output: for i, cell in enumerate(line): max_width_for_each_column[i] = max(max_width_for_each_column[i], len(cell)) for line in output: for i, cell in enumerate(line): if i == len(line) - 1: print(cell.ljust(max_width_for_each_column[i]), end='\n') elif i == 3: # the file size has to be aligned to the right print(cell.rjust(max_width_for_each_column[i]), end=' ') else: print(cell.ljust(max_width_for_each_column[i]), end=' ')
def program(input_path: str, mounting_path: str): # create directory which contains all mounting endpoints if not os.path.exists(mounting_path): try: os.makedirs(mounting_path) except PermissionError: error('Permission denied for creating directory "{}"'.format( mounting_path)) exit() # mount the ewf file mounting_path_ewf_dir = os.path.join(mounting_path, '.ewf') if not os.path.exists(mounting_path_ewf_dir): try: os.makedirs(mounting_path_ewf_dir, exist_ok=True) except PermissionError: error('Permission denied for creating directory "{}"'.format( mounting_path_ewf_dir)) exit() if int( os.system('ewfmount "{}" "{}" >/dev/null 2>&1'.format( __escape_path(input_path), __escape_path(mounting_path_ewf_dir)))) != 0: error(message= 'An error occurred while mounting ewf file to "{}". Exiting.'. format(mounting_path_ewf_dir)) exit() else: info(message='ewf file mounted to "{}"'.format(mounting_path_ewf_dir)) # get the path to the ewf file path_to_the_mounted_ewf_file = None for file_path in os.listdir(mounting_path_ewf_dir): path_to_the_mounted_ewf_file = os.path.join(mounting_path_ewf_dir, file_path) if path_to_the_mounted_ewf_file is None: info(message='Could not find mounted ewf file. Exiting.') exit() # Mount ewf tile to unused loop device path_to_loop_device = __get_first_unused_loop_device() if int( os.system('losetup -Pv "{}" "{}" >/dev/null 2>&1'.format( __escape_path(path_to_loop_device), __escape_path(path_to_the_mounted_ewf_file)))) != 0: info( message= 'An error occurred while mounting ewf file to loop back device. Exiting.' ) exit() while True: info(message='Select Partition to mount:') os.system('fdisk -l "{}"'.format(__escape_path(path_to_loop_device))) print() selected_partition_number = input( 'select number of partition (0 for complete disk) [1] > ') if len(selected_partition_number) == 0: # Default value selected_partition_number = 1 else: # check if partition number is an integer try: selected_partition_number = int(selected_partition_number) except ValueError: error('The partition number must be an integer') print() continue if selected_partition_number == 0: selected_partition_path = path_to_loop_device info(message='selected the complete disk "{}"'.format( __escape_path(selected_partition_path))) else: selected_partition_path = '{}p{}'.format( path_to_loop_device, selected_partition_number) info(message='selected partition "{}"'.format( __escape_path(selected_partition_path))) bitlocker_key = input( 'Bitlocker Recovery Key (if encrypted otherwise empty) > ') if len(bitlocker_key) > 0: # check if provided key is valid if re.fullmatch(r'((\d){6}-){7}(\d{6})', bitlocker_key) is None: error( 'The format of the recovery key you typed in is invalid.') info( 'The key must be in the format: DDDDDD-DDDDDD-DDDDDD-DDDDDD-DDDDDD-DDDDDD-DDDDDD' ) print() continue mounting_path_dislocker = os.path.join( mounting_path, '.partition_{}_encrypted'.format(selected_partition_number)) if not os.path.exists(mounting_path_dislocker): os.makedirs(mounting_path_dislocker) if int( os.system( 'dislocker -v -V "{}" -p{} "{}" >/dev/null 2>&1'. format(__escape_path(selected_partition_path), bitlocker_key, __escape_path(mounting_path_dislocker)))) != 0: info(message= 'An Error occurred. Partition could not be decrypted') else: mounting_path_dislocker_file = os.path.join( mounting_path_dislocker, 'dislocker-file') mounting_path_decrypted = os.path.join( mounting_path, 'partition_{}_decrypted'.format(selected_partition_number)) __final_mount_procedure( source_path=mounting_path_dislocker_file, target_path=mounting_path_decrypted, partition_number=selected_partition_number) else: mounting_path_partition = os.path.join( mounting_path, 'partition_{}'.format(selected_partition_number)) __final_mount_procedure(source_path=selected_partition_path, target_path=mounting_path_partition, partition_number=selected_partition_number) print() input('Press ENTER to mount another partition')