如何实现一个Psexec

倾旋
倾旋
技术分享|2020-4-2|最后更新: 2023-6-22|
type
status
date
slug
summary
tags
category
icon
password
URL

0x01 Psexec

Psexec被编写的初衷是为了方便服务器管理员管理大量的机器而开发的,但由于它的便捷,同时也被黑客使用。
相信很多人都用过Psexec这款工具了,它由Sysinternals网站提供,Sysinternals这个网站由Mark Russinovich于1996年创建,用于托管他的高级系统实用程序和技术信息。

0x02 Psexec的执行原理

为了清楚的了解它的执行原理,我们先从日志看起。
环境:
  • Windows 2008 R2 X64 → 192.168.3.130(以下简称Win2008)
  • Kali Linux 2019.4 → 192.168.3.145(以下简称Kali)
  • Windows 10 → 192.168.3.1(以下简称Win10)
首先在Windows 10上对Windows 2008 R2 X64这台机器进行Psexec
notion image

查看安全日志

打开Win2008日志查看器,先查看安全(Security)日志:
notion image
从日志查看器能够看到产生了多个安全审核日志,事件ID:4624,并且能够看到来源IP以及计算机名。
认证类型NTLM:
notion image
接着,还有事件ID为4648的日志,该条目的解释是:
在进程尝试通过显式指定帐户的凭据来登录该帐户时生成此事件。这通常发生在批量类型的配置中(例如计划任务) 或者使用 RUNAS 命令时。
notion image
可以看到很明显的PSEXECSVC.exe这个程序被启动。
目前可以猜测:先进行Windows 认证,然后产生PSEXESVC.exe并启动。

查看系统日志

notion image
事件ID:7045向系统报告了一个名为“PSEXESVC”的服务被安装,同时紧接着事件ID:7036报告“PSEXESVC服务已经启动”。
notion image
通过事件ID报告的顺序,我们大致了解了PsEXEC的动作。
  1. 事件ID:4624
  1. 事件ID:4648
  1. 事件ID:7045
  1. 事件ID:7036
当PsExec执行exit退出交互式命令行后,会向系统报告事件ID:4634注销事件、事件ID:7036 PSEXESVC服务停止。

0x03 从网络分析Psexec利用过程

notion image
这里我使用Wireshark抓包工具,捕获了整个Psexec建立网络连接到exit退出的整个过程。
认证大致流程:
  1. 192.168.3.1向192.168.3.130 进行三次握手
  1. 192.168.3.1向192.168.3.130 协商认证方式
  1. 192.168.3.1向192.168.3.130 发送 NTLMSSP_NEGOTIATE
  1. 192.168.3.130向192.168.3.1 发送 NTLMSSP_CHANLLENGE
  1. 192.168.3.1向192.168.3.130 发送 NTLMSSP_AUTH
  1. 192.168.3.130向192.168.3.1 发送 ACCEPT-COMPLETED,至此完成NTLMSSP认证
接着向\\192.168.3.130\ADMIN$写入PSEXESVC.exe:
notion image
在SMBV2传输的过程中,文件内容并没有进行加密,可以直接找到DOS头:
notion image
其开始的标志字为“MZ”(MarkZbikowski,他是DOS操作系统的开发者之一),所以称它为“DOS MZ头”。
文件传输后,Psexec会调用OpenServiceManager 来安装服务"PSEXESVC":
notion image
notion image
PSEXESVC服务启动后会与PsExec.exe构建一个管道进行传输数据(还是走SMB V2协议):
The Psexesvc service creates a named pipe, psexecsvc, to which PsExec connects and sends commands that tell the service on the remote system which executable to launch and which options you’ve specified. If you specify the -d (don’t wait) switch, the service exits after starting the executable; otherwise, the service waits for the executable to terminate, then sends the exit code back to PsExec for it to print on the local console.
notion image
到这里我想已经差不多足够我们实现一个PsExec了,大致过程如下:
  1. 编写PsEXESVC服务程序
  1. 连接SMB共享
  1. 上传文件到共享目录
  1. 创建服务
  1. 启动服务
  1. 停止服务
  1. 删除服务
  1. 删除文件
经过搜集资料,我发现主要有以下知识点:
  1. SMB共享的连接与认证
  1. SMB共享的文件操作
  1. 管理远程计算机服务
  1. 编写服务程序

