隐式远程桌面服务——超越隐藏会话

  • A+

thumb.jpg

​在某些情况下,我们需要在不把客户踢出会话的前提下查看客户的屏幕,以此来实现一些经过验证的屏幕截图或着访问打开的GUI应用程序窗口,其中包含合法用户通过RDP(Remote Desktop Protocol)与您连接时横向移动的秘密信息。

​市场上有许多第三方软件(例如VNC,radmin,TeamViewer等)可以实现该功能,但是它还涉及其他操作,例如二进制传输,软件安装等。而且,这些操作不仅过于复杂,还会在远程主机上留下很多垃圾。

​幸运的是,Windows系统有一个被忽略或遗忘的好用的内置功能(作为远程桌面协议的一部分)。它称为隐式远程桌面服务。

​该功能有两个版本。由于旧版的隐式远程桌面服务与最新版本不兼容,并且系统管理员的网站和论坛上也有数篇对此介绍的文章,所以不再作过多描述,仅用几句话作为历史介绍。

​在Windows的早期版本中,shadow.exe文件使用户可以使用隐式远程桌面服务技术连接到远程主机。很快,这就成为了mstsc(Microsoft terminal services client)实用程序及其 /shadow 参数的前身。它是Windows Server 2003中引入的,并且在许多Windows版本中都可用。

​此外,有两个GUI应用程序,它们起相同的作用:Windows Server 2003以后出现的终端服务管理(TSAdmin)和远程桌面服务管理器(RDSM),后者是远程服务器管理工具(RSAT)的一部分,它替代了Windows Server 2012上的TSAdmin。

​RDS Shadowing版本之间的主要区别在于,对于旧版本,必须先建立RDP连接才能在远程主机上建立会话,然后才能在该主机上隐藏其他人的会话。使用最新版本,您可以通过自己主机的控制台在远程主机上隐藏用户的会话。

​现在,我们来了解最新版本。从Windows 7开始的任何现代Microsoft Windows版本都可以用于通过隐藏会话功能连接到远程主机,但是其中一些需要执行额外的步骤,并且在以下情况下只能使用一些限制。

0x01前提

基于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服务。

​第三,除了软件和服务要求之外,还必须对防火墙规则进行一些额外的更改。隐式远程桌面服务功能不使用TCP 3389端口(RDP),而是使用TCP 445端口(SMB)和临时端口,也称为动态端口范围(RPC)。

这些更改可以通过添加新的自定义规则或启用以下内置规则来完成:

  • 第一条规则称为文件和打印机共享(SMB-In),它允许连接到TCP 445端口;
  • 第二条称为“远程桌面-隐式(TCP-In)”。它仅允许%SystemRoot%\system32\RdpSa.exe二进制文件处理任何本地TCP端口上的入站连接。

注:Windows上的动态端口范围通常包括TCP 49152到65535端口。可以通过发出以下命令来确定当前值:

powershell
netsh int ipv4 show dynamicport tcp

详细描述的命令qwinsta和quser还要求打开TCP 445端口,否则会出现以下错误:

powershell
C:\>qwinsta /server:{ADDRESS}
Error 1722 getting sessionnames
Error [1722]:The RPC server is unavailable.

注:如果隐式连接似乎成功,但没有弹出带有隐式会话的窗口,请检查防火墙规则(必须打开动态端口或启用影子规则)。

0x02建立隐式连接

使用远程桌面连接客户端(mstsc)实用程序内置的功能来隐藏会话的最简单的命令如下所示:

powershell
mstsc /v:{ADDRESS} /shadow:{SESSION_ID}

注:

  • /v 参数用于指定{ADDRESS}值,该值可以是远程主机的IP地址或主机名;
  • /shadow 参数用于指定{SESSION_ID}值,该值是隐藏对象的会话ID。

有关mstsc实用程序的所有可用参数的详细信息,可用命令

powershell
mstsc /?

因此,根据上面命令的参数,您必须知道远程用户的会话ID才能建立隐式连接。

若要列出远程主机上的现有会话,可以使用qwinsta或quser命令(两者等效),如下所示:

powershell
qwinsta /server:{ADDRESS}
quser session /server:{ADDRESS}

​有一件有趣的事,如果用户锁定屏幕(Win + L)或切换到另一个用户的帐户(仅从屏幕锁定状态切换时,详情参阅第5节)或弹出UAC(User Account Control)提示,则带有隐式会话的窗口将自动切换到暂停状态(屏幕上出现两个平行条纹),直到用户回来。当用户返回时,带有隐式会话的窗口将自动取消暂停。

pause1.png

​还应注意,即使每个显示器具有不同的分辨率,最新版本的RDS Shadowing也可以很好地支持远程主机上的多显示器设置。

multimon.png

0x03滥用隐藏注册表项和NoConsentPrompt参数

我还没有提到Shadow注册表项,因为默认情况下它不存在。

shadowkey.png

​在这种情况下,其行为与将键值设置为1时相同(如下所述)。换句话说,隐藏对象必须显式地授予权限以允许其会话被隐藏。

​为了能够在没有权限的情况下对其进行隐藏处理,您必须有意识地使用组策略覆盖它,例如,使用名为“本地组策略编辑器”(gpedit.msc)的GUI应用程序设置“设置远程桌面服务用户会话的远程控制规则”策略值允许未经用户许可的会话隐藏。它位于本地计算机策略→计算机配置→管理模板→Windows组件→远程桌面服务→远程桌面会话主机→连接。

gpedit.png

它也可以通过以下命令的命令行解释器手动设置:

powershell
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v Shadow /t REG_DWORD /d 4

/d参数的值为以下之一:

  • 0 –不允许远程控制;
  • 1 –在用户许可下完全控制;
  • 2 –无需用户许可的完全控制;
  • 3 –在用户许可下查看会话;
  • 4 –无需用户许可查看会话。

选择“未配置”值或“禁用”值将删除Shadow注册表项。

​完全控制还允许在“查看会话”模式下进行连接,但是为了避免错误指定 /control参数的情况,将Shadow值设置为4会更安全。

注:要获取Shadow键的当前值,请发出以下命令:

powershell
reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v Shadow

删除Shadow键类型

powershell
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v Shadow /f

在远程主机上定义“Shadow”参数,可以在没有用户同意的情况下隐藏会话,如下所示:

powershell
mstsc /v:{ADDRESS} /shadow:{SESSION_ID} /noconsentprompt /prompt

  • /v 参数可以指定{ADDRESS}值,它是远程主机的IP地址或主机名;
  • /shadow 参数用于指定{SESSION_ID}值,该值是隐藏对象的会话ID;
  • /noconsentprompt 参数允许绕过隐藏对象的许可,并在未经他们同意的情况下隐藏他们的会话;
  • /prompt 参数用于指定用户连接到远程主机的凭据。

无需在弹出窗口中不断键入用户凭据的另一种方法是使用runas命令,如下所示:

powershell
runas /netonly /noprofile /user:{USERNAME} cmd

并在新的命令行窗口中运行mstsc实用程序

powershell
mstsc /v:{ADDRESS} /shadow:{SESSION_ID} /noconsentprompt

同样适用于qwinsta和quser。

有时您可能会遇到以下错误:

accessisdenied.png

这可能意味着某些事情,但在某些情况下这意味着:

  • 远程主机上不存在发出当前命令的上下文的用户;
  • 指定的用户凭证错误;
  • 您正试图在没有权限情况下隐藏会话。

对于qwinsta,此响应几乎相同:

powershell
C:\>qwinsta /server:{ADDRESS}
Error 5 getting sessionnames
Error [5]:Access is denied.

在工作组环境中,如果该帐户也存在于远程主机上,则可以使用任何本地帐户。

​此外,如果您尝试使用远程主机上的非特权用户帐户隐藏会话(或使用qwinsta或quser列出会话),则您只能连接到与该用户相关的会话(仅列出相关会话的信息)。

​如果使用非RID 500管理员帐户,但是在远程主机上启用了UAC远程限制,您将得到相同的响应,更确切地说,这意味着LocalAccountTokenFilterPolicy注册表项设置为0或该注册表项不存在(默认)。

