工具虽老,知识却不老。
这只是一个琐碎的细节,纯当笔记在写。如有错误,还请各位指点。
三台机器:
1. PC-1
2. PC-2
3. PC-3
非域环境(其实域环境下也类似),三台机器上 Administrator 的密码全是 123456
上面说到 “PsExec 利用某一个账号”与远程机器进行身份验证,这里的某一个账号有可能是:
(实际根据 PsExec 版本的不同,有时就算手动指定了某个账号,PsExec 依然会先尝试利用当前用户的凭据去进行身份验证)
以 Administrator 登陆 PC-1,然后:
1.psexec \PC-2 cmd.exe
没有给 psexec 指定账号密码,psexec 会利用当前用户的凭据成功从 PC-1 连接到 PC-2,并获取到了一个可以伪交互的 cmd shell。
2.随后在 cmd shell 中执行:
psexec \\PC-3 hostname
尝试利用 PC-2 的 cmd shell 去连接 PC-3,并执行 hostname,期待能够看到 hostname 命令的输出,也就是:PC-3。
但是,失败了。
我本地的错误信息是:句柄无效。
为什么会失败呢?
以 Administrator 登陆 PC-1,然后:
1.psexec \PC-2 -u administrator -p 123456 cmd.exe
虽然通过第一回测试我们知道就算不手动指定 adminstrator 账号与密码也可以连接成功,但是这里我们还是指定吧。
成功从 PC-1 连接到了 PC-2,并获取到了一个可以交互的 cmd shell。
2.随后在 cmd shell 中执行:
psexec \\PC-3 hostname
3.成功从 PC-2 连接到了 PC-3,并执行了 hostname 命令,并成功得到回显:PC-3
为什么第一回的测试中,从 PC-2 连接至 PC-3 执行命令失败了,但在第二回的测试中可以成功呢?
在我的认知中,第一回确实是应该失败的。而且我认为,如果第一回失败,那么第二回的测试也应该失败才对。因为太长时间没有过用 PsExec 了,所以我自己在看到第二回测试成功的时候,诧异了一下,它与我的认知相悖了。
PC-1 上通过 psexec \PC-2 cmd.exe 连接至 PC-2 后,我猜测 PC-2 上的 PSEXESVC 通过类似 ImpersonateNamedPipeClient 的函数 impersonate 了客户端的身份(也就是 Administrator)。后面映证了我的猜测是正确的。
impersonate 分为两个级别:
impersonation。此级别的 impersonate,使得服务端可以使用客户端的身份来访问本地资源,但是无法访问网络资源,这也被称为 SSP 的 double hop 的问题。(想了解更多的 Google "authentication double hop")
delegation。此级别的 impersonate,使得服务端可以使用客户端的身份访问本地资源以及网络资源。
在微软提供的所有 SSP 中,只有 Kerberos 是支持 delegation 级别的 impersonate 的(MSDN 里面是这么说的),而且还需要在域控上进行特别的配置才可以。
所以,我猜测 PC-2 上的 PSEXESVC 对客户端进行了 impersonation 级别的 impersonate(事实也无法进行 delegation 级别的 impersonate,因为 NTLMSSP 不支持),所以它无法访问网络资源,自然也就无法再去远程访问 PC-3。
“无法再去远程访问 PC-3” 具体体现在,在 PC-2 上尝试远程连接 PC-3 的时候,与 PC-3 进行的是空会话认证,也就是所谓的 anonymous logon,即匿名登陆:
可以看到在上图的 NTLMSSP-TYPE 3 消息中, Negotiate Anonymous 标志位被设置为 1,且 Domain name/User name/NTLM Response 处的值均为空。
第二回的测试成功了让我很诧异,我还以为我一直认为 “NTLM 无法 delegation” 这件事是错的。然后我去翻了一下 PsExec 的帮助文档,以及 PsExec 作者写的文章,才得以解惑。(PsExec 的作者是 Microsoft Azure 的 CTO!)
以下为摘录:
When you specify a username the remote process will execute in that account, and will have access to that account's network resources.
If you omit username the remote process will run in the same account from which you execute PsExec, but because the remote process is impersonating it will not have access to network resources on the remote system.
If you do specify an alternative username/password, then PsExec will send the password in clear text. This can be a security risk if unauthorized network sniffers could intercept traffic between the local and remote system.
简单翻译就是:
如果在运行 psexec 的时候,没有指定用户名与密码,则 psexec 会使用当前的身份与远程机器进行验证。验证成功后服务端会 impersonate 客户端,此时无法通过远程机器访问任何的网络资源。(这里对应的第一回的测试情况,说明我的猜测是没错的)
如果手动指定了用户名与密码,则在验证通过后,PsExec 会将账号密码以明文的方式发送至远端服务器(从 2.1 版本开始,不再是明文发送)。通过这段描述,大概能猜到在手动指定了用户名与密码的情况下,PSEXESVC 不再是利用 impersonate 来获取客户端身份,而是通过其他的方式。我想这里解释了为什么第二回的测试是成功的。
我猜测,第二回的过程应该是这样的(网上好像没有 psexec 的源代码,而且我没有逆向能力,所以只能猜测了,我估计我猜的八九不离十):
PsExec 通过将凭据发送至远程机器,避开了 NTLM 无法 delegation 的问题(也就是 double hop)的问题。如果你了解 CredSSP 的话,你会发现 PsExec 的这种做法与 CredSSP 非常相似。