Ideas (other than just mandetory schannel) for ZeroLogin CVE-2020-1472

Stefan Metzmacher metze at samba.org
Wed Sep 16 10:01:10 UTC 2020


Am 16.09.20 um 08:05 schrieb Andrew Bartlett via samba-technical:
> On Wed, 2020-09-16 at 17:51 +1200, Andrew Bartlett via samba-technical
> wrote:
>> This isn't on the bug
>> https://bugzilla.samba.org/show_bug.cgi?id=14497
>> because it isn't at that point yet, and isn't a MR as I've not even
>> compiled it, but ideas (done with Gary) for mitigation for those who
>> must run with schannel are:
>>
>> Ensure that the password set via ServerSetPassword2 is of non-zero
>> length.
>>
>> Check the password does not have zero bytes in it.
>>
>> Check that the challenge in ServerAuthenticate3 does not have
>> repeating
>> patterns in the first 3 bytes and repeating 0s in the computed
>> response.
>>
>> This should make false positives pretty rare, while working with the
>> failure mode of the cipher.
>>
>> See https://www.secura.com/pathtoimg.php?id=2055 for a really
>> readable
>> description of the issue.
>>
>> I'm going home shortly but will keep looking at this and will be
>> available tonight.
>>
>> I think Samba 4.13 should ship without the option to turn off
>> schannel
>> - just remove it, assuming we can make the tests still go.
> 
> We could also make ServerSetPassword2 absolutely require schannel for
> 'server schannel = auto', impacted servers would still be able to
> ServerAuthenticate3, just not rotate their passwords.

I guess we could also force schannel in dcesrv_netr_creds_server_step_check()
for all types but SEC_CHAN_WKSTA.

This together with your basic password complexity checks on ServerPasswordSet*
and requiring SCHANNEL and PRIVACY on dcesrv_netr_ServerGetTrustInfo()/dcesrv_netr_ServerTrustPasswordsGet()
should be good enough as initial mitigation.

The first attempt is attached. I compiles but needs testing and more debug messages and documentation.
It would also be great if someone could apply similar changes to source3/rpc_server.

metze
-------------- next part --------------
From fb0f8a216ea9189581257fd7113d61423facf816 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 16 Sep 2020 10:18:45 +0200
Subject: [PATCH 1/4] CVE-2020-1472(ZeroLogin): s4:rpc_server: require schannel
 for non workstation trusts

This means domain trust and domain controller accounts are protected,
even if "server schannel = auto" is used.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 34 +++++++++++++------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 0ab55afeab0d..1f374f53522d 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -624,27 +624,39 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 {
 	NTSTATUS nt_status;
 	int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
-	bool schannel_global_required = (schannel == true);
+	bool schannel_required = (schannel == true);
+	struct netlogon_creds_CredentialState *creds = NULL;
+	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
 
-	if (schannel_global_required) {
-		enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
+	dcesrv_call_auth_info(dce_call, &auth_type, NULL);
+
+	nt_status = schannel_check_creds_state(mem_ctx,
+					       dce_call->conn->dce_ctx->lp_ctx,
+					       computer_name,
+					       received_authenticator,
+					       return_authenticator,
+					       &creds);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		ZERO_STRUCTP(return_authenticator);
+		return nt_status;
+	}
 
-		dcesrv_call_auth_info(dce_call, &auth_type, NULL);
+	if (creds->secure_channel_type != SEC_CHAN_WKSTA) {
+		schannel_required = true;
+	}
 
+	if (schannel_required) {
 		if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
 			DBG_ERR("[%s] is not using schannel\n",
 				computer_name);
+			TALLOC_FREE(creds);
+			ZERO_STRUCTP(return_authenticator);
 			return NT_STATUS_ACCESS_DENIED;
 		}
 	}
 
-	nt_status = schannel_check_creds_state(mem_ctx,
-					       dce_call->conn->dce_ctx->lp_ctx,
-					       computer_name,
-					       received_authenticator,
-					       return_authenticator,
-					       creds_out);
-	return nt_status;
+	*creds_out = creds;
+	return NT_STATUS_OK;
 }
 
 /*
-- 
2.17.1


From d1562cf9b8f0d9acc4056f13cbff40a74d247cd5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 16 Sep 2020 10:18:45 +0200
Subject: [PATCH 2/4] CVE-2020-1472(ZeroLogin): s4:rpc_server: require schannel
 if a workstation negotiated it

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 1f374f53522d..bb013f88f2a5 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -644,6 +644,12 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 	if (creds->secure_channel_type != SEC_CHAN_WKSTA) {
 		schannel_required = true;
 	}
+	if (creds->negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
+		/*
+		 * The client asked for it, so we should require it.
+		 */
+		schannel_required = true;
+	}
 
 	if (schannel_required) {
 		if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
-- 
2.17.1


From 4833014075125f01cde63f95c215261e4d9360f6 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 16 Sep 2020 10:53:41 +0200
Subject: [PATCH 3/4] CVE-2020-1472(ZeroLogin): s4:rpc_server: require PRIVACY
 for netr_ServerGetTrustInfo/netr_ServerTrustPasswordsGet

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 24 ++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index bb013f88f2a5..8055983c0694 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -618,6 +618,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca
 static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call,
 						    TALLOC_CTX *mem_ctx,
 						    const char *computer_name,
+						    enum dcerpc_AuthLevel min_auth_level,
 						    struct netr_Authenticator *received_authenticator,
 						    struct netr_Authenticator *return_authenticator,
 						    struct netlogon_creds_CredentialState **creds_out)
