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