VulnCity

هر پاورشلی، Powershell.exe نیست؛ Defense Evasion

نویسنده: یاسین عابدینی · دسته: RedTeam · تاریخ انتشار: ۱۴۰۵/۲/۲

معماری داخلی PowerShell: جدایی موتور از رابط کاربری

مقدمه

powershell.exe تنها یک wrapper ساده است. موتور واقعی PowerShell در System.Management.Automation.dll قرار دارد که می‌توان آن را مستقیماً از .NET فراخوانی کرد.

۱. معماری کلی

مفاهیم کلیدی:

  • System.Management.Automation.dll: هسته اصلی که شامل parser، runtime، و cmdlet engine است
  • powershell.exe: فقط یک host process که DLL را load می‌کند
  • Runspace: محیط اجرای مجزا برای کدهای PowerShell
  • Pipeline: مکانیزم اجرای دستورات به صورت زنجیره‌ای

مزایای استفاده مستقیم از DLL:

  • دور زدن logging و monitoring سطح process
  • اجرای بدون ایجاد فرآیند powershell.exe
  • کنترل دقیق‌تر بر محیط اجرا
  • امکان embedding در برنامه‌های .NET

۲. روش اول: Reflection-based Loading

# بارگذاری مستقیم assembly
$assembly = [Reflection.Assembly]::LoadFile(
    'C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll'
)

# ایجاد instance از PowerShell engine
$ps = $assembly.GetType('System.Management.Automation.PowerShell')::Create()

# اضافه کردن script
[void]$ps.AddScript({ 
    Get-Process | Where-Object {$_.CPU -gt 100}
})

# اجرا
$results = $ps.Invoke()

نکات فنی:

  • LoadFile به مسیر کامل نیاز دارد
  • می‌توان از Load با Fully Qualified Name استفاده کرد
  • Create() یک runspace پیش‌فرض می‌سازد
  • AddScript می‌تواند ScriptBlock یا string بپذیرد

مسیرهای رایج DLL:

# .NET Framework 4.x
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\

# WinSxS (نسخه‌های قدیمی)
C:\Windows\WinSxS\msil_system.management.automation_*\

۳. روش دوم: C# Native Integration

using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;

public class PowerShellExecutor
{
    public static string Execute(string script)
    {
        // ایجاد Runspace Configuration
        RunspaceConfiguration config = RunspaceConfiguration.Create();
        
        // ایجاد و باز کردن Runspace
        using (Runspace runspace = RunspaceFactory.CreateRunspace(config))
        {
            runspace.Open();
            
            // ایجاد Pipeline
            using (Pipeline pipeline = runspace.CreatePipeline())
            {
                // اضافه کردن script
                pipeline.Commands.AddScript(script);
                
                // تبدیل خروجی به string
                pipeline.Commands.Add("Out-String");
                
                // اجرا
                Collection<PSObject> results = pipeline.Invoke();
                
                // پردازش نتایج
                StringBuilder output = new StringBuilder();
                foreach (PSObject obj in results)
                {
                    output.AppendLine(obj.ToString());
                }
                
                return output.ToString();
            }
        }
    }
}

۴. کامپایل و اجرا

# پیدا کردن مسیر System.Management.Automation.dll
$DLLPath = [PSObject].Assembly.Location

# پیدا کردن کامپایلر C#
$CscPath = [System.Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory() + 'csc.exe'

# کامپایل
& $CscPath `
    /r:$DLLPath `
    /r:System.dll `
    /unsafe `
    /platform:anycpu `
    /target:exe `
    /out:"PowerShellHost.exe" `
    "PowerShellHost.cs"

# اجرا
.\PowerShellHost.exe

پارامترهای کامپایلر:

  • /r: - Reference به assembly
  • /unsafe - اجازه unsafe code
  • /platform:anycpu - سازگاری با x86 و x64
  • /target:exe یا /target:winexe - نوع خروجی

۵. سناریوهای پیشرفته

۵.۱ استفاده از Parameters:

pipeline.Commands.AddScript("param($name) Write-Host \"Hello $name\"");
pipeline.Commands[0].Parameters.Add("name", "World");

۵.۲ Import کردن Modules:

InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new[] { "ActiveDirectory", "DnsServer" });
Runspace runspace = RunspaceFactory.CreateRunspace(iss);

۶. ملاحظات امنیتی

از دیدگاه دفاعی:

  • این تکنیک‌ها می‌توانند برای دور زدن Application Whitelisting استفاده شوند
  • AMSI (Antimalware Scan Interface) همچنان می‌تواند محتوای script را اسکن کند
  • Event Log 4104 (Script Block Logging) همچنان فعال است

راهکارهای تشخیص:

  • مانیتور کردن load شدن System.Management.Automation.dll در processهای غیرمعمول
  • بررسی ETW events مربوط به PowerShell
  • استفاده از Sysmon برای رصد Assembly Load

از دیدگاه تهاجمی:

  • برای Constrained Language Mode bypass قابل استفاده است
  • می‌توان با Obfuscation ترکیب کرد
  • امکان injection به processهای دیگر

۷. مثال کامل: Custom PowerShell Host

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

class CustomPSHost
{
    static void Main(string[] args)
    {
        InitialSessionState iss = InitialSessionState.CreateDefault();
        
        // محدود کردن دسترسی‌ها
        iss.LanguageMode = PSLanguageMode.RestrictedLanguage;
        
        using (Runspace rs = RunspaceFactory.CreateRunspace(iss))
        {
            rs.Open();
            
            while (true)
            {
                Console.Write("PS> ");
                string cmd = Console.ReadLine();
                
                if (cmd == "exit") break;
                
                using (PowerShell ps = PowerShell.Create())
                {
                    ps.Runspace = rs;
                    ps.AddScript(cmd);
                    
                    try
                    {
                        var results = ps.Invoke();
                        foreach (var item in results)
                            Console.WriteLine(item);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error: {ex.Message}");
                    }
                }
            }
        }
    }
}