-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compatibility with "Server SPN target name validation" GPO #169
Comments
Interesting, it looks like pyspnego's NTLM implementation is setting When testing this purely I see the NTLM auth message contains the SPN in the NT challenge response NtChallengeResponse:
ResponseType: NTLMv2
NTProofStr: 321303F0587F894BF528994391DAB3BE
ClientChallenge:
RespType: 1
HiRespType: 1
Reserved1: 0
Reserved2: 0
TimeStamp: '2022-03-15T10:13:11.2261824Z'
ChallengeFromClient: 471AE177EF44C84D
Reserved3: 0
AvPairs:
- AvId: MSV_AV_NB_DOMAIN_NAME (2)
Value: DOMAIN
- AvId: MSV_AV_NB_COMPUTER_NAME (1)
Value: SERVER2019
- AvId: MSV_AV_DNS_DOMAIN_NAME (4)
Value: domain.test
- AvId: MSV_AV_DNS_COMPUTER_NAME (3)
Value: SERVER2019.domain.test
- AvId: MSV_AV_DNS_TREE_NAME (5)
Value: domain.test
- AvId: MSV_AV_TIMESTAMP (7)
Value: '2022-03-15T10:13:11.2261824Z'
- AvId: MSV_AV_TARGET_NAME (9)
Value: cifs/server2019.domain.test
- AvId: MSV_AV_FLAGS (6)
Value:
raw: 2
flags:
- MIC_PROVIDED (2)
- AvId: MSV_AV_EOL (0)
Value:
Reserved4: 0 When testing further it looks like the problem is stemming from gss-ntlmssp which is used instead of the Python implementation as a GSSAPI mechanism if available. When running that I see the target name is just the hostname without the SPN. Looks like this has recently been reported and also fixed with gssapi/gss-ntlmssp#63. Will require a new release to make it's way through the various package repositories. Unfortunately there is no flag to state use the builtin Python NTLM implementation over the GSSAPI one if the latter is available as it is considered to be the source implementation for Linux. In this case if you need to use NTLM with this mode you have 3 options:
If you are able to do at least step 2 for your tests to ensure that the pyspnego NTLM implementation is all good. From what I can see it should work. |
I'm somewhat surprised it sends that, the value here is somewhat undocumented but it's mostly used for loopback authentication. I don't think it really applies here. |
Would you be able to test with gssntlssmp from the main branch where this should be fixed? |
Yep, was planning on building the main branch and testing that my code correctly passes the SPN to gss-ntlmssp sometime tomorrow. Will also enable that policy myself to verify the settings work with it as well. |
Thanks for the information – I just tried latest gss-ntlmssp from Git, and it indeed sends the full I'm guessing this is because it now also sets the If I uninstall gss-ntlmssp and let pyspnego do things on its own, NTLM indeed works. |
This is interesting, I tried to be conservative and not claim anything trusted because it was unclear to me what that flag meant. |
I would guess that it means the SPN was obtained from the server itself – there's a field in "negHints" where modern systems send On the other hand, if the SPN was directly derived from the user-specified URL or UNC path, then it would make sense for it to be "trusted", following SSL/TLS logic. |
That would seem odd, my thinking was that untrusted may be a name derived by a reverse DNS query for example... but that is one reason why I set untrusted I did not want to claim anything that I was not sure I should claim. Documentation is something I really need to be sure I can set this appropriately. And I would like to do it before making a release. |
I've briefly seen it before but cannot remember how it is done through SSPI but it makes sense that having it set also still fails. Let me do some digging and I'll get back to you. |
Closing as per the resolution in gssapi/gss-ntlmssp#67. Have tested the proposed fix and things work just fine. |
This is somewhat more of a pyspnego issue, but it involves pysmbprotocol passing it the correct information, so I ended up filing it here.
Windows servers have a Server SPN target name validation security policy available. When enabled, it causes SMB servers to reject authentication if the client claims it's connecting to a different hostname than what the server expects. With Kerberos this is already business as usual (either the client wouldn't be able to get tickets for the wrong SPN, or the server would be unable to decrypt the tickets), but the GPO extends this protection also to NTLM, in order to prevent NTLM relay attacks.
Now none of my python-smbprotocol scripts use NTLM, so this is not an issue for me, but I still decided to test it anyway and found that even when connecting to an allowed server name (i.e. where Samba's smbclient would work), python-smbprotocol nevertheless gets an "Access denied":
smbprotocol.exceptions.AccessDenied: Received unexpected status from the server: A process has requested access to an object but has not been granted those access rights. (3221225506) STATUS_ACCESS_DENIED: 0xc0000022
Specifically, the difference seems to be that with Samba (which works), the
MSV_AV_TARGET_NAME
field in AvPairs includes thecifs/
service name like a Kerberos principal would, whereas with python-smbprotocol it does not. [MS-NLMP] seems to confirm that "ClientSuppliedTargetName" is a SPN, so the caller needs to supply the correct service name and not just the hostname.Samba also sends MSV_AV_SINGLE_HOST but I don't know if it's related.
To enable strict SPN validation on a SMB server:
HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
Name:
SmbServerNameHardeningLevel
Value: REG_DWORD,
1
(validate target only if client sends it) or2
(validate and require clients to send it)The place to configure "allowed" aliases seems to be
SrvAllowedServerNames
REG_MULTI_SZ at the same location.The text was updated successfully, but these errors were encountered: