1843 lines
63 KiB
Diff
1843 lines
63 KiB
Diff
|
|
From 84b8910da08dfa26440405f5e3916f222801859e Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:04:57 +0200
|
||
|
|
Subject: [PATCH 01/19] CVE-2020-1472(ZeroLogon): libcli/auth: add
|
||
|
|
netlogon_creds_random_challenge()
|
||
|
|
|
||
|
|
It's good to have just a single isolated function that will generate
|
||
|
|
random challenges, in future we can add some logic in order to
|
||
|
|
avoid weak values, which are likely to be rejected by a server.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
libcli/auth/credentials.c | 6 ++++++
|
||
|
|
libcli/auth/proto.h | 2 ++
|
||
|
|
2 files changed, 8 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
|
||
|
|
index c541eeff470..46259f39306 100644
|
||
|
|
--- a/libcli/auth/credentials.c
|
||
|
|
+++ b/libcli/auth/credentials.c
|
||
|
|
@@ -33,6 +33,12 @@
|
||
|
|
#include <gnutls/gnutls.h>
|
||
|
|
#include <gnutls/crypto.h>
|
||
|
|
|
||
|
|
+void netlogon_creds_random_challenge(struct netr_Credential *challenge)
|
||
|
|
+{
|
||
|
|
+ ZERO_STRUCTP(challenge);
|
||
|
|
+ generate_random_buffer(challenge->data, sizeof(challenge->data));
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
|
||
|
|
const struct netr_Credential *in,
|
||
|
|
struct netr_Credential *out)
|
||
|
|
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
|
||
|
|
index 88f4a7c6c50..396484a5437 100644
|
||
|
|
--- a/libcli/auth/proto.h
|
||
|
|
+++ b/libcli/auth/proto.h
|
||
|
|
@@ -13,6 +13,8 @@
|
||
|
|
|
||
|
|
/* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c */
|
||
|
|
|
||
|
|
+void netlogon_creds_random_challenge(struct netr_Credential *challenge);
|
||
|
|
+
|
||
|
|
NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
|
||
|
|
struct netr_LMSessionKey *key);
|
||
|
|
NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 3d9e8bd6735272b528fc10c7d8289044870229d5 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:07:30 +0200
|
||
|
|
Subject: [PATCH 02/19] CVE-2020-1472(ZeroLogon): s4:torture/rpc: make use of
|
||
|
|
netlogon_creds_random_challenge()
|
||
|
|
|
||
|
|
This will avoid getting flakey tests once our server starts to
|
||
|
|
reject weak challenges.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source4/torture/rpc/lsa.c | 2 +-
|
||
|
|
source4/torture/rpc/netlogon.c | 34 ++++++++++++----------------------
|
||
|
|
2 files changed, 13 insertions(+), 23 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c
|
||
|
|
index 548ebf8a090..0b1346e055a 100644
|
||
|
|
--- a/source4/torture/rpc/lsa.c
|
||
|
|
+++ b/source4/torture/rpc/lsa.c
|
||
|
|
@@ -2872,7 +2872,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
"ServerReqChallenge failed");
|
||
|
|
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
|
||
|
|
index 65188d2dc85..826793717e7 100644
|
||
|
|
--- a/source4/torture/rpc/netlogon.c
|
||
|
|
+++ b/source4/torture/rpc/netlogon.c
|
||
|
|
@@ -160,7 +160,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
"ServerReqChallenge failed");
|
||
|
|
@@ -229,7 +229,7 @@ bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tct
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
"ServerReqChallenge failed");
|
||
|
|
@@ -324,7 +324,7 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
"ServerReqChallenge failed");
|
||
|
|
@@ -396,7 +396,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
"ServerReqChallenge failed");
|
||
|
|
@@ -1283,7 +1283,7 @@ static bool test_ServerReqChallengeGlobal(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1372,7 +1372,7 @@ static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1461,7 +1461,7 @@ static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1551,7 +1551,7 @@ static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1643,8 +1643,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1_random;
|
||
|
|
r.out.return_credentials = &credentials_discard;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1_random.data,
|
||
|
|
- sizeof(credentials1_random.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1_random);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1656,7 +1655,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1667,16 +1666,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1_random;
|
||
|
|
r.out.return_credentials = &credentials_discard;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1_random.data,
|
||
|
|
- sizeof(credentials1_random.data));
|
||
|
|
-
|
||
|
|
- r.in.server_name = NULL;
|
||
|
|
- r.in.computer_name = "CHALTEST3";
|
||
|
|
- r.in.credentials = &credentials1_random;
|
||
|
|
- r.out.return_credentials = &credentials_discard;
|
||
|
|
-
|
||
|
|
- generate_random_buffer(credentials1_random.data,
|
||
|
|
- sizeof(credentials1_random.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1_random);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r),
|
||
|
|
"ServerReqChallenge failed on b1");
|
||
|
|
@@ -1752,7 +1742,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx,
|
||
|
|
r.in.credentials = &credentials1;
|
||
|
|
r.out.return_credentials = &credentials2;
|
||
|
|
|
||
|
|
- generate_random_buffer(credentials1.data, sizeof(credentials1.data));
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
|
||
|
|
torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
"ServerReqChallenge");
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 8cf3efad0e15c3b001cc23d1e1280a91878f778d Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:08:38 +0200
|
||
|
|
Subject: [PATCH 03/19] CVE-2020-1472(ZeroLogon): libcli/auth: make use of
|
||
|
|
netlogon_creds_random_challenge() in netlogon_creds_cli.c
|
||
|
|
|
||
|
|
This will avoid getting rejected by the server if we generate
|
||
|
|
a weak challenge.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
libcli/auth/netlogon_creds_cli.c | 3 +--
|
||
|
|
1 file changed, 1 insertion(+), 2 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
|
||
|
|
index 407cb471cbc..12cb3149ff6 100644
|
||
|
|
--- a/libcli/auth/netlogon_creds_cli.c
|
||
|
|
+++ b/libcli/auth/netlogon_creds_cli.c
|
||
|
|
@@ -1177,8 +1177,7 @@ static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
|
||
|
|
|
||
|
|
TALLOC_FREE(state->creds);
|
||
|
|
|
||
|
|
- generate_random_buffer(state->client_challenge.data,
|
||
|
|
- sizeof(state->client_challenge.data));
|
||
|
|
+ netlogon_creds_random_challenge(&state->client_challenge);
|
||
|
|
|
||
|
|
subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
|
||
|
|
state->binding_handle,
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 2f21d4bd6c68016b1e9c737dc6614131afa2181d Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:10:53 +0200
|
||
|
|
Subject: [PATCH 04/19] CVE-2020-1472(ZeroLogon): s3:rpc_server:netlogon: make
|
||
|
|
use of netlogon_creds_random_challenge()
|
||
|
|
|
||
|
|
This is not strictly needed, but makes things more clear.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source3/rpc_server/netlogon/srv_netlog_nt.c | 3 +--
|
||
|
|
1 file changed, 1 insertion(+), 2 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
index 52b17c10e61..516bbd7f6a8 100644
|
||
|
|
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
@@ -840,8 +840,7 @@ NTSTATUS _netr_ServerReqChallenge(struct pipes_struct *p,
|
||
|
|
|
||
|
|
pipe_state->client_challenge = *r->in.credentials;
|
||
|
|
|
||
|
|
- generate_random_buffer(pipe_state->server_challenge.data,
|
||
|
|
- sizeof(pipe_state->server_challenge.data));
|
||
|
|
+ netlogon_creds_random_challenge(&pipe_state->server_challenge);
|
||
|
|
|
||
|
|
*r->out.return_credentials = pipe_state->server_challenge;
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From b4df5225f750e686f742466e28f13c55a261674f Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:10:53 +0200
|
||
|
|
Subject: [PATCH 05/19] CVE-2020-1472(ZeroLogon): s4:rpc_server:netlogon: make
|
||
|
|
use of netlogon_creds_random_challenge()
|
||
|
|
|
||
|
|
This is not strictly needed, but makes things more clear.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source4/rpc_server/netlogon/dcerpc_netlogon.c | 3 +--
|
||
|
|
1 file changed, 1 insertion(+), 2 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
index 0ab55afeab0..7d1b9db0b86 100644
|
||
|
|
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
@@ -90,8 +90,7 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
|
||
|
|
|
||
|
|
pipe_state->client_challenge = *r->in.credentials;
|
||
|
|
|
||
|
|
- generate_random_buffer(pipe_state->server_challenge.data,
|
||
|
|
- sizeof(pipe_state->server_challenge.data));
|
||
|
|
+ netlogon_creds_random_challenge(&pipe_state->server_challenge);
|
||
|
|
|
||
|
|
*r->out.return_credentials = pipe_state->server_challenge;
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 18639a64e81866767eaf3e4ea118d932e1cf0d0c Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:15:26 +0200
|
||
|
|
Subject: [PATCH 06/19] CVE-2020-1472(ZeroLogon): libcli/auth: add
|
||
|
|
netlogon_creds_is_random_challenge() to avoid weak values
|
||
|
|
|
||
|
|
This is the check Windows is using, so we won't generate challenges,
|
||
|
|
which are rejected by Windows DCs (and future Samba DCs).
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
libcli/auth/credentials.c | 23 ++++++++++++++++++++++-
|
||
|
|
libcli/auth/proto.h | 1 +
|
||
|
|
2 files changed, 23 insertions(+), 1 deletion(-)
|
||
|
|
|
||
|
|
diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
|
||
|
|
index 46259f39306..54a20100b51 100644
|
||
|
|
--- a/libcli/auth/credentials.c
|
||
|
|
+++ b/libcli/auth/credentials.c
|
||
|
|
@@ -33,10 +33,31 @@
|
||
|
|
#include <gnutls/gnutls.h>
|
||
|
|
#include <gnutls/crypto.h>
|
||
|
|
|
||
|
|
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
|
||
|
|
+{
|
||
|
|
+ /*
|
||
|
|
+ * If none of the first 5 bytes of the client challenge is unique, the
|
||
|
|
+ * server MUST fail session-key negotiation without further processing
|
||
|
|
+ * of the following steps.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+ if (challenge->data[1] == challenge->data[0] &&
|
||
|
|
+ challenge->data[2] == challenge->data[0] &&
|
||
|
|
+ challenge->data[3] == challenge->data[0] &&
|
||
|
|
+ challenge->data[4] == challenge->data[0])
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
void netlogon_creds_random_challenge(struct netr_Credential *challenge)
|
||
|
|
{
|
||
|
|
ZERO_STRUCTP(challenge);
|
||
|
|
- generate_random_buffer(challenge->data, sizeof(challenge->data));
|
||
|
|
+ while (!netlogon_creds_is_random_challenge(challenge)) {
|
||
|
|
+ generate_random_buffer(challenge->data, sizeof(challenge->data));
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
|
||
|
|
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
|
||
|
|
index 396484a5437..a62668f088f 100644
|
||
|
|
--- a/libcli/auth/proto.h
|
||
|
|
+++ b/libcli/auth/proto.h
|
||
|
|
@@ -13,6 +13,7 @@
|
||
|
|
|
||
|
|
/* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c */
|
||
|
|
|
||
|
|
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge);
|
||
|
|
void netlogon_creds_random_challenge(struct netr_Credential *challenge);
|
||
|
|
|
||
|
|
NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 2eb0f87de8c9d86fad4ca1bd74f05d15af98f56e Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 16:17:29 +0200
|
||
|
|
Subject: [PATCH 07/19] CVE-2020-1472(ZeroLogon): libcli/auth: reject weak
|
||
|
|
client challenges in netlogon_creds_server_init()
|
||
|
|
|
||
|
|
This implements the note from MS-NRPC 3.1.4.1 Session-Key Negotiation:
|
||
|
|
|
||
|
|
7. If none of the first 5 bytes of the client challenge is unique, the
|
||
|
|
server MUST fail session-key negotiation without further processing of
|
||
|
|
the following steps.
|
||
|
|
|
||
|
|
It lets ./zerologon_tester.py from
|
||
|
|
https://github.com/SecuraBV/CVE-2020-1472.git
|
||
|
|
report: "Attack failed. Target is probably patched."
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
libcli/auth/credentials.c | 17 ++++++++++++++++-
|
||
|
|
libcli/auth/wscript_build | 2 +-
|
||
|
|
2 files changed, 17 insertions(+), 2 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
|
||
|
|
index 54a20100b51..23339d98bfa 100644
|
||
|
|
--- a/libcli/auth/credentials.c
|
||
|
|
+++ b/libcli/auth/credentials.c
|
||
|
|
@@ -24,6 +24,7 @@
|
||
|
|
#include "system/time.h"
|
||
|
|
#include "libcli/auth/libcli_auth.h"
|
||
|
|
#include "../libcli/security/dom_sid.h"
|
||
|
|
+#include "lib/util/util_str_escape.h"
|
||
|
|
|
||
|
|
#ifndef HAVE_GNUTLS_AES_CFB8
|
||
|
|
#include "lib/crypto/aes.h"
|
||
|
|
@@ -704,7 +705,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
|
||
|
|
|
||
|
|
struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
|
||
|
|
NTSTATUS status;
|
||
|
|
-
|
||
|
|
+ bool ok;
|
||
|
|
|
||
|
|
if (!creds) {
|
||
|
|
return NULL;
|
||
|
|
@@ -717,6 +718,20 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me
|
||
|
|
dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
|
||
|
|
dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
|
||
|
|
|
||
|
|
+ ok = netlogon_creds_is_random_challenge(client_challenge);
|
||
|
|
+ if (!ok) {
|
||
|
|
+ DBG_WARNING("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "non-random client challenge rejected for "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ log_escape(mem_ctx, client_account),
|
||
|
|
+ log_escape(mem_ctx, client_computer_name));
|
||
|
|
+ dump_data(DBGLVL_WARNING,
|
||
|
|
+ client_challenge->data,
|
||
|
|
+ sizeof(client_challenge->data));
|
||
|
|
+ talloc_free(creds);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
creds->computer_name = talloc_strdup(creds, client_computer_name);
|
||
|
|
if (!creds->computer_name) {
|
||
|
|
talloc_free(creds);
|
||
|
|
diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build
|
||
|
|
index 41937623630..2a6a7468e45 100644
|
||
|
|
--- a/libcli/auth/wscript_build
|
||
|
|
+++ b/libcli/auth/wscript_build
|
||
|
|
@@ -18,7 +18,7 @@ bld.SAMBA_SUBSYSTEM('NTLM_CHECK',
|
||
|
|
|
||
|
|
bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
|
||
|
|
source='credentials.c session.c smbencrypt.c smbdes.c',
|
||
|
|
- public_deps='MSRPC_PARSE gnutls GNUTLS_HELPERS',
|
||
|
|
+ public_deps='MSRPC_PARSE gnutls GNUTLS_HELPERS util_str_escape',
|
||
|
|
public_headers='credentials.h:domain_credentials.h'
|
||
|
|
)
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 592e8e9acdca472115fdf69a3d0904f1740f4fb0 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 19:20:25 +0200
|
||
|
|
Subject: [PATCH 08/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon:
|
||
|
|
protect netr_ServerPasswordSet2 against unencrypted passwords
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source4/rpc_server/netlogon/dcerpc_netlogon.c | 60 ++++++++++++++++++-
|
||
|
|
1 file changed, 59 insertions(+), 1 deletion(-)
|
||
|
|
|
||
|
|
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
index 7d1b9db0b86..4aa6f256a07 100644
|
||
|
|
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
@@ -724,7 +724,10 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
|
||
|
|
struct NL_PASSWORD_VERSION version = {};
|
||
|
|
const uint32_t *new_version = NULL;
|
||
|
|
NTSTATUS nt_status;
|
||
|
|
- DATA_BLOB new_password;
|
||
|
|
+ DATA_BLOB new_password = data_blob_null;
|
||
|
|
+ size_t confounder_len;
|
||
|
|
+ DATA_BLOB dec_blob = data_blob_null;
|
||
|
|
+ DATA_BLOB enc_blob = data_blob_null;
|
||
|
|
int ret;
|
||
|
|
struct samr_CryptPassword password_buf;
|
||
|
|
|
||
|
|
@@ -790,6 +793,61 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
|
||
|
|
return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ /*
|
||
|
|
+ * Make sure the length field was encrypted,
|
||
|
|
+ * otherwise we are under attack.
|
||
|
|
+ */
|
||
|
|
+ if (new_password.length == r->in.new_password->length) {
|
||
|
|
+ DBG_WARNING("Length[%zu] field not encrypted\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * We don't allow empty passwords for machine accounts.
|
||
|
|
+ */
|
||
|
|
+ if (new_password.length < 2) {
|
||
|
|
+ DBG_WARNING("Empty password Length[%zu]\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Make sure the confounder part of CryptPassword
|
||
|
|
+ * buffer was encrypted, otherwise we are under attack.
|
||
|
|
+ */
|
||
|
|
+ confounder_len = 512 - new_password.length;
|
||
|
|
+ enc_blob = data_blob_const(r->in.new_password->data, confounder_len);
|
||
|
|
+ dec_blob = data_blob_const(password_buf.data, confounder_len);
|
||
|
|
+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
|
||
|
|
+ DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n",
|
||
|
|
+ confounder_len);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Check that the password part was actually encrypted,
|
||
|
|
+ * otherwise we are under attack.
|
||
|
|
+ */
|
||
|
|
+ enc_blob = data_blob_const(r->in.new_password->data + confounder_len,
|
||
|
|
+ new_password.length);
|
||
|
|
+ dec_blob = data_blob_const(password_buf.data + confounder_len,
|
||
|
|
+ new_password.length);
|
||
|
|
+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
|
||
|
|
+ DBG_WARNING("Password buffer not encrypted Length[%zu]\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * don't allow zero buffers
|
||
|
|
+ */
|
||
|
|
+ if (all_zero(new_password.data, new_password.length)) {
|
||
|
|
+ DBG_WARNING("Password zero buffer Length[%zu]\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/* fetch the old password hashes (at least one of both has to exist) */
|
||
|
|
|
||
|
|
ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs,
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From ff66560357d3eb23ce71f6667443e47a0c491833 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Jeremy Allison <jra@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 12:48:21 -0700
|
||
|
|
Subject: [PATCH 09/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: Fix
|
||
|
|
mem leak onto p->mem_ctx in error path of _netr_ServerPasswordSet2().
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Jeremy Allison <jra@samba.org>
|
||
|
|
---
|
||
|
|
source3/rpc_server/netlogon/srv_netlog_nt.c | 1 +
|
||
|
|
1 file changed, 1 insertion(+)
|
||
|
|
|
||
|
|
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
index 516bbd7f6a8..b26efb78bab 100644
|
||
|
|
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
@@ -1385,6 +1385,7 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p,
|
||
|
|
516);
|
||
|
|
}
|
||
|
|
if (!NT_STATUS_IS_OK(status)) {
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From aa57f084ca2cf16e323d172634eacf34db3ff0d7 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Jeremy Allison <jra@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 12:53:50 -0700
|
||
|
|
Subject: [PATCH 10/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon:
|
||
|
|
protect netr_ServerPasswordSet2 against unencrypted passwords
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
|
||
|
|
|
||
|
|
Signed-off-by: Jeremy Allison <jra@samba.org>
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source3/rpc_server/netlogon/srv_netlog_nt.c | 98 +++++++++++++++++++--
|
||
|
|
1 file changed, 92 insertions(+), 6 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
index b26efb78bab..693e254b051 100644
|
||
|
|
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
@@ -1343,9 +1343,14 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p,
|
||
|
|
{
|
||
|
|
NTSTATUS status;
|
||
|
|
struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
- DATA_BLOB plaintext;
|
||
|
|
+ DATA_BLOB plaintext = data_blob_null;
|
||
|
|
+ DATA_BLOB new_password = data_blob_null;
|
||
|
|
+ size_t confounder_len;
|
||
|
|
+ DATA_BLOB dec_blob = data_blob_null;
|
||
|
|
+ DATA_BLOB enc_blob = data_blob_null;
|
||
|
|
struct samr_CryptPassword password_buf;
|
||
|
|
struct _samr_Credentials_t cr = { CRED_TYPE_PLAIN_TEXT, {0}};
|
||
|
|
+ bool ok;
|
||
|
|
|
||
|
|
become_root();
|
||
|
|
status = netr_creds_server_step_check(p, p->mem_ctx,
|
||
|
|
@@ -1389,18 +1394,99 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p,
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (!decode_pw_buffer(p->mem_ctx,
|
||
|
|
- password_buf.data,
|
||
|
|
- (char**) &plaintext.data,
|
||
|
|
- &plaintext.length,
|
||
|
|
- CH_UTF16)) {
|
||
|
|
+ if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &new_password)) {
|
||
|
|
DEBUG(2,("_netr_ServerPasswordSet2: unable to extract password "
|
||
|
|
"from a buffer. Rejecting auth request as a wrong password\n"));
|
||
|
|
TALLOC_FREE(creds);
|
||
|
|
return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ /*
|
||
|
|
+ * Make sure the length field was encrypted,
|
||
|
|
+ * otherwise we are under attack.
|
||
|
|
+ */
|
||
|
|
+ if (new_password.length == r->in.new_password->length) {
|
||
|
|
+ DBG_WARNING("Length[%zu] field not encrypted\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * We don't allow empty passwords for machine accounts.
|
||
|
|
+ */
|
||
|
|
+ if (new_password.length < 2) {
|
||
|
|
+ DBG_WARNING("Empty password Length[%zu]\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Make sure the confounder part of CryptPassword
|
||
|
|
+ * buffer was encrypted, otherwise we are under attack.
|
||
|
|
+ */
|
||
|
|
+ confounder_len = 512 - new_password.length;
|
||
|
|
+ enc_blob = data_blob_const(r->in.new_password->data, confounder_len);
|
||
|
|
+ dec_blob = data_blob_const(password_buf.data, confounder_len);
|
||
|
|
+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
|
||
|
|
+ DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n",
|
||
|
|
+ confounder_len);
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Check that the password part was actually encrypted,
|
||
|
|
+ * otherwise we are under attack.
|
||
|
|
+ */
|
||
|
|
+ enc_blob = data_blob_const(r->in.new_password->data + confounder_len,
|
||
|
|
+ new_password.length);
|
||
|
|
+ dec_blob = data_blob_const(password_buf.data + confounder_len,
|
||
|
|
+ new_password.length);
|
||
|
|
+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
|
||
|
|
+ DBG_WARNING("Password buffer not encrypted Length[%zu]\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * don't allow zero buffers
|
||
|
|
+ */
|
||
|
|
+ if (all_zero(new_password.data, new_password.length)) {
|
||
|
|
+ DBG_WARNING("Password zero buffer Length[%zu]\n",
|
||
|
|
+ new_password.length);
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Convert from UTF16 -> plaintext. */
|
||
|
|
+ ok = convert_string_talloc(p->mem_ctx,
|
||
|
|
+ CH_UTF16,
|
||
|
|
+ CH_UNIX,
|
||
|
|
+ new_password.data,
|
||
|
|
+ new_password.length,
|
||
|
|
+ (void *)&plaintext.data,
|
||
|
|
+ &plaintext.length);
|
||
|
|
+ if (!ok) {
|
||
|
|
+ DBG_WARNING("unable to extract password from a buffer. "
|
||
|
|
+ "Rejecting auth request as a wrong password\n");
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * We don't allow empty passwords for machine accounts.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
cr.creds.password = (const char*) plaintext.data;
|
||
|
|
+ if (strlen(cr.creds.password) == 0) {
|
||
|
|
+ DBG_WARNING("Empty plaintext password\n");
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ return NT_STATUS_WRONG_PASSWORD;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
status = netr_set_machine_account_password(p->mem_ctx,
|
||
|
|
p->session_info,
|
||
|
|
p->msg_ctx,
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 1c8234f6da6979a063c96c0eb32ddb55a51ce548 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 10:18:45 +0200
|
||
|
|
Subject: [PATCH 11/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon:
|
||
|
|
refactor dcesrv_netr_creds_server_step_check()
|
||
|
|
|
||
|
|
We should debug more details about the failing request.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source4/rpc_server/netlogon/dcerpc_netlogon.c | 45 ++++++++++++++-----
|
||
|
|
1 file changed, 33 insertions(+), 12 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
index 4aa6f256a07..7ccf46ae79b 100644
|
||
|
|
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
@@ -624,26 +624,47 @@ 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);
|
||
|
|
+ struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
+ enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
+ uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||
|
|
+ const char *opname = "<unknown>";
|
||
|
|
|
||
|
|
- if (schannel_global_required) {
|
||
|
|
- enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
-
|
||
|
|
- dcesrv_call_auth_info(dce_call, &auth_type, NULL);
|
||
|
|
-
|
||
|
|
- if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
- DBG_ERR("[%s] is not using schannel\n",
|
||
|
|
- computer_name);
|
||
|
|
- return NT_STATUS_ACCESS_DENIED;
|
||
|
|
- }
|
||
|
|
+ if (opnum < ndr_table_netlogon.num_calls) {
|
||
|
|
+ opname = ndr_table_netlogon.calls[opnum].name;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ 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_out);
|
||
|
|
- return nt_status;
|
||
|
|
+ &creds);
|
||
|
|
+ if (!NT_STATUS_IS_OK(nt_status)) {
|
||
|
|
+ ZERO_STRUCTP(return_authenticator);
|
||
|
|
+ return nt_status;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (schannel_global_required) {
|
||
|
|
+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
+ *creds_out = creds;
|
||
|
|
+ return NT_STATUS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) without schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ ZERO_STRUCTP(return_authenticator);
|
||
|
|
+ return NT_STATUS_ACCESS_DENIED;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *creds_out = creds;
|
||
|
|
+ return NT_STATUS_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From d8e520870c5c8943c289b3f373b1a4bcceefc174 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Wed, 16 Sep 2020 10:56:53 +0200
|
||
|
|
Subject: [PATCH 12/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon:
|
||
|
|
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.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source4/rpc_server/netlogon/dcerpc_netlogon.c | 9 ++++++++-
|
||
|
|
1 file changed, 8 insertions(+), 1 deletion(-)
|
||
|
|
|
||
|
|
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
index 7ccf46ae79b..7994cb904b7 100644
|
||
|
|
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
@@ -624,6 +624,7 @@ 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_global_required;
|
||
|
|
struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||
|
|
@@ -646,7 +647,13 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
|
||
|
|
return nt_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (schannel_global_required) {
|
||
|
|
+ schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
|
||
|
|
+ NULL,
|
||
|
|
+ "server require schannel",
|
||
|
|
+ creds->account_name,
|
||
|
|
+ schannel_global_required);
|
||
|
|
+
|
||
|
|
+ if (schannel_required) {
|
||
|
|
if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
*creds_out = creds;
|
||
|
|
return NT_STATUS_OK;
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 629aeb89877ca7d8aef53b5ea2c507d2f146a23b Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Thu, 17 Sep 2020 13:37:26 +0200
|
||
|
|
Subject: [PATCH 13/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: log
|
||
|
|
warnings about unsecure configurations
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
This should give admins wawrnings until they have a secure
|
||
|
|
configuration.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Reviewed-by: Ralph Boehme <slow@samba.org>
|
||
|
|
Reviewed-by: Günther Deschner <gd@samba.org>
|
||
|
|
---
|
||
|
|
source4/rpc_server/netlogon/dcerpc_netlogon.c | 66 ++++++++++++++++++-
|
||
|
|
1 file changed, 63 insertions(+), 3 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
index 7994cb904b7..9972138dbde 100644
|
||
|
|
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
|
||
|
|
@@ -625,10 +625,12 @@ 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_global_required = (schannel == true);
|
||
|
|
bool schannel_required = schannel_global_required;
|
||
|
|
+ const char *explicit_opt = NULL;
|
||
|
|
struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
uint16_t opnum = dce_call->pkt.u.request.opnum;
|
||
|
|
const char *opname = "<unknown>";
|
||
|
|
+ static bool warned_global_once = false;
|
||
|
|
|
||
|
|
if (opnum < ndr_table_netlogon.num_calls) {
|
||
|
|
opname = ndr_table_netlogon.calls[opnum].name;
|
||
|
|
@@ -647,11 +649,18 @@ 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,
|
||
|
|
+ /*
|
||
|
|
+ * We don't use lpcfg_parm_bool(), as we
|
||
|
|
+ * need the explicit_opt pointer in order to
|
||
|
|
+ * adjust the debug messages.
|
||
|
|
+ */
|
||
|
|
+ explicit_opt = lpcfg_get_parametric(dce_call->conn->dce_ctx->lp_ctx,
|
||
|
|
NULL,
|
||
|
|
"server require schannel",
|
||
|
|
- creds->account_name,
|
||
|
|
- schannel_global_required);
|
||
|
|
+ creds->account_name);
|
||
|
|
+ if (explicit_opt != NULL) {
|
||
|
|
+ schannel_required = lp_bool(explicit_opt);
|
||
|
|
+ }
|
||
|
|
|
||
|
|
if (schannel_required) {
|
||
|
|
if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
@@ -665,11 +674,62 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc
|
||
|
|
opname, opnum,
|
||
|
|
log_escape(mem_ctx, creds->account_name),
|
||
|
|
log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
|
||
|
|
+ "'server require schannel:%s = no' is needed! \n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
TALLOC_FREE(creds);
|
||
|
|
ZERO_STRUCTP(return_authenticator);
|
||
|
|
return NT_STATUS_ACCESS_DENIED;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (!schannel_global_required && !warned_global_once) {
|
||
|
|
+ /*
|
||
|
|
+ * We want admins to notice their misconfiguration!
|
||
|
|
+ */
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "Please configure 'server schannel = yes', "
|
||
|
|
+ "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n");
|
||
|
|
+ warned_global_once = true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) WITH schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "Option 'server require schannel:%s = no' not needed!?\n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
+
|
||
|
|
+ *creds_out = creds;
|
||
|
|
+ return NT_STATUS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+ if (explicit_opt != NULL) {
|
||
|
|
+ DBG_INFO("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) without schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_INFO("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "Option 'server require schannel:%s = no' still needed!\n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
+ } else {
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) without schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
|
||
|
|
+ "'server require schannel:%s = no' might be needed!\n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
*creds_out = creds;
|
||
|
|
return NT_STATUS_OK;
|
||
|
|
}
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From eab8661ef16856eb0926fe3426f7fe6ac870faae Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
||
|
|
Date: Thu, 17 Sep 2020 14:57:22 +0200
|
||
|
|
Subject: [PATCH 14/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon:
|
||
|
|
refactor dcesrv_netr_creds_server_step_check()
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
We should debug more details about the failing request.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
|
||
|
|
|
||
|
|
Signed-off-by: Günther Deschner <gd@samba.org>
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source3/rpc_server/netlogon/srv_netlog_nt.c | 43 +++++++++++++++++----
|
||
|
|
1 file changed, 35 insertions(+), 8 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
index 693e254b051..c134e07573c 100644
|
||
|
|
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
@@ -47,6 +47,7 @@
|
||
|
|
#include "../lib/tsocket/tsocket.h"
|
||
|
|
#include "lib/param/param.h"
|
||
|
|
#include "libsmb/dsgetdcname.h"
|
||
|
|
+#include "lib/util/util_str_escape.h"
|
||
|
|
|
||
|
|
extern userdom_struct current_user_info;
|
||
|
|
|
||
|
|
@@ -1073,19 +1074,21 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
NTSTATUS status;
|
||
|
|
bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
|
||
|
|
struct loadparm_context *lp_ctx;
|
||
|
|
+ struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
+ enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
+ uint16_t opnum = p->opnum;
|
||
|
|
+ const char *opname = "<unknown>";
|
||
|
|
|
||
|
|
if (creds_out != NULL) {
|
||
|
|
*creds_out = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (schannel_global_required) {
|
||
|
|
- if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
- DBG_ERR("[%s] is not using schannel\n",
|
||
|
|
- computer_name);
|
||
|
|
- return NT_STATUS_ACCESS_DENIED;
|
||
|
|
- }
|
||
|
|
+ if (opnum < ndr_table_netlogon.num_calls) {
|
||
|
|
+ opname = ndr_table_netlogon.calls[opnum].name;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ auth_type = p->auth.auth_type;
|
||
|
|
+
|
||
|
|
lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
|
||
|
|
if (lp_ctx == NULL) {
|
||
|
|
DEBUG(0, ("loadparm_init_s3 failed\n"));
|
||
|
|
@@ -1094,9 +1097,33 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
|
||
|
|
status = schannel_check_creds_state(mem_ctx, lp_ctx,
|
||
|
|
computer_name, received_authenticator,
|
||
|
|
- return_authenticator, creds_out);
|
||
|
|
+ return_authenticator, &creds);
|
||
|
|
talloc_unlink(mem_ctx, lp_ctx);
|
||
|
|
- return status;
|
||
|
|
+
|
||
|
|
+ if (!NT_STATUS_IS_OK(status)) {
|
||
|
|
+ ZERO_STRUCTP(return_authenticator);
|
||
|
|
+ return status;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (schannel_global_required) {
|
||
|
|
+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
+ *creds_out = creds;
|
||
|
|
+ return NT_STATUS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) without schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ TALLOC_FREE(creds);
|
||
|
|
+ ZERO_STRUCTP(return_authenticator);
|
||
|
|
+ return NT_STATUS_ACCESS_DENIED;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *creds_out = creds;
|
||
|
|
+ return NT_STATUS_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From db2580705011c996a4feb01c4b6f069a4e013135 Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
||
|
|
Date: Thu, 17 Sep 2020 14:23:16 +0200
|
||
|
|
Subject: [PATCH 15/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon:
|
||
|
|
support "server require schannel:WORKSTATION$ = no"
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
This allows to add expections for individual workstations, when using "server schannel = yes".
|
||
|
|
"server schannel = auto" is very insecure and will be removed soon.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
|
||
|
|
|
||
|
|
Signed-off-by: Günther Deschner <gd@samba.org>
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source3/rpc_server/netlogon/srv_netlog_nt.c | 7 ++++++-
|
||
|
|
1 file changed, 6 insertions(+), 1 deletion(-)
|
||
|
|
|
||
|
|
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
index c134e07573c..3327f4bc0a0 100644
|
||
|
|
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
@@ -1073,6 +1073,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
{
|
||
|
|
NTSTATUS status;
|
||
|
|
bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
|
||
|
|
+ bool schannel_required = schannel_global_required;
|
||
|
|
struct loadparm_context *lp_ctx;
|
||
|
|
struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
@@ -1105,7 +1106,11 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (schannel_global_required) {
|
||
|
|
+ schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM,
|
||
|
|
+ "server require schannel",
|
||
|
|
+ creds->account_name,
|
||
|
|
+ schannel_global_required);
|
||
|
|
+ if (schannel_required) {
|
||
|
|
if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
*creds_out = creds;
|
||
|
|
return NT_STATUS_OK;
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From fa5fc293263150238755fbb8310653550f57049a Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
||
|
|
Date: Thu, 17 Sep 2020 14:42:52 +0200
|
||
|
|
Subject: [PATCH 16/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: log
|
||
|
|
warnings about unsecure configurations
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
|
||
|
|
|
||
|
|
Signed-off-by: Günther Deschner <gd@samba.org>
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
source3/rpc_server/netlogon/srv_netlog_nt.c | 70 +++++++++++++++++++--
|
||
|
|
1 file changed, 66 insertions(+), 4 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
index 3327f4bc0a0..9ef74447b84 100644
|
||
|
|
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
|
||
|
|
@@ -1074,11 +1074,13 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
NTSTATUS status;
|
||
|
|
bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
|
||
|
|
bool schannel_required = schannel_global_required;
|
||
|
|
+ const char *explicit_opt = NULL;
|
||
|
|
struct loadparm_context *lp_ctx;
|
||
|
|
struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
|
||
|
|
uint16_t opnum = p->opnum;
|
||
|
|
const char *opname = "<unknown>";
|
||
|
|
+ static bool warned_global_once = false;
|
||
|
|
|
||
|
|
if (creds_out != NULL) {
|
||
|
|
*creds_out = NULL;
|
||
|
|
@@ -1106,10 +1108,20 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
- schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM,
|
||
|
|
- "server require schannel",
|
||
|
|
- creds->account_name,
|
||
|
|
- schannel_global_required);
|
||
|
|
+ /*
|
||
|
|
+ * We don't use lp_parm_bool(), as we
|
||
|
|
+ * need the explicit_opt pointer in order to
|
||
|
|
+ * adjust the debug messages.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+ explicit_opt = lp_parm_const_string(GLOBAL_SECTION_SNUM,
|
||
|
|
+ "server require schannel",
|
||
|
|
+ creds->account_name,
|
||
|
|
+ NULL);
|
||
|
|
+ if (explicit_opt != NULL) {
|
||
|
|
+ schannel_required = lp_bool(explicit_opt);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (schannel_required) {
|
||
|
|
if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
*creds_out = creds;
|
||
|
|
@@ -1122,11 +1134,61 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
|
||
|
|
opname, opnum,
|
||
|
|
log_escape(mem_ctx, creds->account_name),
|
||
|
|
log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
|
||
|
|
+ "'server require schannel:%s = no' is needed! \n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
TALLOC_FREE(creds);
|
||
|
|
ZERO_STRUCTP(return_authenticator);
|
||
|
|
return NT_STATUS_ACCESS_DENIED;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (!schannel_global_required && !warned_global_once) {
|
||
|
|
+ /*
|
||
|
|
+ * We want admins to notice their misconfiguration!
|
||
|
|
+ */
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "Please configure 'server schannel = yes', "
|
||
|
|
+ "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n");
|
||
|
|
+ warned_global_once = true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) WITH schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "Option 'server require schannel:%s = no' not needed!?\n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
+
|
||
|
|
+ *creds_out = creds;
|
||
|
|
+ return NT_STATUS_OK;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (explicit_opt != NULL) {
|
||
|
|
+ DBG_INFO("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) without schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_INFO("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "Option 'server require schannel:%s = no' still needed!\n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
+ } else {
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): "
|
||
|
|
+ "%s request (opnum[%u]) without schannel from "
|
||
|
|
+ "client_account[%s] client_computer_name[%s]\n",
|
||
|
|
+ opname, opnum,
|
||
|
|
+ log_escape(mem_ctx, creds->account_name),
|
||
|
|
+ log_escape(mem_ctx, creds->computer_name));
|
||
|
|
+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option "
|
||
|
|
+ "'server require schannel:%s = no' might be needed!\n",
|
||
|
|
+ log_escape(mem_ctx, creds->account_name));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
*creds_out = creds;
|
||
|
|
return NT_STATUS_OK;
|
||
|
|
}
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 296a62d1589dbf33aa751e8346ba5721f6314215 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Thu, 17 Sep 2020 17:27:54 +0200
|
||
|
|
Subject: [PATCH 17/19] CVE-2020-1472(ZeroLogon): docs-xml: document 'server
|
||
|
|
require schannel:COMPUTERACCOUNT'
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
---
|
||
|
|
.../smbdotconf/security/serverschannel.xml | 69 +++++++++++++++----
|
||
|
|
1 file changed, 54 insertions(+), 15 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml
|
||
|
|
index 489492d79b1..b682d086f76 100644
|
||
|
|
--- a/docs-xml/smbdotconf/security/serverschannel.xml
|
||
|
|
+++ b/docs-xml/smbdotconf/security/serverschannel.xml
|
||
|
|
@@ -7,26 +7,65 @@
|
||
|
|
<description>
|
||
|
|
|
||
|
|
<para>
|
||
|
|
- This option is deprecated with Samba 4.8 and will be removed in future.
|
||
|
|
- At the same time the default changed to yes, which will be the
|
||
|
|
- hardcoded behavior in future. If you have the need for the behavior of "auto"
|
||
|
|
- to be kept, please file a bug at https://bugzilla.samba.org.
|
||
|
|
+ This option is deprecated and will be removed in future,
|
||
|
|
+ as it is a security problem if not set to "yes" (which will be
|
||
|
|
+ the hardcoded behavior in future).
|
||
|
|
</para>
|
||
|
|
|
||
|
|
<para>
|
||
|
|
- This controls whether the server offers or even demands the use of the netlogon schannel.
|
||
|
|
- <smbconfoption name="server schannel">no</smbconfoption> does not offer the schannel, <smbconfoption
|
||
|
|
- name="server schannel">auto</smbconfoption> offers the schannel but does not enforce it, and <smbconfoption
|
||
|
|
- name="server schannel">yes</smbconfoption> denies access if the client is not able to speak netlogon schannel.
|
||
|
|
- This is only the case for Windows NT4 before SP4.
|
||
|
|
- </para>
|
||
|
|
-
|
||
|
|
+ Samba will complain in the log files at log level 0,
|
||
|
|
+ about the security problem if the option is not set to "yes".
|
||
|
|
+ </para>
|
||
|
|
<para>
|
||
|
|
- Please note that with this set to <literal>no</literal>, you will have to apply the WindowsXP
|
||
|
|
- <filename>WinXP_SignOrSeal.reg</filename> registry patch found in the docs/registry subdirectory of the Samba distribution tarball.
|
||
|
|
- </para>
|
||
|
|
+ See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
+ </para>
|
||
|
|
+
|
||
|
|
+ <para>If you still have legacy domain members use the <smbconfoption name="server require schannel:COMPUTERACCOUNT"/> option.
|
||
|
|
+ </para>
|
||
|
|
+
|
||
|
|
+ <para>This option yields precedence to the <smbconfoption name="server require schannel:COMPUTERACCOUNT"/> option.</para>
|
||
|
|
+
|
||
|
|
</description>
|
||
|
|
|
||
|
|
<value type="default">yes</value>
|
||
|
|
-<value type="example">auto</value>
|
||
|
|
+</samba:parameter>
|
||
|
|
+
|
||
|
|
+<samba:parameter name="server require schannel:COMPUTERACCOUNT"
|
||
|
|
+ context="G"
|
||
|
|
+ type="string"
|
||
|
|
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
|
||
|
|
+<description>
|
||
|
|
+
|
||
|
|
+ <para>If you still have legacy domain members, which required "server schannel = auto" before,
|
||
|
|
+ it is possible to specify explicit expection per computer account
|
||
|
|
+ by using 'server require schannel:COMPUTERACCOUNT = no' as option.
|
||
|
|
+ Note that COMPUTERACCOUNT has to be the sAMAccountName value of
|
||
|
|
+ the computer account (including the trailing '$' sign).
|
||
|
|
+ </para>
|
||
|
|
+
|
||
|
|
+ <para>
|
||
|
|
+ Samba will complain in the log files at log level 0,
|
||
|
|
+ about the security problem if the option is not set to "no",
|
||
|
|
+ but the related computer is actually using the netlogon
|
||
|
|
+ secure channel (schannel) feature.
|
||
|
|
+ </para>
|
||
|
|
+
|
||
|
|
+ <para>
|
||
|
|
+ Samba will warn in the log files at log level 5,
|
||
|
|
+ if a setting is still needed for the specified computer account.
|
||
|
|
+ </para>
|
||
|
|
+
|
||
|
|
+ <para>
|
||
|
|
+ See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
+ </para>
|
||
|
|
+
|
||
|
|
+ <para>This option takes precedence to the <smbconfoption name="server schannel"/> option.</para>
|
||
|
|
+
|
||
|
|
+ <programlisting>
|
||
|
|
+ server require schannel:LEGACYCOMPUTER1$ = no
|
||
|
|
+ server require schannel:NASBOX$ = no
|
||
|
|
+ server require schannel:LEGACYCOMPUTER2$ = no
|
||
|
|
+ </programlisting>
|
||
|
|
+</description>
|
||
|
|
+
|
||
|
|
</samba:parameter>
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From 3110ca45379309c55f96e97df5d6d010390cd8c6 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||
|
|
Date: Fri, 18 Sep 2020 12:39:54 +1200
|
||
|
|
Subject: [PATCH 18/19] CVE-2020-1472(ZeroLogon): s4 torture rpc: Test empty
|
||
|
|
machine acct pwd
|
||
|
|
|
||
|
|
Ensure that an empty machine account password can't be set by
|
||
|
|
netr_ServerPasswordSet2
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||
|
|
---
|
||
|
|
source4/torture/rpc/netlogon.c | 64 +++++++++++++++-------------------
|
||
|
|
1 file changed, 29 insertions(+), 35 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
|
||
|
|
index 826793717e7..af9d94b99ff 100644
|
||
|
|
--- a/source4/torture/rpc/netlogon.c
|
||
|
|
+++ b/source4/torture/rpc/netlogon.c
|
||
|
|
@@ -725,45 +725,39 @@ static bool test_SetPassword2_with_flags(struct torture_context *tctx,
|
||
|
|
|
||
|
|
cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
|
||
|
|
|
||
|
|
- if (!torture_setting_bool(tctx, "dangerous", false)) {
|
||
|
|
- torture_comment(tctx,
|
||
|
|
- "Not testing ability to set password to '', enable dangerous tests to perform this test\n");
|
||
|
|
+ /*
|
||
|
|
+ * As a consequence of CVE-2020-1472(ZeroLogon)
|
||
|
|
+ * Samba explicitly disallows the setting of an empty machine account
|
||
|
|
+ * password.
|
||
|
|
+ *
|
||
|
|
+ * Note that this may fail against Windows, and leave a machine account
|
||
|
|
+ * with an empty password.
|
||
|
|
+ */
|
||
|
|
+ password = "";
|
||
|
|
+ encode_pw_buffer(password_buf.data, password, STR_UNICODE);
|
||
|
|
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
|
||
|
|
+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
|
||
|
|
} else {
|
||
|
|
- /* by changing the machine password to ""
|
||
|
|
- * we check if the server uses password restrictions
|
||
|
|
- * for ServerPasswordSet2
|
||
|
|
- * (win2k3 accepts "")
|
||
|
|
- */
|
||
|
|
- password = "";
|
||
|
|
- encode_pw_buffer(password_buf.data, password, STR_UNICODE);
|
||
|
|
- if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
|
||
|
|
- netlogon_creds_aes_encrypt(creds, password_buf.data, 516);
|
||
|
|
- } else {
|
||
|
|
- netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
|
||
|
|
- }
|
||
|
|
- memcpy(new_password.data, password_buf.data, 512);
|
||
|
|
- new_password.length = IVAL(password_buf.data, 512);
|
||
|
|
-
|
||
|
|
- torture_comment(tctx,
|
||
|
|
- "Testing ServerPasswordSet2 on machine account\n");
|
||
|
|
- torture_comment(tctx,
|
||
|
|
- "Changing machine account password to '%s'\n", password);
|
||
|
|
-
|
||
|
|
- netlogon_creds_client_authenticator(creds, &credential);
|
||
|
|
-
|
||
|
|
- torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
|
||
|
|
- "ServerPasswordSet2 failed");
|
||
|
|
- torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet2 failed");
|
||
|
|
+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
|
||
|
|
+ }
|
||
|
|
+ memcpy(new_password.data, password_buf.data, 512);
|
||
|
|
+ new_password.length = IVAL(password_buf.data, 512);
|
||
|
|
|
||
|
|
- if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) {
|
||
|
|
- torture_comment(tctx, "Credential chaining failed\n");
|
||
|
|
- }
|
||
|
|
+ torture_comment(tctx,
|
||
|
|
+ "Testing ServerPasswordSet2 on machine account\n");
|
||
|
|
+ torture_comment(tctx,
|
||
|
|
+ "Changing machine account password to '%s'\n", password);
|
||
|
|
|
||
|
|
- cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED);
|
||
|
|
- }
|
||
|
|
+ netlogon_creds_client_authenticator(creds, &credential);
|
||
|
|
|
||
|
|
- torture_assert(tctx, test_SetupCredentials(p, tctx, machine_credentials, &creds),
|
||
|
|
- "ServerPasswordSet failed to actually change the password");
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r),
|
||
|
|
+ "ServerPasswordSet2 failed");
|
||
|
|
+ torture_assert_ntstatus_equal(
|
||
|
|
+ tctx,
|
||
|
|
+ r.out.result,
|
||
|
|
+ NT_STATUS_WRONG_PASSWORD,
|
||
|
|
+ "ServerPasswordSet2 did not return NT_STATUS_WRONG_PASSWORD");
|
||
|
|
|
||
|
|
/* now try a random password */
|
||
|
|
password = generate_random_password(tctx, 8, 255);
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|
||
|
|
|
||
|
|
From a13ddb0fe6ddf29642976f4caff9c2391676645c Mon Sep 17 00:00:00 2001
|
||
|
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||
|
|
Date: Fri, 18 Sep 2020 15:57:34 +1200
|
||
|
|
Subject: [PATCH 19/19] CVE-2020-1472(ZeroLogon): s4 torture rpc: repeated
|
||
|
|
bytes in client challenge
|
||
|
|
|
||
|
|
Ensure that client challenges with the first 5 bytes identical are
|
||
|
|
rejected.
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
|
||
|
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||
|
|
|
||
|
|
[abartlet@samba.org: backported from master as test order was flipped]
|
||
|
|
---
|
||
|
|
source4/torture/rpc/netlogon.c | 335 +++++++++++++++++++++++++++++++++
|
||
|
|
1 file changed, 335 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c
|
||
|
|
index af9d94b99ff..c9e614fda30 100644
|
||
|
|
--- a/source4/torture/rpc/netlogon.c
|
||
|
|
+++ b/source4/torture/rpc/netlogon.c
|
||
|
|
@@ -486,6 +486,325 @@ bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1,
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static bool test_ServerReqChallenge(
|
||
|
|
+ struct torture_context *tctx,
|
||
|
|
+ struct dcerpc_pipe *p,
|
||
|
|
+ struct cli_credentials *credentials)
|
||
|
|
+{
|
||
|
|
+ struct netr_ServerReqChallenge r;
|
||
|
|
+ struct netr_Credential credentials1, credentials2, credentials3;
|
||
|
|
+ const char *machine_name;
|
||
|
|
+ struct dcerpc_binding_handle *b = p->binding_handle;
|
||
|
|
+ struct netr_ServerAuthenticate2 a;
|
||
|
|
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
|
||
|
|
+ uint32_t out_negotiate_flags = 0;
|
||
|
|
+ const struct samr_Password *mach_password = NULL;
|
||
|
|
+ enum netr_SchannelType sec_chan_type = 0;
|
||
|
|
+ struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
+ const char *account_name = NULL;
|
||
|
|
+
|
||
|
|
+ machine_name = cli_credentials_get_workstation(credentials);
|
||
|
|
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
|
||
|
|
+ account_name = cli_credentials_get_username(credentials);
|
||
|
|
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
|
||
|
|
+
|
||
|
|
+ r.in.server_name = NULL;
|
||
|
|
+ r.in.computer_name = machine_name;
|
||
|
|
+ r.in.credentials = &credentials1;
|
||
|
|
+ r.out.return_credentials = &credentials2;
|
||
|
|
+
|
||
|
|
+ netlogon_creds_random_challenge(&credentials1);
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ r.out.result,
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ a.in.server_name = NULL;
|
||
|
|
+ a.in.account_name = account_name;
|
||
|
|
+ a.in.secure_channel_type = sec_chan_type;
|
||
|
|
+ a.in.computer_name = machine_name;
|
||
|
|
+ a.in.negotiate_flags = &in_negotiate_flags;
|
||
|
|
+ a.out.negotiate_flags = &out_negotiate_flags;
|
||
|
|
+ a.in.credentials = &credentials3;
|
||
|
|
+ a.out.return_credentials = &credentials3;
|
||
|
|
+
|
||
|
|
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
|
||
|
|
+ a.in.computer_name,
|
||
|
|
+ a.in.secure_channel_type,
|
||
|
|
+ &credentials1, &credentials2,
|
||
|
|
+ mach_password, &credentials3,
|
||
|
|
+ in_negotiate_flags);
|
||
|
|
+
|
||
|
|
+ torture_assert(tctx, creds != NULL, "memory allocation");
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
|
||
|
|
+ "ServerAuthenticate2 failed");
|
||
|
|
+ torture_assert_ntstatus_equal(
|
||
|
|
+ tctx,
|
||
|
|
+ a.out.result,
|
||
|
|
+ NT_STATUS_OK,
|
||
|
|
+ "ServerAuthenticate2 unexpected");
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool test_ServerReqChallenge_zero_challenge(
|
||
|
|
+ struct torture_context *tctx,
|
||
|
|
+ struct dcerpc_pipe *p,
|
||
|
|
+ struct cli_credentials *credentials)
|
||
|
|
+{
|
||
|
|
+ struct netr_ServerReqChallenge r;
|
||
|
|
+ struct netr_Credential credentials1, credentials2, credentials3;
|
||
|
|
+ const char *machine_name;
|
||
|
|
+ struct dcerpc_binding_handle *b = p->binding_handle;
|
||
|
|
+ struct netr_ServerAuthenticate2 a;
|
||
|
|
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
|
||
|
|
+ uint32_t out_negotiate_flags = 0;
|
||
|
|
+ const struct samr_Password *mach_password = NULL;
|
||
|
|
+ enum netr_SchannelType sec_chan_type = 0;
|
||
|
|
+ struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
+ const char *account_name = NULL;
|
||
|
|
+
|
||
|
|
+ machine_name = cli_credentials_get_workstation(credentials);
|
||
|
|
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
|
||
|
|
+ account_name = cli_credentials_get_username(credentials);
|
||
|
|
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
|
||
|
|
+
|
||
|
|
+ r.in.server_name = NULL;
|
||
|
|
+ r.in.computer_name = machine_name;
|
||
|
|
+ r.in.credentials = &credentials1;
|
||
|
|
+ r.out.return_credentials = &credentials2;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Set the client challenge to zero, this should fail
|
||
|
|
+ * CVE-2020-1472(ZeroLogon)
|
||
|
|
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
+ */
|
||
|
|
+ ZERO_STRUCT(credentials1);
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ r.out.result,
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ a.in.server_name = NULL;
|
||
|
|
+ a.in.account_name = account_name;
|
||
|
|
+ a.in.secure_channel_type = sec_chan_type;
|
||
|
|
+ a.in.computer_name = machine_name;
|
||
|
|
+ a.in.negotiate_flags = &in_negotiate_flags;
|
||
|
|
+ a.out.negotiate_flags = &out_negotiate_flags;
|
||
|
|
+ a.in.credentials = &credentials3;
|
||
|
|
+ a.out.return_credentials = &credentials3;
|
||
|
|
+
|
||
|
|
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
|
||
|
|
+ a.in.computer_name,
|
||
|
|
+ a.in.secure_channel_type,
|
||
|
|
+ &credentials1, &credentials2,
|
||
|
|
+ mach_password, &credentials3,
|
||
|
|
+ in_negotiate_flags);
|
||
|
|
+
|
||
|
|
+ torture_assert(tctx, creds != NULL, "memory allocation");
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
|
||
|
|
+ "ServerAuthenticate2 failed");
|
||
|
|
+ torture_assert_ntstatus_equal(
|
||
|
|
+ tctx,
|
||
|
|
+ a.out.result,
|
||
|
|
+ NT_STATUS_ACCESS_DENIED,
|
||
|
|
+ "ServerAuthenticate2 unexpected");
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool test_ServerReqChallenge_5_repeats(
|
||
|
|
+ struct torture_context *tctx,
|
||
|
|
+ struct dcerpc_pipe *p,
|
||
|
|
+ struct cli_credentials *credentials)
|
||
|
|
+{
|
||
|
|
+ struct netr_ServerReqChallenge r;
|
||
|
|
+ struct netr_Credential credentials1, credentials2, credentials3;
|
||
|
|
+ const char *machine_name;
|
||
|
|
+ struct dcerpc_binding_handle *b = p->binding_handle;
|
||
|
|
+ struct netr_ServerAuthenticate2 a;
|
||
|
|
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
|
||
|
|
+ uint32_t out_negotiate_flags = 0;
|
||
|
|
+ const struct samr_Password *mach_password = NULL;
|
||
|
|
+ enum netr_SchannelType sec_chan_type = 0;
|
||
|
|
+ struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
+ const char *account_name = NULL;
|
||
|
|
+
|
||
|
|
+ machine_name = cli_credentials_get_workstation(credentials);
|
||
|
|
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
|
||
|
|
+ account_name = cli_credentials_get_username(credentials);
|
||
|
|
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
|
||
|
|
+
|
||
|
|
+ r.in.server_name = NULL;
|
||
|
|
+ r.in.computer_name = machine_name;
|
||
|
|
+ r.in.credentials = &credentials1;
|
||
|
|
+ r.out.return_credentials = &credentials2;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Set the first 5 bytes of the client challenge to the same value,
|
||
|
|
+ * this should fail CVE-2020-1472(ZeroLogon)
|
||
|
|
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
+ */
|
||
|
|
+ credentials1.data[0] = 'A';
|
||
|
|
+ credentials1.data[1] = 'A';
|
||
|
|
+ credentials1.data[2] = 'A';
|
||
|
|
+ credentials1.data[3] = 'A';
|
||
|
|
+ credentials1.data[4] = 'A';
|
||
|
|
+ credentials1.data[5] = 'B';
|
||
|
|
+ credentials1.data[6] = 'C';
|
||
|
|
+ credentials1.data[7] = 'D';
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ r.out.result,
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ a.in.server_name = NULL;
|
||
|
|
+ a.in.account_name = account_name;
|
||
|
|
+ a.in.secure_channel_type = sec_chan_type;
|
||
|
|
+ a.in.computer_name = machine_name;
|
||
|
|
+ a.in.negotiate_flags = &in_negotiate_flags;
|
||
|
|
+ a.out.negotiate_flags = &out_negotiate_flags;
|
||
|
|
+ a.in.credentials = &credentials3;
|
||
|
|
+ a.out.return_credentials = &credentials3;
|
||
|
|
+
|
||
|
|
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
|
||
|
|
+ a.in.computer_name,
|
||
|
|
+ a.in.secure_channel_type,
|
||
|
|
+ &credentials1, &credentials2,
|
||
|
|
+ mach_password, &credentials3,
|
||
|
|
+ in_negotiate_flags);
|
||
|
|
+
|
||
|
|
+ torture_assert(tctx, creds != NULL, "memory allocation");
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
|
||
|
|
+ "ServerAuthenticate2 failed");
|
||
|
|
+ torture_assert_ntstatus_equal(
|
||
|
|
+ tctx,
|
||
|
|
+ a.out.result,
|
||
|
|
+ NT_STATUS_ACCESS_DENIED,
|
||
|
|
+ "ServerAuthenticate2 unexpected");
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool test_ServerReqChallenge_4_repeats(
|
||
|
|
+ struct torture_context *tctx,
|
||
|
|
+ struct dcerpc_pipe *p,
|
||
|
|
+ struct cli_credentials *credentials)
|
||
|
|
+{
|
||
|
|
+ struct netr_ServerReqChallenge r;
|
||
|
|
+ struct netr_Credential credentials1, credentials2, credentials3;
|
||
|
|
+ const char *machine_name;
|
||
|
|
+ struct dcerpc_binding_handle *b = p->binding_handle;
|
||
|
|
+ struct netr_ServerAuthenticate2 a;
|
||
|
|
+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
|
||
|
|
+ uint32_t out_negotiate_flags = 0;
|
||
|
|
+ const struct samr_Password *mach_password = NULL;
|
||
|
|
+ enum netr_SchannelType sec_chan_type = 0;
|
||
|
|
+ struct netlogon_creds_CredentialState *creds = NULL;
|
||
|
|
+ const char *account_name = NULL;
|
||
|
|
+
|
||
|
|
+ machine_name = cli_credentials_get_workstation(credentials);
|
||
|
|
+ mach_password = cli_credentials_get_nt_hash(credentials, tctx);
|
||
|
|
+ account_name = cli_credentials_get_username(credentials);
|
||
|
|
+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials);
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerReqChallenge\n");
|
||
|
|
+
|
||
|
|
+ r.in.server_name = NULL;
|
||
|
|
+ r.in.computer_name = machine_name;
|
||
|
|
+ r.in.credentials = &credentials1;
|
||
|
|
+ r.out.return_credentials = &credentials2;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Set the first 4 bytes of the client challenge to the same
|
||
|
|
+ * value, this should pass as 5 bytes identical are needed to
|
||
|
|
+ * fail for CVE-2020-1472(ZeroLogon)
|
||
|
|
+ *
|
||
|
|
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497
|
||
|
|
+ */
|
||
|
|
+ credentials1.data[0] = 'A';
|
||
|
|
+ credentials1.data[1] = 'A';
|
||
|
|
+ credentials1.data[2] = 'A';
|
||
|
|
+ credentials1.data[3] = 'A';
|
||
|
|
+ credentials1.data[4] = 'B';
|
||
|
|
+ credentials1.data[5] = 'C';
|
||
|
|
+ credentials1.data[6] = 'D';
|
||
|
|
+ credentials1.data[7] = 'E';
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ r.out.result,
|
||
|
|
+ "ServerReqChallenge failed");
|
||
|
|
+ a.in.server_name = NULL;
|
||
|
|
+ a.in.account_name = account_name;
|
||
|
|
+ a.in.secure_channel_type = sec_chan_type;
|
||
|
|
+ a.in.computer_name = machine_name;
|
||
|
|
+ a.in.negotiate_flags = &in_negotiate_flags;
|
||
|
|
+ a.out.negotiate_flags = &out_negotiate_flags;
|
||
|
|
+ a.in.credentials = &credentials3;
|
||
|
|
+ a.out.return_credentials = &credentials3;
|
||
|
|
+
|
||
|
|
+ creds = netlogon_creds_client_init(tctx, a.in.account_name,
|
||
|
|
+ a.in.computer_name,
|
||
|
|
+ a.in.secure_channel_type,
|
||
|
|
+ &credentials1, &credentials2,
|
||
|
|
+ mach_password, &credentials3,
|
||
|
|
+ in_negotiate_flags);
|
||
|
|
+
|
||
|
|
+ torture_assert(tctx, creds != NULL, "memory allocation");
|
||
|
|
+
|
||
|
|
+ torture_comment(tctx, "Testing ServerAuthenticate2\n");
|
||
|
|
+
|
||
|
|
+ torture_assert_ntstatus_ok(
|
||
|
|
+ tctx,
|
||
|
|
+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a),
|
||
|
|
+ "ServerAuthenticate2 failed");
|
||
|
|
+ torture_assert_ntstatus_equal(
|
||
|
|
+ tctx,
|
||
|
|
+ a.out.result,
|
||
|
|
+ NT_STATUS_OK,
|
||
|
|
+ "ServerAuthenticate2 unexpected");
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
try a change password for our machine account
|
||
|
|
*/
|
||
|
|
@@ -4954,6 +5273,22 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx)
|
||
|
|
torture_rpc_tcase_add_test(tcase, "lsa_over_netlogon", test_lsa_over_netlogon);
|
||
|
|
torture_rpc_tcase_add_test_creds(tcase, "SetupCredentialsDowngrade", test_SetupCredentialsDowngrade);
|
||
|
|
|
||
|
|
+ torture_rpc_tcase_add_test_creds(
|
||
|
|
+ tcase,
|
||
|
|
+ "ServerReqChallenge",
|
||
|
|
+ test_ServerReqChallenge);
|
||
|
|
+ torture_rpc_tcase_add_test_creds(
|
||
|
|
+ tcase,
|
||
|
|
+ "ServerReqChallenge_zero_challenge",
|
||
|
|
+ test_ServerReqChallenge_zero_challenge);
|
||
|
|
+ torture_rpc_tcase_add_test_creds(
|
||
|
|
+ tcase,
|
||
|
|
+ "ServerReqChallenge_5_repeats",
|
||
|
|
+ test_ServerReqChallenge_5_repeats);
|
||
|
|
+ torture_rpc_tcase_add_test_creds(
|
||
|
|
+ tcase,
|
||
|
|
+ "ServerReqChallenge_4_repeats",
|
||
|
|
+ test_ServerReqChallenge_4_repeats);
|
||
|
|
return suite;
|
||
|
|
}
|
||
|
|
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|