在某些情况下,有时需要有可能查看客户的用户屏幕以制作一些经过验证的屏幕截图或访问一个打开的 GUI 应用程序窗口,其中包含横向移动的秘密,同时合法用户通过 RDP 与您连接不想把他们踢出会议。
市场上有许多第三方软件如VNC、radmin、TeamViewer等来实现它,但它涉及额外的操作,如二进制交付、安装等。此外,这些操作过于嘈杂,会在远程主机上留下大量垃圾。
幸运的是,基于 Windows 的系统有一个很棒的内置功能(作为远程桌面协议的一部分),它被不公平地忽略或遗忘。它称为远程桌面服务阴影。
该功能有两个版本。由于旧版本的远程桌面服务阴影与最新版本不兼容,并且系统管理员的网站和论坛上有几篇关于它的文章,因此我不打算广泛地描述前一个,仅作为历史注释几句话。
在早期版本的 Windows 中,shadow.exe文件允许用户使用远程桌面服务阴影技术连接到远程主机。很快,这是mstsc实用程序及其 /shadow 参数的前身。它是在 Windows Server 2003 中引入的,可用于许多版本的 Windows。
此外,还有两个 GUI 应用程序,它们执行相同的操作:自 Windows Server 2003 以来就存在的终端服务管理(TSAdmin) 和作为远程服务器管理工具 (RSAT) 一部分的远程桌面服务管理器(RDSM) 和替换 Windows Server 2012 上的 TSAdmin。
RDS Shadowing 版本之间的主要区别在于,对于旧版,您必须先建立 RDP 连接才能在远程主机上获取会话,然后才能在该主机上隐藏其他任何人的会话。使用最新版本,您可以从自己主机的控制台在远程主机上隐藏用户的会话。
现在让我们深入了解最新版本。从 Windows 7 开始的任何现代 Microsoft Windows 版本都可用于连接到具有会话重影功能的远程主机,但其中一些需要完成额外的步骤,并且只能在以下提到的情况下有几个限制才能使用。
要求
基于 Windows 的系统必须满足三个主要要求才能使用该功能。
第一个也是最重要的部分是远程桌面协议版本。它必须是8.1或更高版本。以下版本的 Microsoft Windows 可用于服务器端和客户端,因为它们具有开箱即用的 RDP 8.1:
- Windows 8.1 及更高版本;
- Windows Server 2012 R2 及更高版本。
Windows 7、Windows Server 2008、Windows 8、Windows Server 2012 版本在服务器端不支持此功能。
如果您想将这些版本用作客户端,您要做的第一件事就是安装其他更新以将远程桌面协议版本更新到 8.1。之后,您就可以连接到支持 RDS 阴影功能的远程主机上的任何 Windows 版本。有关详细信息,请参阅https://support.microsoft.com/en-us/help/2830477/update-for-remoteapp-and-desktop-connections-feature-is-available-for。
接下来但同样重要的是远程主机必须运行 RDP 服务。
第三,除了软件和服务要求之外,还必须对防火墙规则进行一些额外的更改。远程桌面服务重影功能不使用 3389/TCP 端口 (RDP),而是使用 445/TCP 端口 (SMB) 和临时端口,也称为动态端口范围 (RPC)。
这些更改可以通过添加新的自定义规则或启用以下内置规则来完成:
- 第一条规则叫做
File and Printer Sharing (SMB-In)
,它允许连接到端口 445/TCP; - 第二个是
Remote Desktop - Shadow (TCP-In)
。它只允许%SystemRoot%system32RdpSa.exe
二进制文件处理任何本地 TCP 端口上的入站连接。
注意: Windows 上的动态端口范围通常包括从 49152 到 65535 的 TCP 端口。可以通过发出以下命令来确定当前值:
代码语言:javascript复制netsh int ipv4 show dynamicport tcp
命令qwinsta
和quser
进一步描述还需要打开端口 445/TCP,否则会出现以下错误:
C:>qwinsta /server:{ADDRESS}
Error 1722 getting sessionnames
Error [1722]:The RPC server is unavailable.
注意:在shadowing连接看似成功,但没有弹出shadow session的窗口的情况下,检查防火墙规则(动态端口必须打开或启用Shadow规则)。
建立影子连接
使用远程桌面连接客户端 ( mstsc
) 实用程序中内置的功能来隐藏会话的最简单命令行字符串如下所示:
mstsc /v:{ADDRESS} /shadow:{SESSION_ID}
在哪里
/v
参数允许指定{ADDRESS}
可以是远程主机的 IP 地址或主机名的值;/shadow
参数用于指定{SESSION_ID}
作为 shadowee 会话 ID 的值。
注意:有关 mstsc 实用程序的所有可用参数的详细信息,请发出命令
代码语言:javascript复制mstsc /?
因此,根据上述命令的参数,您必须知道远程用户的会话 ID 才能建立影子连接。
要列出远程主机上的现有会话,您可以使用qwinsta
如下命令:
qwinsta /server:{ADDRESS}
或quser
等价于上述命令的命令
quser session /server:{ADDRESS}
一件有趣的事情是,如果用户锁定他们的屏幕 ( Win L
) 或切换到另一个用户的帐户(仅从锁定屏幕,有关详细信息,请参阅第 5 节)或弹出 UAC 提示,则带有阴影会话的窗口会自动切换到暂停状态(屏幕上的两条平行条纹),直到用户回来。当用户回来时,带有阴影会话的窗口会自动取消暂停。
影子会话处于暂停状态
还应该注意的是,最新版本的 RDS Shadowing 非常好地支持远程主机上的多显示器设置,即使在每台显示器上开箱即用的分辨率不同。
多显示器支持
滥用影子注册表项和 NoConsentPrompt 参数
我还没有提到Shadow
注册表项,因为默认情况下它不存在。
Shadow
默认情况下该键不存在
在这种情况下,行为与键值设置为1时的行为相同(如下所述)。换句话说,受影者必须明确授予允许其会话被影射的许可。
为了能够在未经许可的情况下隐藏它,您必须有意使用组策略覆盖它,例如,使用名为本地组策略编辑器 ( gpedit.msc
) 的GUI 应用程序设置远程桌面服务用户会话远程控制策略值的设置规则以允许会话未经用户许可的阴影。它位于本地计算机策略 → 计算机配置 → 管理模板 → Windows 组件 → 远程桌面服务 → 远程桌面会话主机 → 连接。
本地组策略编辑器管理控制台的策略设置窗口
也可以使用命令行解释器通过发出以下命令手动设置它:
代码语言:javascript复制reg add "HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindows NTTerminal Services" /v Shadow /t REG_DWORD /d 4
其中/d
参数的值为以下之一:
- 0 – 不允许遥控;
- 1 – 经用户许可完全控制;
- 2 – 无需用户许可即可完全控制;
- 3 – 经用户许可查看会话;
- 4 – 未经用户许可查看会话。
选择Not Configured
值或Disabled
值会删除Shadow
注册表项。
完全控制还允许在查看会话模式下连接,但为了避免错误指定/control
参数的情况,将Shadow
值设置为4更安全。
注意:要获取 Shadow 键的当前值,请执行以下操作:
代码语言:javascript复制reg query "HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindows NTTerminal Services" /v Shadow
删除阴影键类型
代码语言:javascript复制reg delete "HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindows NTTerminal Services" /v Shadow /f
Shadow
在远程主机上定义参数,可以在未经用户同意的情况下隐藏会话,如下所示:
mstsc /v:{ADDRESS} /shadow:{SESSION_ID} /noconsentprompt /prompt
在哪里
/v
参数让我们指定{ADDRESS}
远程主机的 IP 地址或主机名;/shadow
参数用于指定{SESSION_ID}
作为 shadowee 会话 ID 的值;/noconsentprompt
参数允许绕过 shadowee 的许可并在未经他们同意的情况下隐藏他们的会话;/prompt
参数用于指定用户的凭据以连接到远程主机。
另一种无需在弹出窗口中不断输入即可指定用户凭据的方法是使用以下runas
命令:
runas /netonly /noprofile /user:{USERNAME} cmd
并在新的命令行解释器窗口中运行该mstsc
实用程序
mstsc /v:{ADDRESS} /shadow:{SESSION_ID} /noconsentprompt
同样适用于qwinsta
和quser
。
有时您可能会遇到以下一般错误:
这可能意味着任何事情,但在某些情况下,这可能意味着
- 远程主机上不存在发出当前命令的上下文的用户;
- 指定的用户凭据不正确;
- 您正在尝试隐藏您没有权限的会话。
这种行为与以下情况几乎相同qwinsta
:
C:>qwinsta /server:{ADDRESS}
Error 5 getting sessionnames
Error [5]:Access is denied.
在工作组环境中,如果远程主机上也存在此帐户,则您可以使用任何本地帐户。
此外,如果你试图阴影会话(或使用列表会话qwinsta
或quser
)远程主机上未经授权的用户帐户,然后您就可以只连接到会议(仅列出有关会话的信息),与此相关的用户.
如果您使用的是非 RID 500 管理员帐户,您将获得相同的行为,但在远程主机上启用了 UAC 远程限制,更准确地说,这意味着LocalAccountTokenFilterPolicy
注册表项设置为0或该项不存在(默认情况下)。
在第一个屏幕截图中启用了 UAC 远程限制,在第二个屏幕中禁用了它们
qwinsta
启用 UAC 远程限制时的命令输出
qwinsta
禁用 UAC 远程限制时的命令输出
这是一种众所周知的安全机制,可在用户远程连接时去除管理员访问令牌。更多详细信息位于https://docs.microsoft.com/en-us/troubleshoot/windows-server/windows-security/user-account-control-and-remote-restriction。
要禁用它,请使用以下命令将值更改为1:
代码语言:javascript复制reg add HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
注意:要获取LocalAccountTokenFilterPolicy
密钥的当前值,请发出以下命令:
reg query HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem /v LocalAccountTokenFilterPolicy
删除LocalAccountTokenFilterPolicy
密钥类型
reg delete HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem /v LocalAccountTokenFilterPolicy /f
重要的是,如果您很幸运并且在远程主机上启用了内置的 RID 500 管理员帐户(默认情况下它是禁用的),您可以使用它来隐藏会话,因为LocalAccountTokenFilterPolicy
密钥不会影响它。FilterAdministratorToken
如果设置为1,则有另一个注册表项可能会限制此帐户,但默认情况下它设置为0。
因此,在工作组(以及域)环境中,本地管理员是唯一可以访问其他本地用户会话的本地用户(如果LocalAccountTokenFilterPolicy
和FilterAdministratorToken
注册表项设置为适当的值)。
在域环境中,任何域管理员都能够隐藏本地和域用户的会话。
我不知道它什么时候可能有用,但是可以mstsc
通过简单地增加{SESSION_ID}
值来枚举使用自身的会话的存在
mstsc /v:{ADDRESS} /shadow:{SESSION_ID}
如果没有这样的会话,则会出现以下错误:
您尝试连接的会话不存在
或者,如果会话存在,但没有人连接到它,或者您没有必要的权限,则会出现以下错误之一:
会话存在,但没有人连接到它
没有足够的权限来隐藏会话
否则,您将被授予权限并打开查看者的窗口
成功建立的镜像连接
滥用 StartRCM 和 fDenyChildConnections 注册表项
需求部分已经提到,要成功隐藏会话,必须运行远程桌面服务,否则会出现以下错误:
此服务器上运行的 Windows 版本不支持用户重影
启动它们的最简单方法是使用图形用户界面,如下所示:
允许从 GUI 窗口进行远程连接
或手动将fDenyTSConnections
注册表项从1(默认情况下)切换到0
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
这些动作会触发一些魔法来完成所有必要的事情。
注意:要查询当前值,请使用以下命令:
代码语言:javascript复制reg query "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server" /v fDenyTSConnections
像这样运行这些服务将在 3389/TCP 端口上启动一个监听器,可以在netstat
输出中找到
3389/TCP 端口上的监听器
看起来不错,对吧?有趣的是,您可以简单地将fDenyTSConnections
注册表项切换回1
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server" /v fDenyTSConnections /t REG_DWORD /d 1 /f
然后监听器关闭并且 3389/TCP 端口从 netstat 输出中消失,但由于所有服务仍在运行并且必要的端口(139/TCP、445/TCP 和动态端口范围)已打开,您可以隐藏任何用户的会话。
已建立的影子连接
我更深入一点,发现在我将fDenyTSConnections
密钥从1切换到0后哪些服务仍在运行。这是清单:
- 远程桌面服务(TermService),
- 远程桌面配置(SessionEnv),
- 远程桌面服务用户模式端口重定向器 (UmRdpService),
- 证书传播 (CertPropSvc)。
但真正需要其中的两个才能使 RDS 阴影工作:
- 远程桌面服务(TermService),
- 远程桌面配置 (SessionEnv)。
此外,我发现如果您尝试手动启动这些服务并且某些注册表项未设置为下面第 5 节中列出的适当值,则 RDS 阴影将无法工作。
让我们看看谁在关注fDenyTSConnections
key的变化。这里的关键思想是,如果有另一种方法来启动这些服务,我们可能能够独立于fDenyTSConnections
密钥隐藏会话并在 3389/TCP 端口上运行侦听器。
要完成它,请启动 Process Monitor 并设置过滤器fDenyTSConnections
并将密钥fDenyTSConnections
从1切换到0。
访问fDenyTSConnections
键值的进程列表
访问fDenyTSConnections
键值的进程有几个独特的堆栈跟踪。其中两个如下:
读取fDenyTSConnections
键值的 svchost 进程的第一个堆栈跟踪
读取fDenyTSConnections
键值的 svchost 进程的第二个堆栈跟踪
在第一个堆栈中,有趣的是(本地会话管理器服务)中有一个CPolicyMonitor
类lsm.dll
,它有两个方法PolicyMonitorWorker
,IsDenyTSConnectionsPolicy
用于监视fDenyTSConnections
键的更改。
CRemoteConnectionManager::Start
第二个堆栈跟踪中的现有调用表明它运行远程连接管理器。正如您在下面的屏幕截图中看到的,有StartRCM
一个名称与“启动远程连接管理器”太相似的注册表项。
此外,我fDenyChildConnections
在https://www.guardicore.com/2017/05/the-bondnet-army/ 上找到了一些关于另一个注册表项的信息,该注册表项与 RDP 连接有某种关系。默认情况下,此键不存在。
fDenyChildConnections
密钥相关信息
该fDenyChildConnections
键也存在于 Process Monitor 的输出中。
正如您所看到的,密钥由我们在上面第一个堆栈跟踪中看到的相同函数监控,因此在lsm.dll
.
我检查了这些注册表项中的每一个,发现它们都按预期工作。相互独立地发出以下命令(并将前一个恢复为默认值)我成功地获得了隐藏连接,而无需将 设置IsDenyTSConnections
为0并在 3389/TCP 端口上运行侦听器:
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server" /v StartRCM /t REG_DWORD /d 1 /f
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server" /v fDenyChildConnections /t REG_DWORD /d 0 /f
StartRCM
密钥设置为1时已建立的阴影连接
fDenyChildConnections
密钥设置为0时已建立的阴影连接
在 3389/TCP 端口上没有监听器的 netstat 命令输出
坚持
RDS Shadowing 技术可以获得一种持久性。
无论远程桌面服务 ( TermService
) 服务如何启动,当出现以下情况之一时,它都无法停止:
fDenyChildConnections
是0 ,IsDenyTSConnections
设置为0,StartRCM
是1。
虽然这是真的,但每次尝试停止它时都会收到以下错误:
坏处是远程桌面配置 ( SessionEnv
) 服务可以停止,如果是这样,您将在尝试隐藏会话时收到以下错误:
接口未知
另一方面,一旦主机重新启动,远程桌面配置 ( SessionEnv
) 服务将再次启动(在如上所述将其中一个键设置为适当值的情况下)。当然,如果您有特权访问,它可以随时手动启动。
此外,正如我在第 4 节中已经写过的,只有一部分 RDP 服务必须运行,因此您可以停止和禁用其余的服务,而不会对 RDP 功能产生任何影响(以防有人决定将其关闭稍后)并保持 RDS 阴影工作。这些服务是:
- 远程桌面服务用户模式端口重定向器 (
UmRdpService
), - 证书传播 (
CertPropSvc
)。
我没有对智能卡进行任何测试,所以我不知道禁用证书传播服务将如何影响用户或操作系统。
这里有几个屏幕截图证明了这一点。我所做的是禁用服务,使用 GUI 打开 RDP 并成功获得 RDP 连接。之后我断开并建立了一个阴影连接(最后一个截图)。
远程桌面服务和远程桌面配置服务状态
建立 RDP 连接
成功建立的 RDP 连接
成功建立的镜像连接
在第 2 节中,我提到如果用户锁定他们的会话,影子会话将被暂停,但如果用户使用快速用户切换功能在其解锁时直接从他们自己的会话切换到另一个帐户,这将不起作用. 在这种情况下,影子连接关闭,您会收到以下错误:
有一种方法可以通过添加以下注册表项(默认情况下不存在)来剥夺用户这个机会并隐藏他们的快速用户切换界面:
代码语言:javascript复制reg add HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem /v HideFastUserSwitching /t REG_DWORD /d 1
不利的一面是该功能也会从锁定屏幕中消失,因此用户在退出之前将无法切换到另一个帐户。
*nix 上的 RDS 阴影
就像在每个不平衡的世界中一样,*nix 用户都有可怕的消息。这体现在众所周知的实用程序(如 FreeRDP 和 rdesktop)不支持远程桌面服务阴影功能的事实中。