​第一个截屏中,启用了UAC远程限制,第二个截屏中禁用了它

uac1e1603979082741.png

uac2e1603979180870.png

​这是一种众所周知的安全机制,当用户远程连接时,该机制会去除管理员token。详情参照https://docs.microsoft.com/en-us/troubleshoot/windows-server/windows-security/user-account-control-and-remote-restriction.

要禁用它,请使用以下命令将值更改为1:

powershell
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f

注:要获取LocalAccountTokenFilterPolicy键的当前值,请发出以下命令:

powershell
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy

删除LocalAccountTokenFilterPolicy键值类型

powershell
reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /f

​更重要的是,如果幸运的话,在远程主机上启用了内置RID 500管理员帐户(默认情况下已禁用),则可以用它隐藏会话,因为LocalAccountTokenFilterPolicy键值不会影响它。

​如果将其设置为1,则还有另一个FilterAdministratorToken注册表项可能会限制此帐户,但是默认情况下,它设置为0。

​因此,在工作组(以及域)环境中,本地管理员是唯一可以访问其他本地用户会话的本地用户(如果LocalAccountTokenFilterPolicy和FilterAdministratorToken注册表项设置为适当的值)。

​我不知道什么时候可能有用,但是可以通过mstsc命令简单地增加{SESSION_ID}值来枚举存在的会话

powershell
mstsc /v:{ADDRESS} /shadow:{SESSION_ID}

如果指定会话不存在,则会发生以下错误:

sessionerror.png

或者,如果存在会话,但没有人连接到该会话,或者您没有必需的权限,则会出现以下错误之一:

sessionnotconnected.png

accessisdenied 1.png

否则,将授予您权限,并打开查看器的窗口

sessionoke1603979398341.png

0x04滥用StartRCM和fDenyChildConnections注册表项

​在“前提”部分中已提到,要成功隐藏会话,必须运行远程桌面服务,否则会发生以下错误:

shadownoservices.png

启动它们的最简单方法是使用图形用户界面,如下所示:

rdp.png

或手动将fDenyTSConnections注册表项从1(默认)切换为0

powershell
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f

这些行为会触发某种魔效,可以完成所有必要的操作。

注:使用以下命令查询当前值:

powershell
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections

​像这样运行这些服务将在TCP 3389端口上启动监听器,该端口可在netstat输出中找到

netstate1603979995792.png
看起来不错吧?有趣的是,您可以简单地将fDenyTSConnections注册表项切换回1

powershell
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 1 /f

​然后关闭监听器,随后TCP 3389端口就不会再出现在netstat的输出中,但由于所有服务都仍在运行并且必要的端口(TCP 139,TCP 445和动态端口范围)都处于开放状态,所以您可以隐藏任何用户的会话。

fdenyts1.png

​在将fDenyTSConnections键从1切换为0后,我进行了更深入的研究,发现部分服务仍在运行。列表如下:

  • 远程桌面服务(TermService),
  • 远程桌面配置(SessionEnv),
  • 远程桌面服务UserMode端口重定向器(UmRdpService),
  • 证书传播(CertPropSvc)。

但实际上只有其中两个对RDS Shadowing起作用是必需的:

  • 远程桌面服务(TermService),
  • 远程桌面配置(SessionEnv)。

​另外,我发现,如果您尝试手动启动这些服务,并且某些注册表项未设置为下面第5节中列出的适当值,则隐式RDS将无法工作。

​让我们看看谁在监视fDenyTSConnections键的更改。这里的关键思想是,如果有另一种方法来启动这些服务,我们将可能能够独立于fDenyTSConnections键和TCP 3389端口上运行的监听器来隐藏会话。

​为此,请启动Process Monitor并将过滤器设置为fDenyTSConnections,并将键fDenyTSConnections从1切换为0。

procmon1.png

​访问fDenyTSConnections键值的进程有多个唯一的堆栈记录。其中两个是以下内容:

procmon2.png

procmon3.png

