RemotePSpy 提供对远程 PowerShell 会话的实时监控,这对于没有内置全面日志记录功能的旧版(5.0 之前)PowerShell 尤其有用。
它使用 Windows 事件跟踪(ETW)从 WinRM 协议获取消息数据,该协议用作远程 PowerShell 的传输层,并解码各个协议层以提供所执行脚本命令及其输入/输出的跟踪信息。
这目前是一个早期研究原型,因此并不支持 PowerShell 远程协议(PSRP)的每个方面。它仍然可以为远程 PowerShell 会话中发生的情况提供有用的见解。
最简单的安装方式是使用 pip:
pip install remotepspy
通过 pip 安装时,依赖项应自动安装,但如果您希望从源代码安装,则依赖项如下所列:
仅当使用(推荐的,且默认的)Microsoft-Windows-WinRM ETW 提供程序作为数据源时,才需要 libwim-15.dll。它用于解压缩 WinRM/WSMan 协议中包含 PSRP 消息片段的某些流对象。只需将其放在主 Python 脚本的同一目录中即可。
只需执行 RemotePSpy 即可开始监控和记录,完成后按回车键。日志将写入当前工作目录,文件名为 RemotePSpy.log。
该工具还会将远程 PowerShell 用户在其屏幕上看到的内容的近似副本打印到 stdout,同时将更详细的信息写入日志文件。更复杂的日志记录可用,请参阅下面的“日志记录”。
如果您将 Python 安装到了 PATH 中,RemotePSpy 可执行脚本也会在您的 PATH 中。否则,您可能需要在 Python site-packages 目录中查找它们。
默认的 RemotePSpy 使用(推荐的)WinRM ETW 提供程序作为数据源。如果您希望改用 PowerShell ETW 提供程序,可以执行 RemotePSpy_powershell_prov。
由于跟踪某些状态(基于此特定 ETW 提供程序中数据的提供方式)的复杂性增加,此版本可能会产生一些不必要的警告。
该代码由许多相当模块化的类组成,这些类可以在协议栈的不同层接受输入。这允许它们以略有不同的方式组合在一起,具体取决于数据的来源和形式。大多数类接受一个回调函数,用于将生成的结果传递给栈中的下一层。
下面描述了所使用的主要类,随后是一些处理流程,这些流程显示了在不同场景中哪个类将数据馈送给哪个类。
ETWWinRM – 从 WinRM 提供程序获取 ETW 事件。
ETWPowerShell – 从 PowerShell 提供程序获取 ETW 事件。
PowerShellETWParser – 为 PowerShell ETW 事件标识 Shell 上下文,将片段数据传递给 PSRPDefragmenter。还提供线程同步。
SoapDefragmenter – 从 WinRM ETW 事件重新组装完整的 WSMan SOAP 消息,将完整的 SOAP 传递给 WSManPS。
WSManPS – 过滤掉与 PowerShell 无关的 WinRM,跟踪 Shell 上下文,从 WSMan SOAP 中解析出 PSRP 片段数据,并将片段数据传递给 PSRPDefragmenter。
PSRPDefragmenter – 将 PSRP 片段重新组装为完整的 PSRP 消息。片段按 ObjectID 组装,并通过考虑 Shell 上下文来确保 ObjectID 的唯一性。将最终的 PSRP 消息传递给 PSRPParser。
PSRPParser – 解码原始二进制 PSRP 消息,提取 RPID、Pipeline ID 和 MessageType 等头部详细信息。将解码后的消息传递给 SimpleCommandTracer。
SimpleCommandTracer – 使用 MessageType 解释 PSRP 消息,并提取和打印/记录命令、参数及其输出。包括对序列化 PowerShell 对象的部分解码。并非每个可能功能的完整实现,但尝试覆盖大多数常见情况以允许执行跟踪。
使用 Microsoft-Windows-WinRM ETW 提供程序时的处理流程:
ETWWinRM -> SoapDefragmenter -> WSManPS -> PSRPDefragmenter -> PSRPParser -> SimpleCommandTracer
使用 Microsoft-Windows-PowerShell ETW 提供程序时的处理流程:
ETWPowerShell -> PowerShellETWParser -> PSRPDefragmenter -> PSRPParser -> SimpleCommandTracer
协议栈的每一层都有全面的日志记录。这允许在各个级别进行调试,并且在开发期间尤其有帮助。希望它也能对任何想要研究远程 PowerShell 实际运行情况的人有用,因为可以在所有关键层获得协议的完整跟踪。
目前,必须编辑脚本末尾配置记录器的源代码才能更改日志记录。未来的版本希望能为此类配置提供更好的方法。
每个记录器名称由使用它的类中的常量 LOGGER_NAME 定义。每个记录器都定义为“RemotePSpy”的子级(例如 RemotePSpy.etw)。以编程方式,可以使用 logging.getLogger() 并配合适当的日志名称来配置记录器。
为快速参考,以下记录器和级别将为您提供协议中不同层的协议跟踪:
请注意,SimpleCommandTracer 也会在 stdout 上输出跟踪,这试图在一定程度上复制远程 PowerShell 用户会看到的显示。这与命令跟踪日志不同,后者以更精确的方式记录每个命令、管道方法调用和管道输出,包括 RPID 和 Pipeline ID 等额外上下文。
下面更全面地总结了每个日志中在哪个级别出现什么内容:
ERROR:
WARNING:
INFO:
DEBUG:
DEBUG:
ERROR:
WARNING:
INFO:
DEBUG:
ERROR:
WARNING:
INFO:
DEBUG:
INFO:
DEBUG:
DEBUG:
ERROR:
DEBUG:
INFO:
| 关键日志数据 | 记录器名称常量 | 级别 |
|---|
| 命令跟踪 | SimpleCommandTracer.LOGGER_NAME | INFO |
| 完整 ETW 事件跟踪 | ETWWinRM.LOGGER_NAME | DEBUG |
| 完整 WSMan SOAP 消息跟踪 | SoapDefragmenter.LOGGER_NAME | INFO |
| 每个 PSRP 片段的完整跟踪 | PSRPDefragmenter.LOGGER_NAME | DEBUG |
| 完整 PSRP 消息跟踪 | PSRPParser.LOGGER_NAME | DEBUG |