Source code for volatility3.plugins.windows.sessions

# This file is Copyright 2022 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#

import datetime
import logging

from volatility3.framework import renderers, interfaces
from volatility3.framework.configuration import requirements
from volatility3.framework.objects import utility
from volatility3.plugins.windows import pslist
from volatility3.plugins import timeliner

vollog = logging.getLogger(__name__)


[docs]class Sessions(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): """lists Processes with Session information extracted from Environmental Variables""" _required_framework_version = (2, 0, 0)
[docs] @classmethod def get_requirements(cls): return [ requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel', architectures = ["Intel32", "Intel64"]), requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)), requirements.ListRequirement(name = 'pid', element_type = int, description = "Process IDs to include (all other processes are excluded)", optional = True) ]
def _generator(self): kernel = self.context.modules[self.config['kernel']] filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None)) # Collect all the values as we will want to group them later sessions = {} for proc in pslist.PsList.list_processes(self.context, kernel.layer_name, kernel.symbol_table_name, filter_func = filter_func): session_id = proc.get_session_id() # Detect RDP, Console or set default value session_type = renderers.NotAvailableValue() # Construct Username from Process Env user_domain = '' user_name = '' for var, val in proc.environment_variables(): if var.lower() == 'username': user_name = val elif var.lower() == 'userdomain': user_domain = val if var.lower() == 'sessionname': session_type = val # Concat Domain and User full_user = f'{user_domain}/{user_name}' if full_user == '/': full_user = renderers.NotAvailableValue() # Collect all the values in to a row we can yield after sorting. row = { "session_id": session_id, "process_id": proc.UniqueProcessId, "process_name": utility.array_to_string(proc.ImageFileName), "user_name": full_user, "process_start": proc.get_create_time(), "session_type": session_type } # Add row to correct session so we can sort it later if session_id in sessions: sessions[session_id].append(row) else: sessions[session_id] = [row] # Group and yield each row for rows in sessions.values(): for row in rows: yield 0, (row.get('session_id'), row.get('session_type'), row.get('process_id'), row.get('process_name'), row.get('user_name'), row.get('process_start'))
[docs] def generate_timeline(self): for row in self._generator(): _depth, row_data = row # Only add to timeline if we have the username # Without the user context PSList output is identical if isinstance(row_data[4], str): description = f"Process: {row_data[2]} {row_data[3]} started by user {row_data[4]}" yield (description, timeliner.TimeLinerType.CREATED, row_data[5])
[docs] def run(self): return renderers.TreeGrid([("Session ID", int), ('Session Type', str), ("Process ID", int), ("Process", str), ("User Name", str), ("Create Time", datetime.datetime)], self._generator())