def start_ktrace(self, name, kprops): """Starts a new trace. Parameters --------- name: str the name for the trace session kprops: KTraceProps an instance of the kernel trace properties """ self._trace_name = name handle = TRACEHANDLE() kp = kprops.get() status = start_trace(byref(handle), self._trace_name, kp) self._handle = handle if status == ERROR_ALREADY_EXISTS: # the kernel logger trace session # is already running. Restart the trace. self.stop_ktrace() status = start_trace(byref(handle), self._trace_name, kp) if status != ERROR_SUCCESS: raise FibratusError('Unable to start fibratus') self._handle = handle elif status == ERROR_ACCESS_DENIED: # insufficient privileges panic( "You don't have administrative privileges. Stopping fibratus..." ) elif status == ERROR_BAD_LENGTH: raise FibratusError('Incorrect buffer size for the trace buffer') elif status == ERROR_INVALID_PARAMETER: raise FibratusError('Invalid trace handle or provider GUID') elif status != ERROR_SUCCESS: raise FibratusError('Unable to start fibratus')
def __init__(self, config_path=None): path = os.getenv('FIBRATUS_CONFIG_PATH', __DEFAULT_CONFIG_PATH__) path = config_path or path try: self._yaml = anyconfig.load(path, ignore_missing=False) except FileNotFoundError: panic('ERROR - %s configuration file does not exist' % path)
def load(self, validate=True): schema_file = os.path.join(sys._MEIPASS, 'schema.yml') \ if hasattr(sys, '_MEIPASS') else self._default_schema_path try: self._yaml = anyconfig.load(self.path, ignore_missing=False) except FileNotFoundError: panic('ERROR - %s configuration file does not exist' % self.path) if validate: validator = Core(source_file=self.path, schema_files=[schema_file]) validator.validate(raise_exception=True)
def render_tabular(self): """Renders the table to the console. """ if len(self._cols) > 0: tabular = self._tabular.get_string(start=1, end=self._limit) if self._sort_by: tabular = self._tabular.get_string(start=1, end=self._limit, sortby=self._sort_by, reversesort=self._sort_desc) self._tabular.clear_rows() if not _ansi_term.term_ready: try: _ansi_term.setup_console() except TermInitializationError: panic( 'fibratus run: ERROR - console initialization failed') _ansi_term.cls() _ansi_term.write_output(tabular)
def start_ktrace(self, name, kprops): """Starts a new trace. Parameters --------- name: str the name for the trace session kprops: KTraceProps an instance of the kernel trace properties """ self._trace_name = name handle = TRACEHANDLE() kp = kprops.get() status = start_trace(byref(handle), self._trace_name, kp) self._handle = handle if status == ERROR_ALREADY_EXISTS: # the kernel logger trace session # is already running. Restart the trace. self.stop_ktrace() status = start_trace(byref(handle), self._trace_name, kp) if status != ERROR_SUCCESS: raise FibratusError('Unable to start fibratus') self._handle = handle elif status == ERROR_ACCESS_DENIED: # insufficient privileges panic("You don't have administrative privileges. Stopping fibratus...") elif status == ERROR_BAD_LENGTH: raise FibratusError('Incorrect buffer size for the trace buffer') elif status == ERROR_INVALID_PARAMETER: raise FibratusError('Invalid trace handle or provider GUID') elif status != ERROR_SUCCESS: raise FibratusError('Unable to start fibratus')
def _assert_root_dir(cls): if not os.path.exists(FILAMENTS_DIR): panic('fibratus run: ERROR - %s path does not exist.' % FILAMENTS_DIR)
def _initialize_funcs(self): """Setup the filament modules functions. Functions --------- set_filter: func accepts the comma separated list of kernel events for whose the filter should be applied set_interval: func establishes the fixed repeating interval in seconds columns: func configure the column set for the table add_row: func adds a new row to the table sort_by: func sorts the table by specific column """ def set_filter(*args): self._filters = args self._filament_module.set_filter = set_filter def set_interval(interval): if not type(interval) is int: raise FilamentError('Interval must be an integer value') self._interval = interval self._filament_module.set_interval = set_interval def columns(cols): if not isinstance(cols, list): raise FilamentError('Columns must be a list, ' '%s found' % type(cols)) self._cols = cols self._tabular = Tabular(self._cols) self._tabular.padding_width = 10 self._tabular.junction_char = '|' def add_row(row): if not isinstance(row, list): raise FilamentError( 'Expected list type for the row, found %s' % type(row)) self._tabular.add_row(row) def sort_by(col, sort_desc=True): if len(self._cols) == 0: raise FilamentError('Expected at least 1 column but 0 found') if col not in self._cols: raise FilamentError('%s column does not exist' % col) self._sort_by = col self._sort_desc = sort_desc def limit(l): if len(self._cols) == 0: raise FilamentError('Expected at least 1 column but 0 found') if not type(l) is int: raise FilamentError('Limit must be an integer value') self._limit = l def title(text): self._tabular.title = text self._filament_module.columns = columns self._filament_module.title = title self._filament_module.sort_by = sort_by self._filament_module.limit = limit self._filament_module.add_row = add_row self._filament_module.render_tabular = self.render_tabular on_init = self._find_filament_func('on_init') if on_init and self._zero_args(on_init): self._filament_module.on_init() if self._find_filament_func('on_interval'): self.scheduler.add_executor(ThreadPoolExecutor(max_workers=4)) self.scheduler.start() def on_interval(): try: self._filament_module.on_interval() except Exception: self._logger.error( 'Unexpected error on interval elapsed %s' % traceback.format_exc()) self.scheduler.add_job(on_interval, 'interval', seconds=self._interval, max_instances=4, misfire_grace_time=60) if len(self._cols) > 0: try: self._ansi_term.setup_console() except TermInitializationError: panic('fibratus run: ERROR - console initialization failed')
def __init__(self, filament, **kwargs): self._start = datetime.now() try: log_path = os.path.join(os.path.expanduser('~'), '.fibratus', 'fibratus.log') FileHandler(log_path, mode='w+').push_application() StreamHandler(sys.stdout, bubble=True).push_application() except PermissionError: panic( "ERROR - Unable to open log file for writing due to permission error" ) self.logger = Logger(Fibratus.__name__) self._config = YamlConfig() self.logger.info('Starting Fibratus...') enable_cswitch = kwargs.pop('cswitch', False) self.kcontroller = KTraceController() self.ktrace_props = KTraceProps() self.ktrace_props.enable_kflags(cswitch=enable_cswitch) self.ktrace_props.logger_name = etw.KERNEL_LOGGER_NAME enum_handles = kwargs.pop('enum_handles', True) self.handle_repository = HandleRepository() self._handles = [] # query for handles on the # start of the kernel trace if enum_handles: self.logger.info('Enumerating system handles...') self._handles = self.handle_repository.query_handles() self.logger.info('%s handles found' % len(self._handles)) self.handle_repository.free_buffers() image_meta_config = self._config.image_meta self.image_meta_registry = ImageMetaRegistry( image_meta_config.enabled, image_meta_config.imports, image_meta_config.file_info) self.thread_registry = ThreadRegistry(self.handle_repository, self._handles, self.image_meta_registry) self.kevt_streamc = KEventStreamCollector( etw.KERNEL_LOGGER_NAME.encode()) skips = self._config.skips image_skips = skips.images if 'images' in skips else [] if len(image_skips) > 0: self.logger.info("Adding skips for images %s" % image_skips) for skip in image_skips: self.kevt_streamc.add_skip(skip) self.kevent = KEvent(self.thread_registry) self._output_classes = dict(console=ConsoleOutput, amqp=AmqpOutput, smtp=SmtpOutput, elasticsearch=ElasticsearchOutput) self._outputs = self._construct_outputs() self.output_aggregator = OutputAggregator(self._outputs) self._binding_classes = dict(yara=YaraBinding) self._bindings = self._construct_bindings() if filament: filament.logger = self.logger filament.do_output_accessors(self._outputs) self._filament = filament self.fsio = FsIO(self.kevent, self._handles) self.hive_parser = HiveParser(self.kevent, self.thread_registry) self.tcpip_parser = TcpIpParser(self.kevent) self.dll_repository = DllRepository(self.kevent) self.context_switch_registry = ContextSwitchRegistry( self.thread_registry, self.kevent) self.output_kevents = {} self.filters_count = 0
def _initialize_funcs(self): """Setup the filament modules functions. Functions --------- set_filter: func accepts the comma separated list of kernel events for whose the filter should be applied set_interval: func establishes the fixed repeating interval in seconds columns: func configure the column set for the table add_row: func adds a new row to the table sort_by: func sorts the table by specific column """ def set_filter(*args): self._filters = args self._filament_module.set_filter = set_filter def set_interval(interval): if not type(interval) is int: raise FilamentError('Interval must be an integer value') self._interval = interval self._filament_module.set_interval = set_interval def columns(cols): if not isinstance(cols, list): raise FilamentError('Columns must be a list, ' '%s found' % type(cols)) self._cols = cols self._tabular = Tabular(self._cols) self._tabular.padding_width = 10 self._tabular.junction_char = '|' def add_row(row): if not isinstance(row, list): raise FilamentError('Expected list type for the row, found %s' % type(row)) self._tabular.add_row(row) def sort_by(col, sort_desc=True): if len(self._cols) == 0: raise FilamentError('Expected at least 1 column but 0 found') if col not in self._cols: raise FilamentError('%s column does not exist' % col) self._sort_by = col self._sort_desc = sort_desc def limit(l): if len(self._cols) == 0: raise FilamentError('Expected at least 1 column but 0 found') if not type(l) is int: raise FilamentError('Limit must be an integer value') self._limit = l def title(text): self._tabular.title = text self._filament_module.columns = columns self._filament_module.title = title self._filament_module.sort_by = sort_by self._filament_module.limit = limit self._filament_module.add_row = add_row self._filament_module.render_tabular = self.render_tabular on_init = self._find_filament_func('on_init') if on_init and self._zero_args(on_init): self._filament_module.on_init() if self._find_filament_func('on_interval'): self.scheduler.add_executor(ThreadPoolExecutor(max_workers=4)) self.scheduler.start() def on_interval(): try: self._filament_module.on_interval() except Exception: self._logger.error('Unexpected error on interval elapsed %s' % traceback.format_exc()) self.scheduler.add_job(on_interval, IntervalTrigger(), seconds=self._interval, max_instances=4, misfire_grace_time=60) if len(self._cols) > 0: try: self._ansi_term.setup_console() except TermInitializationError: panic('fibratus run: ERROR - console initialization failed')
def main(): if args['run']: if len(kevent_filters) > 0 and not filament_name: for kfilter in kevent_filters: _check_kevent(kfilter) enum_handles = False if args['--no-enum-handles'] else True cswitch = True if args['--cswitch'] else False filament = None filament_filters = [] if filament_name: if not Filament.exists(filament_name): panic('fibratus run: ERROR - %s filament does not exist. Run list-filaments to see ' 'the available filaments' % filament_name) filament = Filament() try: filament.load_filament(filament_name) except FilamentError as e: panic('fibratus run: ERROR - %s' % e) filament_filters = filament.filters if len(filament_filters) > 0: for kfilter in filament_filters: _check_kevent(kfilter) filament.render_tabular() try: fibratus = Fibratus(filament, enum_handles=enum_handles, cswitch=cswitch) except KeyboardInterrupt: # the user has stopped command execution # before opening the kernel event stream sys.exit(0) @PHANDLER_ROUTINE def handle_ctrl_c(event): if event == 0: fibratus.stop_ktrace() return 0 set_console_ctrl_handler(handle_ctrl_c, True) # add specific filters filters = dict() filters['pid'] = args['--pid'] if args['--pid'] else None filters['image'] = args['--image'] if args['--image'] else None if not filament: if len(kevent_filters) > 0: fibratus.add_filters(kevent_filters, **filters) else: fibratus.add_filters([], **filters) else: if len(filament_filters) > 0: fibratus.add_filters(filament_filters, **filters) else: fibratus.add_filters([], **filters) try: fibratus.run() except KeyboardInterrupt: set_console_ctrl_handler(handle_ctrl_c, False) elif args['list-filaments']: filaments = Tabular(['Filament', 'Description'], 'Description', sort_by='Filament') for filament, desc in Filament.list_filaments().items(): filaments.add_row([filament, desc]) filaments.draw() elif args['list-kevents']: kevents = Tabular(['KEvent', 'Category', 'Description'], 'Description', sort_by='Category') for kevent, meta in KEvents.meta_info().items(): kevents.add_row([kevent, meta[0].name, meta[1]]) kevents.draw()
def _check_kevent(kevent): if kevent not in KEvents.all(): panic('fibratus run: ERROR - %s is not a valid kernel event. Run list-kevents to see ' 'the available kernel events' % kevent)
def main(): if args['run']: if len(kevent_filters) > 0 and not filament_name: for kfilter in kevent_filters: _check_kevent(kfilter) enum_handles = False if args['--no-enum-handles'] else True cswitch = True if args['--cswitch'] else False filament = None filament_filters = [] if not filament_name: print('Starting fibratus...') else: if not Filament.exists(filament_name): panic( 'fibratus run: ERROR - %s filament does not exist. Run list-filaments to see ' 'the availble filaments' % filament_name) filament = Filament() try: filament.load_filament(filament_name) except FilamentError as e: panic('fibratus run: ERROR - %s' % e) filament_filters = filament.filters if len(filament_filters) > 0: for kfilter in filament_filters: _check_kevent(kfilter) filament.render_tabular() try: fibratus = Fibratus(filament, enum_handles=enum_handles, cswitch=cswitch) except KeyboardInterrupt: # the user has stopped command execution # before opening the kernel event stream sys.exit(0) @PHANDLER_ROUTINE def handle_ctrl_c(event): if event == 0: fibratus.stop_ktrace() return 0 set_console_ctrl_handler(handle_ctrl_c, True) # add specific filters filters = dict() filters['pid'] = args['--pid'] if args['--pid'] else None if not filament: if len(kevent_filters) > 0: fibratus.add_filters(kevent_filters, **filters) else: fibratus.add_filters([], **filters) else: if len(filament_filters) > 0: fibratus.add_filters(filament_filters, **filters) else: fibratus.add_filters([], **filters) try: fibratus.run() except KeyboardInterrupt: set_console_ctrl_handler(handle_ctrl_c, False) elif args['list-filaments']: filaments = Tabular(['Filament', 'Description'], 'Description', sort_by='Filament') for filament, desc in Filament.list_filaments().items(): filaments.add_row([filament, desc]) filaments.draw() elif args['list-kevents']: kevents = Tabular(['KEvent', 'Category', 'Description'], 'Description', sort_by='Category') for kevent, meta in KEvents.meta_info().items(): kevents.add_row([kevent, meta[0].name, meta[1]]) kevents.draw()
def _check_kevent(kevent): if kevent not in KEvents.all(): panic( 'fibratus run: ERROR - %s is not a valid kernel event. Run list-kevents to see ' 'the available kernel events' % kevent)
def __init__(self, filament, **kwargs): self._start = datetime.now() try: log_path = os.path.join(os.path.expanduser('~'), '.fibratus', 'fibratus.log') FileHandler(log_path, mode='w+').push_application() StreamHandler(sys.stdout, bubble=True).push_application() except PermissionError: panic("ERROR - Unable to open log file for writing due to permission error") self.logger = Logger(Fibratus.__name__) self.logger.info('Starting Fibratus...') self._config = YamlConfig() self.logger.info('Loading configuration from [%s]' % self._config.config_path) try: self._config.load() except SchemaError as e: panic('Invalid configuration file. %s' % e.msg) enable_cswitch = kwargs.pop('cswitch', False) self.kcontroller = KTraceController() self.ktrace_props = KTraceProps() self.ktrace_props.enable_kflags(cswitch=enable_cswitch) self.ktrace_props.logger_name = etw.KERNEL_LOGGER_NAME enum_handles = kwargs.pop('enum_handles', True) self.handle_repository = HandleRepository() self._handles = [] # query for handles on the # start of the kernel trace if enum_handles: self.logger.info('Enumerating system handles...') self._handles = self.handle_repository.query_handles() self.logger.info('%s handles found' % len(self._handles)) self.handle_repository.free_buffers() image_meta_config = self._config.image_meta self.image_meta_registry = ImageMetaRegistry(image_meta_config.enabled, image_meta_config.imports, image_meta_config.file_info) self.thread_registry = ThreadRegistry(self.handle_repository, self._handles, self.image_meta_registry) self.kevt_streamc = KEventStreamCollector(etw.KERNEL_LOGGER_NAME.encode()) skips = self._config.skips image_skips = skips.images if 'images' in skips else [] if len(image_skips) > 0: self.logger.info("Adding skips for images %s" % image_skips) for skip in image_skips: self.kevt_streamc.add_skip(skip) self.kevent = KEvent(self.thread_registry) self._output_classes = dict(console=ConsoleOutput, amqp=AmqpOutput, smtp=SmtpOutput, elasticsearch=ElasticsearchOutput, fs=FsOutput) self._outputs = self._construct_outputs() self.output_aggregator = OutputAggregator(self._outputs) self._binding_classes = dict(yara=YaraBinding) self._bindings = self._construct_bindings() if filament: filament.logger = self.logger filament.do_output_accessors(self._outputs) self._filament = filament self.fsio = FsIO(self.kevent, self._handles) self.hive_parser = HiveParser(self.kevent, self.thread_registry) self.tcpip_parser = TcpIpParser(self.kevent) self.dll_repository = DllRepository(self.kevent) self.context_switch_registry = ContextSwitchRegistry(self.thread_registry, self.kevent) self.output_kevents = {} self.filters_count = 0