0x04 连接SMB共享

应用程序可以调用WNetAddConnection函数将本地设备连接到网络资源,成功的连接是持久的,这意味着系统在后续的登录操作期间会自动恢复连接。
返回值:
如果函数成功,则返回值为NO_ERROR
OK,接下来我们创建一个Windows控制台应用程序,我这里使用的是Visual Studio 2019
notion image
创建一个名字叫Psexec的项目:
notion image
紧接着就可以写具体的实现代码了。
测试过程:
notion image
可以看到,传入对应的参数即可建立一个SMB连接。
notion image
建立SMB连接后,我们需要继续编写一个通过SMB协议在远程服务器上创建文件的函数。

关于SMB上传文件

说到这里,可能有的朋友觉得实现这个需求会非常的复杂,但是经过我的假设与验证,发现实现起来并不难,在后来的日子里,我获得了PsExec的源代码后,我这个方法比它更加方便直接。
CIFS(Common Internet File System),它是Windows上的一个文件共享协议。
CIFS 可以使您达到以下功能:
  1. 访问服务器本地文件并读写这些文件
  1. 与其它用户一起共享一些文件块
  1. 在断线时自动恢复与网络的连接
  1. 使用统一码(Unicode)文件名:文件名可以使用任何字符集,而不局限于为英语或西欧语言设计的字符集。
通过CIFS协议我们才能够将网络上的文件共享映射为本地资源去访问,大家可能熟悉net use
但不真正了解背后的原理。既然能够将网络文件映射到本地,相当于构建了一个逻辑上的本地磁盘,进而推理出我们直接利用Windows文件相关的API来操作共享文件都是可行的。
实现代码如下:
是不是非常简单,它就像操作本地文件一样简单。
为了方便测试,我在本地创建了一个test.txt 文本文件,然后我把wmain 更改了一下:
notion image
在Win2008上的C:\Windows\查看:
notion image
文件写入成功。

0x05 编写服务程序

Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务,并且部分服务是以SYSTEM权限启动。为了编写服务程序,我们需要了解一些关于服务的概念。
服务控制管理器(SCM:Services Control Manager)是一个管理系统所有服务的进程。当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 函数分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。

ServiceMain 函数

该函数是服务的入口点。它运行在一个单独的线程当中,这个线程是由控制分派器创建的。ServiceMain 应该尽可能早早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。
这里可以直接提供一个服务模板:
创建一个控制台应用程序,将源代码编译后就可以创建服务了,该服务会每隔5秒向D:\log.txt
写入信息。这里如果展开讲会花费不少时间,我直接把SERVICE_RUNNING 状态下的代码进行更改,使其执行Shellcode上线。

0x06 使用Windows API远程管理服务

前面说到,Windows的服务都由服务控制管理器(SCM:Services Control Manager)进行管理,我们可以通过Windows API去连接SCM,当服务程序上传到服务器上以后,创建一个服务,把binpath指向服务程序的路径,再对服务进行启动就可以达到任意代码执行的效果。
注意:远程连接SCM还是走的SMB协议 445端口,SMB V2可以明显看到流量内容。
如果当前用户在连接到另一台计算机上的服务时没有适当的访问权限,则 OpenSCManager函数调用将失败。若要远程连接到服务,请在调用OpenSCManager之前使用LOGON32_LOGON_NEW_CREDENTIALS 调用LogonUser函数,然后调用ImpersonateLoggedOnUser
这里需要注意的是,通过WNetAddConnection2认证后,再去调用OpenSCManager是不需要认证的。
获得SCM句柄后调用CreateService 创建一个服务,最终调用StartService 完成整个服务的创建、启动过程。
效果如下:
notion image
至此,整个Psexec工具原理分析与实践完成。

0x07 PsExec完整代码

0x08 总结PsExec防御

  1. 如果内网大量机器使用SMB V2,可从网络协议上进行分析,着重监控OpenSCManager
  1. 终端上进行事件监控如:创建服务、创建文件,根据HASH匹配能有效阻绝一部分攻击
  1. 服务器采用强口令,内网通用密码的情况太严重
  1. 在终端上日志着重采集以下事件ID
  • 事件ID:4624
  • 事件ID:4648
  • 事件ID:7045
  • 事件ID:7036
我的总结可能不够严谨,欢迎斧正。
©2021-2024 倾旋. All rights reserved.