@@ -626,9 +627,20 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 	int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx);
 	bool schannel_required = (schannel == true);
 	struct netlogon_creds_CredentialState *creds = NULL;
+	uint16_t opnum = dce_call->pkt.u.request.opnum;
 	enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
+	enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
 
-	dcesrv_call_auth_info(dce_call, &auth_type, NULL);
+	dcesrv_call_auth_info(dce_call, &auth_type, &auth_level);
+
+	if (auth_level < min_auth_level) {
+		DBG_ERR("[%s] opnum[%u] called with "
+			"auth_level[%u] < min_auth_level[%u]\n",
+			computer_name, opnum,
+			auth_level, min_auth_level);
+		ZERO_STRUCTP(return_authenticator);
+		return NT_STATUS_ACCESS_DENIED;
+	}
 
 	nt_status = schannel_check_creds_state(mem_ctx,
 					       dce_call->conn->dce_ctx->lp_ctx,
@@ -684,6 +696,7 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet(struct dcesrv_call_state *dce_call
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_NONE,
 							r->in.credential, r->out.return_authenticator,
 							&creds);
 	NT_STATUS_NOT_OK_RETURN(nt_status);
@@ -750,6 +763,7 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_NONE,
 							r->in.credential, r->out.return_authenticator,
 							&creds);
 	NT_STATUS_NOT_OK_RETURN(nt_status);
@@ -1425,6 +1439,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_NONE,
 							r->in.credential,
 							r->out.return_authenticator,
 							&state->creds);
@@ -1486,6 +1501,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogon(struct dcesrv_call_state *dce_call, TA
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_NONE,
 							r->in.credential,
 							r->out.return_authenticator,
 							&state->creds);
@@ -2125,6 +2141,7 @@ static NTSTATUS dcesrv_netr_LogonGetCapabilities(struct dcesrv_call_state *dce_c
 	status = dcesrv_netr_creds_server_step_check(dce_call,
 						     mem_ctx,
 						     r->in.computer_name,
+						     DCERPC_AUTH_LEVEL_NONE,
 						     r->in.credential,
 						     r->out.return_authenticator,
 						     &creds);
@@ -2379,6 +2396,7 @@ static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_cal
 	status = dcesrv_netr_creds_server_step_check(dce_call,
 						     mem_ctx,
 						     r->in.computer_name,
+						     DCERPC_AUTH_LEVEL_NONE,
 						     r->in.credential,
 						     r->out.return_authenticator,
 						     &creds);
@@ -2801,6 +2819,7 @@ static NTSTATUS dcesrv_netr_NetrLogonSendToSam(struct dcesrv_call_state *dce_cal
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_NONE,
 							r->in.credential,
 							r->out.return_authenticator,
 							&creds);
@@ -4021,6 +4040,7 @@ static NTSTATUS dcesrv_netr_GetForestTrustInformation(struct dcesrv_call_state *
 	status = dcesrv_netr_creds_server_step_check(dce_call,
 						     mem_ctx,
 						     r->in.computer_name,
+						     DCERPC_AUTH_LEVEL_NONE,
 						     r->in.credential,
 						     r->out.return_authenticator,
 						     &creds);
@@ -4111,6 +4131,7 @@ static NTSTATUS dcesrv_netr_ServerGetTrustInfo(struct dcesrv_call_state *dce_cal
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_PRIVACY,
 							r->in.credential,
 							r->out.return_authenticator,
 							&creds);
@@ -4304,6 +4325,7 @@ static NTSTATUS dcesrv_netr_DsrUpdateReadOnlyServerDnsRecords(struct dcesrv_call
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
+							DCERPC_AUTH_LEVEL_NONE,
 							r->in.credential,
 							r->out.return_authenticator,
 							&creds);
-- 
2.17.1


From 52b3d5d463cc7e1ef9920cee469702e47c27cda7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 16 Sep 2020 10:56:53 +0200
Subject: [PATCH 4/4] CVE-2020-1472(ZeroLogin): s4:rpc_server: support "server
 require schannel:WORKSTATION$ = no"

This allows to add expections for individual workstations, when using "server schannel = yes".
"server schannel = auto" is very insecure and will be removed soon.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 8055983c0694..71f3bf589156 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -653,6 +653,12 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
 		return nt_status;
 	}
 
+	schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
+					    NULL,
+					    "server require schannel",
+					    creds->account_name,
+					    schannel_required);
+
 	if (creds->secure_channel_type != SEC_CHAN_WKSTA) {
 		schannel_required = true;
 	}
-- 
2.17.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20200916/34c5a1b3/signature.sig>


More information about the samba-technical mailing list