​在第一个堆栈中,有趣的是lsm.dll(本地会话管理器服务)中有CPolicyMonitor类,它有两个监视对fDenyTSConnections项的更改的方法PolicyMonitorWorker和IsDenyTSConnectionsPolicy。

​第二个堆栈记录中存在的CRemoteConnectionManager :: Start调用表明它正在运行远程连接管理器。如您在以下屏幕截图中所见,有一个StartRCM注册表项,其名称与“启动远程连接管理器”太相似。

regterminal.png

​此外,我在https://www.guardicore.com/2017/05/the-bondnet-army/发现了有关另一个名为fDenyChildConnections的注册表项的一些信息,该信息与RDP连接有某种联系。此键默认不存在。

fdenychild.png

fDenyChildConnections键在Process Monitor的输出中也存在。

procmon5.png

​如您所见,该键由我们在上面的第一个堆栈记录中看到的相同函数监听,因此在lsm.dll中有一些与此键相关的验证检查。

procmon4.png

​我检查了每个注册表项,发现它们都按预期工作。彼此独立地发出以下命令(并将前一个命令还原为默认值),我成功获得了隐藏的连接,而无需将IsDenyTSConnections设置为0并在TCP 3389端口上运行监听器:

powershell
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v StartRCM /t REG_DWORD /d 1 /f
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyChildConnections /t REG_DWORD /d 0 /f

startrcm1e1603979464351.png

child0e1603979500186.png

netstatnolistener2.png

0x05持久性

隐式RDS技术可能会获得某种持久性。

无论如何启动远程桌面服务(TermService)服务,在满足以下条件之一时就无法停止它:

  • fDenyChildConnections 值为0,
  • IsDenyTSConnections 值为 0,
  • StartRCM 值为 1.

这是真的,每次尝试停止它时,都会出现以下错误:

rdpservices.png

​糟糕的是,可以停止远程桌面配置(SessionEnv)服务,如果这样,在尝试隐藏会话时会收到以下错误:

shadowSessionEnvdisabled.png

​另一方面,一旦主机重新启动,则远程桌面配置(SessionEnv)服务将再次启动(在其中一个键如上所述设置为适当值的条件下)。当然,如果您具有特权访问权限,则可以随时手动启动它。

​而且,正如我在第4节中已经写过的那样,RDP服务中只有一部分必须正在运行,因此您可以停止并禁用其余部分,而不会影响RDP功能(以防有人后续打开它),并保持RDS Shadowing正常运行。服务包括:

  • 远程桌面服务用户模式端口重定向器(UmRdpService),
  • 证书传播(CertPropSvc)。

​我没有使用智能卡进行任何测试,因此我不知道禁用证书传播服务将会怎么影响用户或操作系统。

​这几个截图证明了这一点。我所做的是禁用了服务,使用GUI打开RDP并成功建立了RDP连接。之后,我断开连接并建立了隐式连接(最后一个屏幕截图)。

rdpservicesdisabled2.png

rdpisok2.png

rdpisoke1603979656629.png

rdpservicesdisablede1603979707492.png

​在第2节中,我已经提到过,如果用户锁定了会话,则隐藏会话将被暂停,但是如果用户使用快速用户切换功能在解锁时直接从自己的会话中切换到另一个帐户,则该会话将不起作用。在这种情况下,隐式连接已关闭,并且您收到以下错误:

disc.png

​通过添加以下注册表项(默认情况下,该注册表项不存在),可以使用户消除这种可能并向他们隐藏“快速用户切换”界面:

powershell
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v HideFastUserSwitching /t REG_DWORD /d 1

​不好的是,该功能也从锁定屏幕上消失了,因此,在用户退出之前,用户将无法切换到另一个帐户。

0x06 *nix上的隐式RDS

​就像在每个不平衡的世界中一样,对于*nix用户来说,这是一个可怕的消息。这体现在以下事实中:著名的实用程序(例如FreeRDP和rdesktop)不支持远程桌面服务隐藏功能。

​可以在GitHub上这些项目的相应问题页面上找到更多信息:

==本文译自:https://swarm.ptsecurity.com/remote-desktop-services-shadowing/==
==原作者:Roman Maximov==