From 5492cd8caacfd7c9f84a4d9877bb237ca81a8008 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2022 16:00:36 +0100 Subject: [PATCH 01/40] CVE-2022-38023 docs-xml: improve wording for several options: "takes precedence" -> "overrides" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 8ec62694a94c346e6ba8f3144a417c9984a1c8b9) (cherry picked from commit 1040fa4c23509234af5ca5bf4c190c80183d39b4) --- docs-xml/smbdotconf/logon/rejectmd5clients.xml | 2 +- docs-xml/smbdotconf/security/serverschannel.xml | 2 +- docs-xml/smbdotconf/winbind/rejectmd5servers.xml | 2 +- docs-xml/smbdotconf/winbind/requirestrongkey.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs-xml/smbdotconf/logon/rejectmd5clients.xml b/docs-xml/smbdotconf/logon/rejectmd5clients.xml index 41684ef1080..0bb9f6f6c8e 100644 --- a/docs-xml/smbdotconf/logon/rejectmd5clients.xml +++ b/docs-xml/smbdotconf/logon/rejectmd5clients.xml @@ -10,7 +10,7 @@ You can set this to yes if all domain members support aes. This will prevent downgrade attacks. - This option takes precedence to the 'allow nt4 crypto' option. + This option overrides the 'allow nt4 crypto' option. no diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index b682d086f76..79e4e73a95c 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -59,7 +59,7 @@ See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 - This option takes precedence to the option. + This option overrides the option. server require schannel:LEGACYCOMPUTER1$ = no diff --git a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml index 37656293aa4..151b4676c57 100644 --- a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml +++ b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml @@ -15,7 +15,7 @@ The behavior can be controlled per netbios domain by using 'reject md5 servers:NETBIOSDOMAIN = yes' as option. - This option takes precedence to the option. + This option overrides the option. no diff --git a/docs-xml/smbdotconf/winbind/requirestrongkey.xml b/docs-xml/smbdotconf/winbind/requirestrongkey.xml index 4db62bfb02d..b17620ec8f1 100644 --- a/docs-xml/smbdotconf/winbind/requirestrongkey.xml +++ b/docs-xml/smbdotconf/winbind/requirestrongkey.xml @@ -19,7 +19,7 @@ This option yields precedence to the option. - This option takes precedence to the option. + This option overrides the option. yes -- 2.39.0 From 3d2049c48010dfb4c452a3a430c9974e2d6affac Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2022 16:05:26 +0100 Subject: [PATCH 02/40] CVE-2022-38023 docs-xml: improve wording for several options: "yields precedence" -> "is over-riden" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 830e865ba5648f6520bc552ffd71b61f754b8251) (cherry picked from commit ddafd6dc7706e74e74ce96039ac8006b9b2e05ad) --- docs-xml/smbdotconf/logon/allownt4crypto.xml | 2 +- docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml | 2 +- docs-xml/smbdotconf/security/clientschannel.xml | 2 +- docs-xml/smbdotconf/security/serverschannel.xml | 2 +- docs-xml/smbdotconf/winbind/requirestrongkey.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs-xml/smbdotconf/logon/allownt4crypto.xml b/docs-xml/smbdotconf/logon/allownt4crypto.xml index 03dc8fa93f7..06afcef73b1 100644 --- a/docs-xml/smbdotconf/logon/allownt4crypto.xml +++ b/docs-xml/smbdotconf/logon/allownt4crypto.xml @@ -18,7 +18,7 @@ "allow nt4 crypto = yes" allows weak crypto to be negotiated, maybe via downgrade attacks. - This option yields precedence to the 'reject md5 clients' option. + This option is over-ridden by the 'reject md5 clients' option. no diff --git a/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml index 03531adbfb3..8bccab391cc 100644 --- a/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml +++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml @@ -15,7 +15,7 @@ The behavior can be overwritten per interface name (e.g. lsarpc, netlogon, samr, srvsvc, winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = yes' as option. - This option yields precedence to the implementation specific restrictions. + This option is over-ridden by the implementation specific restrictions. E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY. The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY. diff --git a/docs-xml/smbdotconf/security/clientschannel.xml b/docs-xml/smbdotconf/security/clientschannel.xml index 5b07da95050..d124ad48181 100644 --- a/docs-xml/smbdotconf/security/clientschannel.xml +++ b/docs-xml/smbdotconf/security/clientschannel.xml @@ -23,7 +23,7 @@ Note that for active directory domains this is hardcoded to yes. - This option yields precedence to the option. + This option is over-ridden by the option. yes auto diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index 79e4e73a95c..3e66df1c203 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -23,7 +23,7 @@ If you still have legacy domain members use the option. - This option yields precedence to the option. + This option is over-ridden by the option. diff --git a/docs-xml/smbdotconf/winbind/requirestrongkey.xml b/docs-xml/smbdotconf/winbind/requirestrongkey.xml index b17620ec8f1..9c1c1d7af14 100644 --- a/docs-xml/smbdotconf/winbind/requirestrongkey.xml +++ b/docs-xml/smbdotconf/winbind/requirestrongkey.xml @@ -17,7 +17,7 @@ Note for active directory domain this option is hardcoded to 'yes' - This option yields precedence to the option. + This option is over-ridden by the option. This option overrides the option. -- 2.39.0 From 5644da497df94e202daea09b3f5184c10ef4aa9a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:46:59 +0100 Subject: [PATCH 03/40] CVE-2022-38023 libcli/auth: pass lp_ctx to netlogon_creds_cli_set_global_db() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 992f39a2c8a58301ceeb965f401e29cd64c5a209) (cherry picked from commit deffd8ea00fecbbf61c4a26279176fe0ae3fe438) --- libcli/auth/netlogon_creds_cli.c | 3 ++- libcli/auth/netlogon_creds_cli.h | 2 +- source3/rpc_client/cli_netlogon.c | 2 +- source3/utils/destroy_netlogon_creds_cli.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 0b31dc91b4b..53f70b42f6f 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -201,7 +201,8 @@ static NTSTATUS netlogon_creds_cli_context_common( static struct db_context *netlogon_creds_cli_global_db; -NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db) +NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, + struct db_context **db) { if (netlogon_creds_cli_global_db != NULL) { return NT_STATUS_INVALID_PARAMETER_MIX; diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h index 56a2dd9bc77..2ce5de9d305 100644 --- a/libcli/auth/netlogon_creds_cli.h +++ b/libcli/auth/netlogon_creds_cli.h @@ -31,7 +31,7 @@ struct messaging_context; struct dcerpc_binding_handle; struct db_context; -NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db); +NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struct db_context **db); NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx); void netlogon_creds_cli_close_global_db(void); diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index 505a1d015bc..8590eda9207 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -76,7 +76,7 @@ NTSTATUS rpccli_pre_open_netlogon_creds(void) return NT_STATUS_NO_MEMORY; } - status = netlogon_creds_cli_set_global_db(&global_db); + status = netlogon_creds_cli_set_global_db(lp_ctx, &global_db); TALLOC_FREE(frame); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source3/utils/destroy_netlogon_creds_cli.c b/source3/utils/destroy_netlogon_creds_cli.c index 137ac8393e7..95a650f4654 100644 --- a/source3/utils/destroy_netlogon_creds_cli.c +++ b/source3/utils/destroy_netlogon_creds_cli.c @@ -83,7 +83,7 @@ int main(int argc, const char *argv[]) goto done; } - status = netlogon_creds_cli_set_global_db(&global_db); + status = netlogon_creds_cli_set_global_db(lp_ctx, &global_db); if (!NT_STATUS_IS_OK(status)) { fprintf(stderr, "netlogon_creds_cli_set_global_db failed: %s\n", -- 2.39.0 From 5316869d543457c4b5b524ebb94bc6f28503e719 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:47:33 +0100 Subject: [PATCH 04/40] CVE-2022-38023 libcli/auth: add/use netlogon_creds_cli_warn_options() This warns the admin about insecure options BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (similar to commit 7e7adf86e59e8a673fbe87de46cef0d62221e800) [jsutton@samba.org Replaced call to tevent_cached_getpid() with one to getpid()] (cherry picked from commit ae1f4644245237fe76bb162af8e95c42903e4eca) --- libcli/auth/netlogon_creds_cli.c | 66 ++++++++++++++++++++++++++++++++ libcli/auth/netlogon_creds_cli.h | 2 + 2 files changed, 68 insertions(+) diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 53f70b42f6f..924317d9905 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -204,6 +204,8 @@ static struct db_context *netlogon_creds_cli_global_db; NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struct db_context **db) { + netlogon_creds_cli_warn_options(lp_ctx); + if (netlogon_creds_cli_global_db != NULL) { return NT_STATUS_INVALID_PARAMETER_MIX; } @@ -218,6 +220,8 @@ NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx) struct db_context *global_db; int hash_size, tdb_flags; + netlogon_creds_cli_warn_options(lp_ctx); + if (netlogon_creds_cli_global_db != NULL) { return NT_STATUS_OK; } @@ -258,6 +262,68 @@ void netlogon_creds_cli_close_global_db(void) TALLOC_FREE(netlogon_creds_cli_global_db); } +void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx) +{ + bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx); + bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx); + int global_client_schannel = lpcfg_client_schannel(lp_ctx); + bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx); + static bool warned_global_reject_md5_servers = false; + static bool warned_global_require_strong_key = false; + static bool warned_global_client_schannel = false; + static bool warned_global_seal_secure_channel = false; + static int warned_global_pid = 0; + int current_pid = getpid(); + + if (warned_global_pid != current_pid) { + warned_global_reject_md5_servers = false; + warned_global_require_strong_key = false; + warned_global_client_schannel = false; + warned_global_seal_secure_channel = false; + warned_global_pid = current_pid; + } + + if (!global_reject_md5_servers && !warned_global_reject_md5_servers) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'reject md5 servers = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_reject_md5_servers = true; + } + + if (!global_require_strong_key && !warned_global_require_strong_key) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'require strong key = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_require_strong_key = true; + } + + if (global_client_schannel != true && !warned_global_client_schannel) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'client schannel = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_client_schannel = true; + } + + if (!global_seal_secure_channel && !warned_global_seal_secure_channel) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'winbind sealed pipes = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_secure_channel = true; + } +} + NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, struct messaging_context *msg_ctx, const char *client_account, diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h index 2ce5de9d305..e4e0232e92f 100644 --- a/libcli/auth/netlogon_creds_cli.h +++ b/libcli/auth/netlogon_creds_cli.h @@ -35,6 +35,8 @@ NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struc NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx); void netlogon_creds_cli_close_global_db(void); +void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx); + NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, struct messaging_context *msg_ctx, const char *client_account, -- 2.39.0 From c9accfd5e673f012eb0462cc2f177c3bb31cf66b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 16:16:05 +0100 Subject: [PATCH 05/40] CVE-2022-38023 s3:net: add and use net_warn_member_options() helper This makes sure domain member related 'net' commands print warnings about unsecure smb.conf options. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 1fdf1d55a5dd550bdb16d037b5dc995c33c1a67a) (cherry picked from commit 4dc0b8d0a89b0aea865f8508ca3f0d68f50c6f12) --- source3/utils/net.c | 6 ++++++ source3/utils/net_ads.c | 14 ++++++++++++++ source3/utils/net_dom.c | 2 ++ source3/utils/net_join.c | 2 ++ source3/utils/net_proto.h | 2 ++ source3/utils/net_rpc.c | 10 ++++++++++ source3/utils/net_util.c | 15 +++++++++++++++ 7 files changed, 51 insertions(+) diff --git a/source3/utils/net.c b/source3/utils/net.c index 7c5b6a05be7..2b94ec01747 100644 --- a/source3/utils/net.c +++ b/source3/utils/net.c @@ -83,6 +83,8 @@ enum netr_SchannelType get_sec_channel_type(const char *param) static int net_changetrustpw(struct net_context *c, int argc, const char **argv) { + net_warn_member_options(); + if (net_ads_check_our_domain(c) == 0) return net_ads_changetrustpw(c, argc, argv); @@ -110,6 +112,8 @@ static int net_primarytrust_dumpinfo(struct net_context *c, int argc, return 1; } + net_warn_member_options(); + if (c->opt_stdin) { set_line_buffering(stdin); set_line_buffering(stdout); @@ -191,6 +195,8 @@ static int net_changesecretpw(struct net_context *c, int argc, return 1; } + net_warn_member_options(); + if(c->opt_force) { struct secrets_domain_info1 *info = NULL; struct secrets_domain_info1_change *prev = NULL; diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 19ac9e4533f..edca2304fae 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -1290,6 +1290,8 @@ static int net_ads_status(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + if (!ADS_ERR_OK(ads_startup(c, true, &ads))) { return -1; } @@ -1431,6 +1433,8 @@ static NTSTATUS net_ads_join_ok(struct net_context *c) return NT_STATUS_ACCESS_DENIED; } + net_warn_member_options(); + net_use_krb_machine_account(c); get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip); @@ -1461,6 +1465,8 @@ int net_ads_testjoin(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + /* Display success or failure */ status = net_ads_join_ok(c); if (!NT_STATUS_IS_OK(status)) { @@ -1843,6 +1849,8 @@ int net_ads_join(struct net_context *c, int argc, const char **argv) if (c->display_usage) return net_ads_join_usage(c, argc, argv); + net_warn_member_options(); + if (!modify_config) { werr = check_ads_config(); @@ -2726,6 +2734,8 @@ int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv) return -1; } + net_warn_member_options(); + net_use_krb_machine_account(c); use_in_memory_ccache(); @@ -2995,6 +3005,8 @@ static int net_ads_keytab_add(struct net_context *c, return 0; } + net_warn_member_options(); + d_printf(_("Processing principals to add...\n")); if (!ADS_ERR_OK(ads_startup(c, true, &ads))) { return -1; @@ -3034,6 +3046,8 @@ static int net_ads_keytab_create(struct net_context *c, int argc, const char **a return 0; } + net_warn_member_options(); + if (!ADS_ERR_OK(ads_startup(c, true, &ads))) { return -1; } diff --git a/source3/utils/net_dom.c b/source3/utils/net_dom.c index 1e45c59220c..db6e34e52de 100644 --- a/source3/utils/net_dom.c +++ b/source3/utils/net_dom.c @@ -154,6 +154,8 @@ static int net_dom_join(struct net_context *c, int argc, const char **argv) return net_dom_usage(c, argc, argv); } + net_warn_member_options(); + if (c->opt_host) { server_name = c->opt_host; } diff --git a/source3/utils/net_join.c b/source3/utils/net_join.c index 1493dff74d7..f67f08f79a8 100644 --- a/source3/utils/net_join.c +++ b/source3/utils/net_join.c @@ -39,6 +39,8 @@ int net_join(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + if (net_ads_check_our_domain(c) == 0) { if (net_ads_join(c, argc, argv) == 0) return 0; diff --git a/source3/utils/net_proto.h b/source3/utils/net_proto.h index 22fe39e0f1c..38581a796cb 100644 --- a/source3/utils/net_proto.h +++ b/source3/utils/net_proto.h @@ -423,6 +423,8 @@ int net_run_function(struct net_context *c, int argc, const char **argv, const char *whoami, struct functable *table); void net_display_usage_from_functable(struct functable *table); +void net_warn_member_options(void); + const char *net_share_type_str(int num_type); NTSTATUS net_scan_dc(struct net_context *c, diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index a56190f7be5..90e602535de 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -370,6 +370,8 @@ static int net_rpc_oldjoin(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + mem_ctx = talloc_init("net_rpc_oldjoin"); if (!mem_ctx) { return -1; @@ -489,6 +491,8 @@ int net_rpc_testjoin(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + mem_ctx = talloc_init("net_rpc_testjoin"); if (!mem_ctx) { return -1; @@ -563,6 +567,8 @@ static int net_rpc_join_newstyle(struct net_context *c, int argc, const char **a return 0; } + net_warn_member_options(); + mem_ctx = talloc_init("net_rpc_join_newstyle"); if (!mem_ctx) { return -1; @@ -684,6 +690,8 @@ int net_rpc_join(struct net_context *c, int argc, const char **argv) return -1; } + net_warn_member_options(); + if (strlen(lp_netbios_name()) > 15) { d_printf(_("Our netbios name can be at most 15 chars long, " "\"%s\" is %u chars long\n"), @@ -814,6 +822,8 @@ int net_rpc_info(struct net_context *c, int argc, const char **argv) return 0; } + net_warn_member_options(); + return run_rpc_command(c, NULL, &ndr_table_samr, NET_FLAGS_PDC, rpc_info_internals, argc, argv); diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c index a84b4f5500e..f88559b0e96 100644 --- a/source3/utils/net_util.c +++ b/source3/utils/net_util.c @@ -29,6 +29,8 @@ #include "secrets.h" #include "../libcli/security/security.h" #include "libsmb/libsmb.h" +#include "lib/param/param.h" +#include "libcli/auth/netlogon_creds_cli.h" NTSTATUS net_rpc_lookup_name(struct net_context *c, TALLOC_CTX *mem_ctx, struct cli_state *cli, @@ -534,6 +536,19 @@ void net_display_usage_from_functable(struct functable *table) } } +void net_warn_member_options(void) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct loadparm_context *lp_ctx = NULL; + + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); + if (lp_ctx != NULL) { + netlogon_creds_cli_warn_options(lp_ctx); + } + + TALLOC_FREE(frame); +} + const char *net_share_type_str(int num_type) { switch(num_type) { -- 2.39.0 From 36aa077cf0625964f708bfa35ce9bea7cd1823b5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:59:36 +0100 Subject: [PATCH 06/40] CVE-2022-38023 s3:winbindd: also allow per domain "winbind sealed pipes:DOMAIN" and "require strong key:DOMAIN" This avoids advising insecure defaults for the global options. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit d60828f6391307a59abaa02b72b6a8acf66b2fef) (cherry picked from commit f1cb8950583c12eaa5cbe907d0b16923f7187541) --- source3/winbindd/winbindd_cm.c | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 0e671ca22be..c052dfedefa 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -2725,6 +2725,8 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context *p_creds; struct cli_credentials *creds = NULL; bool retry = false; /* allow one retry attempt for expired session */ + bool sealed_pipes = true; + bool strong_key = true; if (sid_check_is_our_sam(&domain->sid)) { if (domain->rodc == false || need_rw_dc == false) { @@ -2898,14 +2900,24 @@ retry: anonymous: + sealed_pipes = lp_winbind_sealed_pipes(); + sealed_pipes = lp_parm_bool(-1, "winbind sealed pipes", + domain->name, + sealed_pipes); + strong_key = lp_require_strong_key(); + strong_key = lp_parm_bool(-1, "require strong key", + domain->name, + strong_key); + /* Finally fall back to anonymous. */ - if (lp_winbind_sealed_pipes() || lp_require_strong_key()) { + if (sealed_pipes || strong_key) { status = NT_STATUS_DOWNGRADE_DETECTED; DEBUG(1, ("Unwilling to make SAMR connection to domain %s " "without connection level security, " - "must set 'winbind sealed pipes = false' and " - "'require strong key = false' to proceed: %s\n", - domain->name, nt_errstr(status))); + "must set 'winbind sealed pipes:%s = false' and " + "'require strong key:%s = false' to proceed: %s\n", + domain->name, domain->name, domain->name, + nt_errstr(status))); goto done; } status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr, @@ -3052,6 +3064,8 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context *p_creds; struct cli_credentials *creds = NULL; bool retry = false; /* allow one retry attempt for expired session */ + bool sealed_pipes = true; + bool strong_key = true; retry: result = init_dc_connection_rpc(domain, false); @@ -3207,13 +3221,24 @@ retry: goto done; } - if (lp_winbind_sealed_pipes() || lp_require_strong_key()) { + sealed_pipes = lp_winbind_sealed_pipes(); + sealed_pipes = lp_parm_bool(-1, "winbind sealed pipes", + domain->name, + sealed_pipes); + strong_key = lp_require_strong_key(); + strong_key = lp_parm_bool(-1, "require strong key", + domain->name, + strong_key); + + /* Finally fall back to anonymous. */ + if (sealed_pipes || strong_key) { result = NT_STATUS_DOWNGRADE_DETECTED; DEBUG(1, ("Unwilling to make LSA connection to domain %s " "without connection level security, " - "must set 'winbind sealed pipes = false' and " - "'require strong key = false' to proceed: %s\n", - domain->name, nt_errstr(result))); + "must set 'winbind sealed pipes:%s = false' and " + "'require strong key:%s = false' to proceed: %s\n", + domain->name, domain->name, domain->name, + nt_errstr(result))); goto done; } -- 2.39.0 From 1b31a7a1ced167950f36231a2405485e0d027e47 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 24 Nov 2022 18:22:23 +0100 Subject: [PATCH 07/40] CVE-2022-38023 docs-xml/smbdotconf: change 'reject md5 servers' default to yes AES is supported by Windows >= 2008R2 and Samba >= 4.0 so there's no reason to allow md5 servers by default. Note the change in netlogon_creds_cli_context_global() is only cosmetic, but avoids confusion while reading the code. Check with: git show -U35 libcli/auth/netlogon_creds_cli.c BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 1c6c1129905d0c7a60018e7bf0f17a0fd198a584) (cherry picked from commit 18bcf0b6496d4ed9d76d23f82674935bd275dc3b) --- docs-xml/smbdotconf/winbind/rejectmd5servers.xml | 7 +++++-- lib/param/loadparm.c | 1 + libcli/auth/netlogon_creds_cli.c | 4 ++-- source3/param/loadparm.c | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml index 151b4676c57..3bc4eaf7b02 100644 --- a/docs-xml/smbdotconf/winbind/rejectmd5servers.xml +++ b/docs-xml/smbdotconf/winbind/rejectmd5servers.xml @@ -13,10 +13,13 @@ This will prevent downgrade attacks. The behavior can be controlled per netbios domain - by using 'reject md5 servers:NETBIOSDOMAIN = yes' as option. + by using 'reject md5 servers:NETBIOSDOMAIN = no' as option. + + The default changed from 'no' to 'yes, with the patches for CVE-2022-38023, + see https://bugzilla.samba.org/show_bug.cgi?id=15240 This option overrides the option. -no +yes diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index e0c6adec9c8..0aa8b1df65a 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2749,6 +2749,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "winbind sealed pipes", "True"); lpcfg_do_global_parameter(lp_ctx, "winbind scan trusted domains", "True"); lpcfg_do_global_parameter(lp_ctx, "require strong key", "True"); + lpcfg_do_global_parameter(lp_ctx, "reject md5 servers", "True"); lpcfg_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR); lpcfg_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR); lpcfg_do_global_parameter_var(lp_ctx, "gpo update command", "%s/samba-gpupdate", dyn_SCRIPTSBINDIR); diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index 924317d9905..0ee1c66147c 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -340,8 +340,8 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx, const char *client_computer; uint32_t proposed_flags; uint32_t required_flags = 0; - bool reject_md5_servers = false; - bool require_strong_key = false; + bool reject_md5_servers = true; + bool require_strong_key = true; int require_sign_or_seal = true; bool seal_secure_channel = true; enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 5ee6d33c7fc..69e053fc98f 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -656,6 +656,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.client_schannel = true; Globals.winbind_sealed_pipes = true; Globals.require_strong_key = true; + Globals.reject_md5_servers = true; Globals.server_schannel = true; Globals.read_raw = true; Globals.write_raw = true; -- 2.39.0 From 2966f89be4b8bc0fdc06761af4aa07032d02c112 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 Dec 2022 10:56:29 +0100 Subject: [PATCH 08/40] CVE-2022-38023 s4:rpc_server/netlogon: 'server schannel != yes' warning to dcesrv_interface_netlogon_bind This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit e060ea5b3edbe3cba492062c9605f88fae212ee0) (cherry picked from commit de121d6c613c6e83e49f2622391d1705077646a4) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 63e2821cac7..d3bfb79c674 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -60,6 +60,21 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface) { + struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx; + int schannel = lpcfg_server_schannel(lp_ctx); + bool schannel_global_required = (schannel == true); + static bool warned_global_schannel_once = false; + + if (!schannel_global_required && !warned_global_schannel_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2020-1472(ZeroLogon): " + "Please configure 'server schannel = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); + warned_global_schannel_once = true; + } + return dcesrv_interface_bind_reject_connect(context, iface); } @@ -628,7 +643,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; - static bool warned_global_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -680,16 +694,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc 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 " -- 2.39.0 From 235f33dfbad2de997ebb4887948a54208f1c6447 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Dec 2022 14:03:50 +0100 Subject: [PATCH 09/40] CVE-2022-38023 s4:rpc_server/netlogon: add a lp_ctx variable to dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 7baabbe9819cd5a2714e7ea4e57a0c23062c0150) (cherry picked from commit 9669a41693b8da410cf57e21f2de7c7e6e4c4235) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index d3bfb79c674..e5316022588 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -634,8 +634,9 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out) { + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; NTSTATUS nt_status; - int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); + int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; @@ -651,7 +652,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc dcesrv_call_auth_info(dce_call, &auth_type, NULL); nt_status = schannel_check_creds_state(mem_ctx, - dce_call->conn->dce_ctx->lp_ctx, + lp_ctx, computer_name, received_authenticator, return_authenticator, @@ -666,7 +667,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc * need the explicit_opt pointer in order to * adjust the debug messages. */ - explicit_opt = lpcfg_get_parametric(dce_call->conn->dce_ctx->lp_ctx, + explicit_opt = lpcfg_get_parametric(lp_ctx, NULL, "server require schannel", creds->account_name); -- 2.39.0 From 2ad6426eac5ce148f20e058067b6c1b4d7220979 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Dec 2022 14:03:50 +0100 Subject: [PATCH 10/40] CVE-2022-38023 s4:rpc_server/netlogon: add talloc_stackframe() to dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 0e6a2ba83ef1be3c6a0f5514c21395121621a145) (cherry picked from commit b9269801ed6bc034da924cdedd0b6a2938a1379f) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index e5316022588..d676f0ca878 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -635,6 +635,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc struct netlogon_creds_CredentialState **creds_out) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS nt_status; int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); @@ -678,6 +679,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -685,13 +687,15 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "%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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name)); TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); + TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } @@ -700,13 +704,14 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "%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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + log_escape(frame, creds->account_name)); *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -716,24 +721,25 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "%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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + log_escape(frame, 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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + log_escape(frame, creds->account_name)); } *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } -- 2.39.0 From a6b15a811fba73b035139c54db4497eb7d8dcf88 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 12:37:03 +0100 Subject: [PATCH 11/40] CVE-2022-38023 s4:rpc_server/netlogon: re-order checking in dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit ec62151a2fb49ecbeaa3bf924f49a956832b735e) (cherry picked from commit 643b4c1b95e40e46af14afa60aa42b0fcf1cf446) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index d676f0ca878..b6d4139d75c 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -676,13 +676,27 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc schannel_required = lp_bool(explicit_opt); } - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (!schannel_required) { + 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(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } + if (explicit_opt != NULL && !schannel_required) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed!?\n", + log_escape(frame, creds->account_name)); } + *creds_out = creds; + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + if (schannel_required) { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", @@ -699,23 +713,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc return NT_STATUS_ACCESS_DENIED; } - 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); - - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; - } - - if (explicit_opt != NULL) { DBG_INFO("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " -- 2.39.0 From b0dca8597391e5b25d175727912e43ceb8c77f31 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 12:37:03 +0100 Subject: [PATCH 12/40] CVE-2022-38023 s4:rpc_server/netlogon: improve CVE-2020-1472(ZeroLogon) debug messages In order to avoid generating useless debug messages during make test, we will use 'CVE_2020_1472:warn_about_unused_debug_level = 3' and 'CVE_2020_1472:error_debug_level = 2' in order to avoid schannel warnings. Review with: git show -w BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 16ee03efc194d9c1c2c746f63236b977a419918d) (cherry picked from commit e02e8ad46b02a4c16f575b6371eea8ea66dee067) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 147 +++++++++++++----- 1 file changed, 106 insertions(+), 41 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index b6d4139d75c..94cadca8247 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -642,15 +642,34 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; struct netlogon_creds_CredentialState *creds = NULL; + int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + unsigned int dbg_lvl = DBGLVL_DEBUG; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; + const char *reason = ""; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; } - dcesrv_call_auth_info(dce_call, &auth_type, NULL); + dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); + + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + reason = "WITH SEALED"; + } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + reason = "WITH SIGNED"; + } else { + smb_panic("Schannel without SIGN/SEAL"); + } + } else { + reason = "WITHOUT"; + } nt_status = schannel_check_creds_state(mem_ctx, lp_ctx, @@ -677,62 +696,108 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc } if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (!schannel_required) { - 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); + nt_status = NT_STATUS_OK; + + if (explicit_opt != NULL && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(nt_status))); + if (explicit_opt != NULL && !schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; TALLOC_FREE(frame); - return NT_STATUS_OK; + return nt_status; } if (schannel_required) { - 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' " - "might be needed for a legacy client.\n", - log_escape(frame, creds->account_name)); + nt_status = NT_STATUS_ACCESS_DENIED; + + if (explicit_opt != NULL) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(nt_status))); + if (explicit_opt != NULL) { + D_NOTICE("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); - return NT_STATUS_ACCESS_DENIED; + return nt_status; } + nt_status = 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' still needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' might be needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(nt_status))); + + if (explicit_opt != NULL) { + D_INFO("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server require schannel:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): " + "Please use 'server require schannel:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; -- 2.39.0 From 9278539cca368e0409e0910b6139eb0344407e81 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 12:26:01 +0100 Subject: [PATCH 13/40] CVE-2022-38023 selftest:Samba4: avoid global 'server schannel = auto' Instead of using the generic deprecated option use the specific server require schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 63c96ea6c02981795e67336401143f2a8836992c) (cherry picked from commit 0be35930722530e5befa16a65a16232393258057) --- selftest/target/Samba4.pm | 40 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 4758a5513d1..93463f9f18b 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1580,7 +1580,24 @@ sub provision_ad_dc_ntvfs($$$) dsdb event notification = true dsdb password event notification = true dsdb group change notification = true - server schannel = auto + + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + + # needed for 'samba.tests.auth_log' tests + server require schannel:LOCALDC\$ = no "; push (@{$extra_provision_options}, "--use-ntvfs"); my $ret = $self->provision($prefix, @@ -1917,8 +1934,25 @@ sub provision_ad_dc($$$$$$) lpq cache time = 0 print notify backchannel = yes - server schannel = auto - auth event notification = true + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + + # needed for 'samba.tests.auth_log' tests + server require schannel:ADDC\$ = no + + auth event notification = true dsdb event notification = true dsdb password event notification = true dsdb group change notification = true -- 2.39.0 From 8501a1e00bc36fd80f544d0ec5a82269db4002d7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 28 Nov 2022 15:02:13 +0100 Subject: [PATCH 14/40] CVE-2022-38023 s4:torture: use NETLOGON_NEG_SUPPORTS_AES by default For generic tests we should use the best available features. And AES will be required by default soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit cfd55a22cda113fbb2bfa373b54091dde1ea6e66) (cherry picked from commit 90f06ad6d7d00fc51a2d64557cf58739fef851c1) --- source4/torture/ntp/ntp_signd.c | 2 +- source4/torture/rpc/lsa.c | 4 ++-- source4/torture/rpc/netlogon.c | 20 ++++++++++---------- source4/torture/rpc/samba3rpc.c | 15 ++++++++++++--- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/source4/torture/ntp/ntp_signd.c b/source4/torture/ntp/ntp_signd.c index 124c9604871..6d482bfdee1 100644 --- a/source4/torture/ntp/ntp_signd.c +++ b/source4/torture/ntp/ntp_signd.c @@ -70,7 +70,7 @@ static bool test_ntp_signd(struct torture_context *tctx, uint32_t rid; const char *machine_name; const struct samr_Password *pwhash = cli_credentials_get_nt_hash(credentials, mem_ctx); - uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + uint32_t negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; struct sign_request sign_req; struct signed_reply signed_reply; diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index 52370f4fe8e..2ce2db69859 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -4285,7 +4285,7 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p, torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b"); ok = check_pw_with_ServerAuthenticate3(p1, tctx, - NETLOGON_NEG_AUTH2_ADS_FLAGS, + NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, server_name, incoming_creds, &creds); torture_assert_int_equal(tctx, ok, expected_result, @@ -4382,7 +4382,7 @@ static bool check_dom_trust_pw(struct dcerpc_pipe *p, torture_assert_ntstatus_ok(tctx, status, "dcerpc_pipe_connect_b"); ok = check_pw_with_ServerAuthenticate3(p2, tctx, - NETLOGON_NEG_AUTH2_ADS_FLAGS, + NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, server_name, incoming_creds, &creds); torture_assert(tctx, ok, "check_pw_with_ServerAuthenticate3 with changed password"); diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index da4d407c627..0f6f43d4637 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -189,7 +189,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, /* This allows the tests to continue against the more fussy windows 2008 */ if (NT_STATUS_EQUAL(a.out.result, NT_STATUS_DOWNGRADE_DETECTED)) { - return test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + return test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, credentials, cli_credentials_get_secure_channel_type(credentials), creds_out); @@ -429,7 +429,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx, "ServerAuthenticate3 failed"); torture_assert_ntstatus_equal(tctx, a.out.result, NT_STATUS_DOWNGRADE_DETECTED, "ServerAuthenticate3 should have failed"); - negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; creds = netlogon_creds_client_init(tctx, a.in.account_name, a.in.computer_name, a.in.secure_channel_type, @@ -496,7 +496,7 @@ static bool test_ServerReqChallenge( 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 in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -568,7 +568,7 @@ static bool test_ServerReqChallenge_zero_challenge( 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 in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -645,7 +645,7 @@ static bool test_ServerReqChallenge_5_repeats( 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 in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -729,7 +729,7 @@ static bool test_ServerReqChallenge_4_repeats( 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 in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; uint32_t out_negotiate_flags = 0; const struct samr_Password *mach_password = NULL; enum netr_SchannelType sec_chan_type = 0; @@ -1170,7 +1170,7 @@ static bool test_SetPassword2(struct torture_context *tctx, struct dcerpc_pipe *p, struct cli_credentials *machine_credentials) { - return test_SetPassword2_with_flags(tctx, p, machine_credentials, NETLOGON_NEG_AUTH2_ADS_FLAGS); + return test_SetPassword2_with_flags(tctx, p, machine_credentials, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES); } static bool test_SetPassword2_AES(struct torture_context *tctx, @@ -3464,7 +3464,7 @@ static bool test_netr_GetForestTrustInformation(struct torture_context *tctx, struct dcerpc_pipe *p = NULL; struct dcerpc_binding_handle *b = NULL; - if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, machine_credentials, &creds)) { return false; } @@ -4403,7 +4403,7 @@ static bool test_GetDomainInfo(struct torture_context *tctx, torture_comment(tctx, "Testing netr_LogonGetDomainInfo\n"); - if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p1, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, machine_credentials, &creds)) { return false; } @@ -4978,7 +4978,7 @@ static bool test_GetDomainInfo_async(struct torture_context *tctx, torture_comment(tctx, "Testing netr_LogonGetDomainInfo - async count %d\n", ASYNC_COUNT); - if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS, + if (!test_SetupCredentials3(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES, machine_credentials, &creds)) { return false; } diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index bf1de04a5b5..158b42bed0c 100644 --- a/source4/torture/rpc/samba3rpc.c +++ b/source4/torture/rpc/samba3rpc.c @@ -1077,7 +1077,7 @@ static bool auth2(struct torture_context *tctx, goto done; } - negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; E_md4hash(cli_credentials_get_password(wks_cred), mach_pw.hash); a.in.server_name = talloc_asprintf( @@ -1266,10 +1266,19 @@ static bool schan(struct torture_context *tctx, E_md4hash(cli_credentials_get_password(user_creds), pinfo.ntpassword.hash); - netlogon_creds_arcfour_crypt(creds_state, pinfo.ntpassword.hash, 16); - logon.password = &pinfo; + /* + * We don't use this here: + * + * netlogon_creds_encrypt_samlogon_logon(creds_state, + * NetlogonInteractiveInformation, + * &logon); + * + * in order to detect bugs + */ + netlogon_creds_aes_encrypt(creds_state, pinfo.ntpassword.hash, 16); + r.in.logon_level = NetlogonInteractiveInformation; r.in.logon = &logon; r.out.return_authenticator = &return_authenticator; -- 2.39.0 From bb0647a86d290f797d486f0a5e3e9dfffb2ee6f8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 09:54:17 +0100 Subject: [PATCH 15/40] CVE-2022-38023 s4:rpc_server/netlogon: split out dcesrv_netr_ServerAuthenticate3_check_downgrade() We'll soon make it possible to use 'reject md5 servers:CLIENTACCOUNT$ = no', which means we'll need the downgrade detection in more places. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit b6339fd1dcbe903e73efeea074ab0bd04ef83561) (cherry picked from commit 33a814d745c0c2dd4e49582fbee892471620bfcd) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 114 ++++++++++-------- 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 94cadca8247..f8bc26f50d9 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -128,6 +128,67 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal return NT_STATUS_OK; } +static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( + struct dcesrv_call_state *dce_call, + struct netr_ServerAuthenticate3 *r, + struct netlogon_server_pipe_state *pipe_state, + uint32_t negotiate_flags, + NTSTATUS orig_status) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); + bool reject_des_client = !allow_nt4_crypto; + bool reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); + + if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { + reject_des_client = false; + } + + if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + reject_des_client = false; + reject_md5_client = false; + } + + if (reject_des_client || reject_md5_client) { + /* + * Here we match Windows 2012 and return no flags. + */ + *r->out.negotiate_flags = 0; + return NT_STATUS_DOWNGRADE_DETECTED; + } + + /* + * This talloc_free is important to prevent re-use of the + * challenge. We have to delay it this far due to NETApp + * servers per: + * https://bugzilla.samba.org/show_bug.cgi?id=11291 + */ + TALLOC_FREE(pipe_state); + + /* + * At this point we must also cleanup the TDB cache + * entry, if we fail the client needs to call + * netr_ServerReqChallenge again. + * + * Note: this handles a non existing record just fine, + * the r->in.computer_name might not be the one used + * in netr_ServerReqChallenge(), but we are trying to + * just tidy up the normal case to prevent re-use. + */ + schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx, + r->in.computer_name); + + /* + * According to Microsoft (see bugid #6099) + * Windows 7 looks at the negotiate_flags + * returned in this structure *even if the + * call fails with access denied! + */ + *r->out.negotiate_flags = negotiate_flags; + + return orig_status; +} + /* * Do the actual processing of a netr_ServerAuthenticate3 message. * called from dcesrv_netr_ServerAuthenticate3, which handles the logging. @@ -155,11 +216,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( "objectSid", "samAccountName", NULL}; uint32_t server_flags = 0; uint32_t negotiate_flags = 0; - bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(dce_call->conn->dce_ctx->lp_ctx); - bool reject_des_client = !allow_nt4_crypto; - bool reject_md5_client = lpcfg_reject_md5_clients(dce_call->conn->dce_ctx->lp_ctx); ZERO_STRUCTP(r->out.return_credentials); + *r->out.negotiate_flags = 0; *r->out.rid = 0; pipe_state = dcesrv_iface_state_find_conn(dce_call, @@ -238,52 +297,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( negotiate_flags = *r->in.negotiate_flags & server_flags; - if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { - reject_des_client = false; - } - - if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { - reject_des_client = false; - reject_md5_client = false; - } - - if (reject_des_client || reject_md5_client) { - /* - * Here we match Windows 2012 and return no flags. - */ - *r->out.negotiate_flags = 0; - return NT_STATUS_DOWNGRADE_DETECTED; + nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_OK); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; } - /* - * This talloc_free is important to prevent re-use of the - * challenge. We have to delay it this far due to NETApp - * servers per: - * https://bugzilla.samba.org/show_bug.cgi?id=11291 - */ - TALLOC_FREE(pipe_state); - - /* - * At this point we must also cleanup the TDB cache - * entry, if we fail the client needs to call - * netr_ServerReqChallenge again. - * - * Note: this handles a non existing record just fine, - * the r->in.computer_name might not be the one used - * in netr_ServerReqChallenge(), but we are trying to - * just tidy up the normal case to prevent re-use. - */ - schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx, - r->in.computer_name); - - /* - * According to Microsoft (see bugid #6099) - * Windows 7 looks at the negotiate_flags - * returned in this structure *even if the - * call fails with access denied! - */ - *r->out.negotiate_flags = negotiate_flags; - switch (r->in.secure_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_DNS_DOMAIN: -- 2.39.0 From 66ace90dd68b20f14668d9437a4af12b862f3c79 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 24 Nov 2022 18:26:18 +0100 Subject: [PATCH 16/40] CVE-2022-38023 docs-xml/smbdotconf: change 'reject md5 clients' default to yes AES is supported by Windows Server >= 2008R2, Windows (Client) >= 7 and Samba >= 4.0, so there's no reason to allow md5 clients by default. However some third party domain members may need it. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit c8e53394b98b128ed460a6111faf05dfbad980d1) (cherry picked from commit ade168df393064dd25a6e540e06332dcd1803297) --- docs-xml/smbdotconf/logon/rejectmd5clients.xml | 11 ++++++++--- lib/param/loadparm.c | 1 + selftest/target/Samba4.pm | 4 ++++ source3/param/loadparm.c | 1 + 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs-xml/smbdotconf/logon/rejectmd5clients.xml b/docs-xml/smbdotconf/logon/rejectmd5clients.xml index 0bb9f6f6c8e..edcbe02e99a 100644 --- a/docs-xml/smbdotconf/logon/rejectmd5clients.xml +++ b/docs-xml/smbdotconf/logon/rejectmd5clients.xml @@ -7,11 +7,16 @@ only in 'active directory domain controller' mode), will reject clients which does not support NETLOGON_NEG_SUPPORTS_AES. - You can set this to yes if all domain members support aes. - This will prevent downgrade attacks. + Support for NETLOGON_NEG_SUPPORTS_AES was added in Windows + starting with Server 2008R2 and Windows 7, it's available in Samba + starting with 4.0, however third party domain members like NetApp ONTAP + still uses RC4 (HMAC-MD5), see https://www.samba.org/samba/security/CVE-2022-38023.html for more details. + + The default changed from 'no' to 'yes', with the patches for CVE-2022-38023, + see https://bugzilla.samba.org/show_bug.cgi?id=15240 This option overrides the 'allow nt4 crypto' option. -no +yes diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 0aa8b1df65a..6a5b88cd43e 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2805,6 +2805,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "winbind nss info", "template"); lpcfg_do_global_parameter(lp_ctx, "server schannel", "True"); + lpcfg_do_global_parameter(lp_ctx, "reject md5 clients", "True"); lpcfg_do_global_parameter(lp_ctx, "short preserve case", "True"); diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 93463f9f18b..2f96f4be3eb 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1581,6 +1581,8 @@ sub provision_ad_dc_ntvfs($$$) dsdb password event notification = true dsdb group change notification = true + reject md5 clients = no + CVE_2020_1472:warn_about_unused_debug_level = 3 server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no @@ -1934,6 +1936,8 @@ sub provision_ad_dc($$$$$$) lpq cache time = 0 print notify backchannel = yes + reject md5 clients = no + CVE_2020_1472:warn_about_unused_debug_level = 3 server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 69e053fc98f..14d546d740b 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -658,6 +658,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.require_strong_key = true; Globals.reject_md5_servers = true; Globals.server_schannel = true; + Globals.reject_md5_clients = true; Globals.read_raw = true; Globals.write_raw = true; Globals.null_passwords = false; -- 2.39.0 From 450a9bf44b11b46b927aae2059c9ba0c8f10f86a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 10:31:08 +0100 Subject: [PATCH 17/40] CVE-2022-38023 s4:rpc_server/netlogon: defer downgrade check until we found the account in our SAM We'll soon make it possible to use 'reject md5 servers:CLIENTACCOUNT$ = no', which means we'll need use the account name from our SAM. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit b09f51eefc311bbb1525efd1dc7b9a837f7ec3c2) (cherry picked from commit 5154471bca2162c14c91ebd02148be521e333817) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index f8bc26f50d9..8829dd3c342 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -297,13 +297,6 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( negotiate_flags = *r->in.negotiate_flags & server_flags; - nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( - dce_call, r, pipe_state, negotiate_flags, - NT_STATUS_OK); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - switch (r->in.secure_channel_type) { case SEC_CHAN_WKSTA: case SEC_CHAN_DNS_DOMAIN: @@ -312,11 +305,15 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( case SEC_CHAN_RODC: break; case SEC_CHAN_NULL: - return NT_STATUS_INVALID_PARAMETER; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INVALID_PARAMETER); default: DEBUG(1, ("Client asked for an invalid secure channel type: %d\n", r->in.secure_channel_type)); - return NT_STATUS_INVALID_PARAMETER; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INVALID_PARAMETER); } sam_ctx = samdb_connect(mem_ctx, @@ -326,7 +323,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( dce_call->conn->remote_address, 0); if (sam_ctx == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INVALID_SYSTEM_SERVICE); } if (r->in.secure_channel_type == SEC_CHAN_DOMAIN || @@ -355,16 +354,22 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( encoded_name = ldb_binary_encode_string(mem_ctx, r->in.account_name); if (encoded_name == NULL) { - return NT_STATUS_NO_MEMORY; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_MEMORY); } len = strlen(encoded_name); if (len < 2) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (require_trailer && encoded_name[len - 1] != trailer) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } encoded_name[len - 1] = '\0'; @@ -382,30 +387,42 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( "but there's no tdo for [%s] => [%s] \n", log_escape(mem_ctx, r->in.account_name), encoded_name)); - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + nt_status); } nt_status = dsdb_trust_get_incoming_passwords(tdo_msg, mem_ctx, &curNtHash, &prevNtHash); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + nt_status); } flatname = ldb_msg_find_attr_as_string(tdo_msg, "flatName", NULL); if (flatname == NULL) { - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } *trust_account_for_search = talloc_asprintf(mem_ctx, "%s$", flatname); if (*trust_account_for_search == NULL) { - return NT_STATUS_NO_MEMORY; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_MEMORY); } } else { *trust_account_for_search = r->in.account_name; @@ -420,14 +437,18 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (num_records == 0) { DEBUG(3,("Couldn't find user [%s] in samdb.\n", log_escape(mem_ctx, r->in.account_name))); - return NT_STATUS_NO_TRUST_SAM_ACCOUNT; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (num_records > 1) { DEBUG(0,("Found %d records matching user [%s]\n", num_records, log_escape(mem_ctx, r->in.account_name))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INTERNAL_DB_CORRUPTION); } *trust_account_in_db = ldb_msg_find_attr_as_string(msgs[0], @@ -436,9 +457,18 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (*trust_account_in_db == NULL) { DEBUG(0,("No samAccountName returned in record matching user [%s]\n", r->in.account_name)); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + return dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_INTERNAL_DB_CORRUPTION); } - + + nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( + dce_call, r, pipe_state, negotiate_flags, + NT_STATUS_OK); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0); if (user_account_control & UF_ACCOUNTDISABLE) { -- 2.39.0 From 9fc01859b77bb22ce52e90a6dafbea5fb18d192d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 13:13:36 +0100 Subject: [PATCH 18/40] CVE-2022-38023 s4:rpc_server/netlogon: add 'server reject md5 schannel:COMPUTERACCOUNT = no' and 'allow nt4 crypto:COMPUTERACCOUNT = yes' This makes it more flexible when we change the global default to 'reject md5 servers = yes'. 'allow nt4 crypto = no' is already the default. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 69b36541606d7064de9648cd54b35adfdf8f0e8f) (cherry picked from commit a0c68f4caaa0771dcde074906956335c9e458bdf) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 8829dd3c342..c593b7903a8 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -133,12 +133,48 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( struct netr_ServerAuthenticate3 *r, struct netlogon_server_pipe_state *pipe_state, uint32_t negotiate_flags, + const char *trust_account_in_db, NTSTATUS orig_status) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; - bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); - bool reject_des_client = !allow_nt4_crypto; - bool reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); + bool global_allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); + bool account_allow_nt4_crypto = global_allow_nt4_crypto; + const char *explicit_nt4_opt = NULL; + bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); + bool account_reject_md5_client = global_reject_md5_client; + const char *explicit_md5_opt = NULL; + bool reject_des_client; + bool allow_nt4_crypto; + bool reject_md5_client; + + /* + * We don't use lpcfg_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + + if (trust_account_in_db != NULL) { + explicit_nt4_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "allow nt4 crypto", + trust_account_in_db); + } + if (explicit_nt4_opt != NULL) { + account_allow_nt4_crypto = lp_bool(explicit_nt4_opt); + } + allow_nt4_crypto = account_allow_nt4_crypto; + if (trust_account_in_db != NULL) { + explicit_md5_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "server reject md5 schannel", + trust_account_in_db); + } + if (explicit_md5_opt != NULL) { + account_reject_md5_client = lp_bool(explicit_md5_opt); + } + reject_md5_client = account_reject_md5_client; + + reject_des_client = !allow_nt4_crypto; if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { reject_des_client = false; @@ -307,12 +343,14 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( case SEC_CHAN_NULL: return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INVALID_PARAMETER); default: DEBUG(1, ("Client asked for an invalid secure channel type: %d\n", r->in.secure_channel_type)); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INVALID_PARAMETER); } @@ -325,6 +363,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (sam_ctx == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INVALID_SYSTEM_SERVICE); } @@ -356,6 +395,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (encoded_name == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_MEMORY); } @@ -363,12 +403,14 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (len < 2) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (require_trailer && encoded_name[len - 1] != trailer) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } encoded_name[len - 1] = '\0'; @@ -389,11 +431,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( encoded_name)); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ nt_status); } @@ -403,11 +447,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } if (!NT_STATUS_IS_OK(nt_status)) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ nt_status); } @@ -415,6 +461,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (flatname == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } @@ -422,6 +469,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( if (*trust_account_for_search == NULL) { return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_MEMORY); } } else { @@ -439,6 +487,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( log_escape(mem_ctx, r->in.account_name))); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_NO_TRUST_SAM_ACCOUNT); } @@ -448,6 +497,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( log_escape(mem_ctx, r->in.account_name))); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INTERNAL_DB_CORRUPTION); } @@ -459,11 +509,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( r->in.account_name)); return dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + NULL, /* trust_account_in_db */ NT_STATUS_INTERNAL_DB_CORRUPTION); } nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade( dce_call, r, pipe_state, negotiate_flags, + *trust_account_in_db, NT_STATUS_OK); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; -- 2.39.0 From 780fb78f24b9edd2db7fdbd8bb6797c34fc1debc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 13:31:14 +0100 Subject: [PATCH 19/40] CVE-2022-38023 docs-xml/smbdotconf: document "allow nt4 crypto:COMPUTERACCOUNT = no" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit bd429d025981b445bf63935063e8e302bfab3f9b) (cherry picked from commit 4cb1e57caaf537c760de95a4a4e300ff8c711dfe) --- docs-xml/smbdotconf/logon/allownt4crypto.xml | 76 +++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/docs-xml/smbdotconf/logon/allownt4crypto.xml b/docs-xml/smbdotconf/logon/allownt4crypto.xml index 06afcef73b1..bbd03a42db7 100644 --- a/docs-xml/smbdotconf/logon/allownt4crypto.xml +++ b/docs-xml/smbdotconf/logon/allownt4crypto.xml @@ -1,11 +1,18 @@ + + This option is deprecated and will be removed in future, + as it is a security problem if not set to "no" (which will be + the hardcoded behavior in future). + + This option controls whether the netlogon server (currently only in 'active directory domain controller' mode), will - reject clients which does not support NETLOGON_NEG_STRONG_KEYS + reject clients which do not support NETLOGON_NEG_STRONG_KEYS nor NETLOGON_NEG_SUPPORTS_AES. This option was added with Samba 4.2.0. It may lock out clients @@ -18,8 +25,73 @@ "allow nt4 crypto = yes" allows weak crypto to be negotiated, maybe via downgrade attacks. - This option is over-ridden by the 'reject md5 clients' option. + Avoid using this option! Use explicit 'yes' instead! + Which is available with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240 + + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'yes' option + for the client. The message will indicate + the explicit 'yes' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + This allows admins to use "yes" only for a short grace period, + in order to collect the explicit + 'yes' options. + + This option is over-ridden by the 'yes' option. no + + + + + If you still have legacy domain members which required 'allow nt4 crypto = yes', + it is possible to specify an explicit exception per computer account + by using 'allow nt4 crypto:COMPUTERACCOUNT = yes' as option. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will log a complaint in the log files at log level 0 + about the security problem if the option is set to "yes", + but the related computer does not require it. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + + Samba will log a warning in the log files at log level 5, + if a setting is still needed for the specified computer account. + + + + See CVE-2022-38023, + https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + This option overrides the option. + + This option is over-ridden by the 'yes' option. + + + allow nt4 crypto:LEGACYCOMPUTER1$ = yes + allow nt4 crypto:NASBOX$ = yes + allow nt4 crypto:LEGACYCOMPUTER2$ = yes + + + + -- 2.39.0 From 5c4cb1622e74a27b8d0d67110f6e7b3e247e9c1a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 14:02:11 +0100 Subject: [PATCH 20/40] CVE-2022-38023 docs-xml/smbdotconf: document "server reject md5 schannel:COMPUTERACCOUNT" BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 2ad302b42254e3c2800aaf11669fe2e6d55fa8a1) (cherry picked from commit b7f0e7f2ccc9c07b2daa0dc6d66ea117108e9a4f) --- docs-xml/smbdotconf/logon/allownt4crypto.xml | 13 ++- .../smbdotconf/logon/rejectmd5clients.xml | 96 ++++++++++++++++++- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/docs-xml/smbdotconf/logon/allownt4crypto.xml b/docs-xml/smbdotconf/logon/allownt4crypto.xml index bbd03a42db7..ee63e6cc245 100644 --- a/docs-xml/smbdotconf/logon/allownt4crypto.xml +++ b/docs-xml/smbdotconf/logon/allownt4crypto.xml @@ -45,7 +45,9 @@ in order to collect the explicit 'yes' options. - This option is over-ridden by the 'yes' option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. no @@ -85,12 +87,19 @@ This option overrides the option. - This option is over-ridden by the 'yes' option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. + Which means 'yes' + is only useful in combination with 'no' allow nt4 crypto:LEGACYCOMPUTER1$ = yes + server reject md5 schannel:LEGACYCOMPUTER1$ = no allow nt4 crypto:NASBOX$ = yes + server reject md5 schannel:NASBOX$ = no allow nt4 crypto:LEGACYCOMPUTER2$ = yes + server reject md5 schannel:LEGACYCOMPUTER2$ = no diff --git a/docs-xml/smbdotconf/logon/rejectmd5clients.xml b/docs-xml/smbdotconf/logon/rejectmd5clients.xml index edcbe02e99a..fe7701d9277 100644 --- a/docs-xml/smbdotconf/logon/rejectmd5clients.xml +++ b/docs-xml/smbdotconf/logon/rejectmd5clients.xml @@ -1,8 +1,15 @@ + + This option is deprecated and will be removed in a future release, + as it is a security problem if not set to "yes" (which will be + the hardcoded behavior in the future). + + This option controls whether the netlogon server (currently only in 'active directory domain controller' mode), will reject clients which does not support NETLOGON_NEG_SUPPORTS_AES. @@ -10,13 +17,94 @@ Support for NETLOGON_NEG_SUPPORTS_AES was added in Windows starting with Server 2008R2 and Windows 7, it's available in Samba starting with 4.0, however third party domain members like NetApp ONTAP - still uses RC4 (HMAC-MD5), see https://www.samba.org/samba/security/CVE-2022-38023.html for more details. + still uses RC4 (HMAC-MD5), see + https://www.samba.org/samba/security/CVE-2022-38023.html + for more details. + + + The default changed from 'no' to 'yes', with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + Avoid using this option! Use an explicit per machine account + '' instead! + Which is available with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240. + - The default changed from 'no' to 'yes', with the patches for CVE-2022-38023, - see https://bugzilla.samba.org/show_bug.cgi?id=15240 + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'no' option + for the client. The message will indicate + the explicit 'no' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + - This option overrides the 'allow nt4 crypto' option. + This allows admins to use "no" only for a short grace period, + in order to collect the explicit + 'no' options. + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'no'. + yes + + + + + If you still have legacy domain members or trusted domains, + which required "reject md5 clients = no" before, + it is possible to specify an explicit exception per computer account + by setting 'server reject md5 schannel:COMPUTERACCOUNT = no'. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will log a complaint in the log files at log level 0 + about the security problem if the option is set to "no", + but the related computer does not require it. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + + Samba will log a warning in the log files at log level 5 + if a setting is still needed for the specified computer account. + + + + See CVE-2022-38023, + https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + This option overrides the option. + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'no'. + + + + server reject md5 schannel:LEGACYCOMPUTER1$ = no + server reject md5 schannel:NASBOX$ = no + server reject md5 schannel:LEGACYCOMPUTER2$ = no + + + + -- 2.39.0 From 08e1e753d58d057d90fa8f1d492d5ba45d82798b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 13:13:36 +0100 Subject: [PATCH 21/40] CVE-2022-38023 s4:rpc_server/netlogon: debug 'reject md5 servers' and 'allow nt4 crypto' misconfigurations This allows the admin to notice what's wrong in order to adjust the configuration if required. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 43df4be35950f491864ae8ada05d51b42a556381) [metze@samba.org remove lpcfg_weak_crypto() check for 4.15] (cherry picked from commit ba1482a18a807a5db4d1bd84640a0d5d83fcd9c3) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index c593b7903a8..d02e85a035e 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -61,10 +61,34 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context const struct dcesrv_interface *iface) { struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx; + bool global_allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx); + bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); + static bool warned_global_nt4_once = false; + static bool warned_global_md5_once = false; static bool warned_global_schannel_once = false; + if (global_allow_nt4_crypto && !warned_global_nt4_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023 (and others): " + "Please configure 'allow nt4 crypto = no' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_nt4_once = true; + } + + if (!global_reject_md5_client && !warned_global_md5_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023: " + "Please configure 'reject md5 clients = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_md5_once = true; + } + if (!schannel_global_required && !warned_global_schannel_once) { /* * We want admins to notice their misconfiguration! @@ -146,6 +170,12 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( bool reject_des_client; bool allow_nt4_crypto; bool reject_md5_client; + bool need_des = true; + bool need_md5 = true; + int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "error_debug_level", DBGLVL_ERR); /* * We don't use lpcfg_parm_bool(), as we @@ -177,19 +207,62 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( reject_des_client = !allow_nt4_crypto; if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) { + need_des = false; reject_des_client = false; } if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + need_des = false; + need_md5 = false; reject_des_client = false; reject_md5_client = false; } if (reject_des_client || reject_md5_client) { + TALLOC_CTX *frame = talloc_stackframe(); + + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: " + "client_account[%s] computer_name[%s] " + "schannel_type[%u] " + "client_negotiate_flags[0x%x] " + "%s%s%s " + "NT_STATUS_DOWNGRADE_DETECTED " + "reject_des[%u] reject_md5[%u]\n", + log_escape(frame, r->in.account_name), + log_escape(frame, r->in.computer_name), + r->in.secure_channel_type, + (unsigned)*r->in.negotiate_flags, + trust_account_in_db ? "real_account[" : "", + trust_account_in_db ? trust_account_in_db : "", + trust_account_in_db ? "]" : "", + reject_des_client, + reject_md5_client)); + if (trust_account_in_db == NULL) { + goto return_downgrade; + } + + if (reject_md5_client && explicit_md5_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } + if (reject_des_client && explicit_nt4_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } + +return_downgrade: /* * Here we match Windows 2012 and return no flags. */ *r->out.negotiate_flags = 0; + TALLOC_FREE(frame); return NT_STATUS_DOWNGRADE_DETECTED; } @@ -222,6 +295,54 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade( */ *r->out.negotiate_flags = negotiate_flags; + if (!NT_STATUS_IS_OK(orig_status) || trust_account_in_db == NULL) { + return orig_status; + } + + if (global_reject_md5_client && account_reject_md5_client && explicit_md5_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = yes' not needed!?\n", + trust_account_in_db); + } else if (need_md5 && !account_reject_md5_client && explicit_md5_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' " + "still needed for a legacy client.\n", + trust_account_in_db); + } else if (need_md5 && explicit_md5_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } else if (!account_reject_md5_client && explicit_md5_opt) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: Check if option " + "'server reject md5 schannel:%s = no' not needed!?\n", + trust_account_in_db)); + } + + if (!global_allow_nt4_crypto && !account_allow_nt4_crypto && explicit_nt4_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = no' not needed!?\n", + trust_account_in_db); + } else if (need_des && account_allow_nt4_crypto && explicit_nt4_opt) { + D_INFO("CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' " + "still needed for a legacy client.\n", + trust_account_in_db); + } else if (need_des && explicit_nt4_opt == NULL) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' " + "might be needed for a legacy client.\n", + trust_account_in_db)); + } else if (account_allow_nt4_crypto && explicit_nt4_opt) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: Check if option " + "'allow nt4 crypto:%s = yes' not needed!?\n", + trust_account_in_db)); + } + return orig_status; } -- 2.39.0 From 5d2986bc6e9cbc384e62e53050e8f300b5f04ae2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 14:57:20 +0100 Subject: [PATCH 22/40] CVE-2022-38023 selftest:Samba4: avoid global 'allow nt4 crypto = yes' and 'reject md5 clients = no' Instead of using the generic deprecated option use the specific allow nt4 crypto:COMPUTERACCOUNT = yes and server reject md5 schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 7ae3735810c2db32fa50f309f8af3c76ffa29768) [metze@samba.org fixed conflict in 4.15] (cherry picked from commit 08b69ca61f747a74c5a6634d25ce35e43e145ecd) --- selftest/target/Samba4.pm | 61 +++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 2f96f4be3eb..ed286ad8e13 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1572,7 +1572,6 @@ sub provision_ad_dc_ntvfs($$$) my $extra_conf_options = "netbios aliases = localDC1-a server services = +winbind -winbindd ldap server require strong auth = allow_sasl_over_tls - allow nt4 crypto = yes raw NTLMv2 auth = yes lsa over netlogon = yes rpc server port = 1027 @@ -1581,9 +1580,21 @@ sub provision_ad_dc_ntvfs($$$) dsdb password event notification = true dsdb group change notification = true - reject md5 clients = no - CVE_2020_1472:warn_about_unused_debug_level = 3 + CVE_2022_38023:warn_about_unused_debug_level = 3 + allow nt4 crypto:torturetest\$ = yes + server reject md5 schannel:schannel2\$ = no + server reject md5 schannel:schannel3\$ = no + server reject md5 schannel:schannel8\$ = no + server reject md5 schannel:schannel9\$ = no + server reject md5 schannel:torturetest\$ = no + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no + server reject md5 schannel:torturepacwkdes\$ = no + server reject md5 schannel:samlogontest\$ = no server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no server require schannel:schannel2\$ = no @@ -1636,6 +1647,14 @@ sub provision_fl2000dc($$) my $extra_conf_options = " spnego:simulate_w2k=yes ntlmssp_server:force_old_spnego=yes + + CVE_2022_38023:warn_about_unused_debug_level = 3 + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no + server reject md5 schannel:torturepacwkdes\$ = no "; my $extra_provision_options = ["--use-ntvfs", "--base-schema=2008_R2"]; # This environment uses plain text secrets @@ -1678,7 +1697,17 @@ sub provision_fl2003dc($$$) my $extra_conf_options = "allow dns updates = nonsecure and secure dcesrv:header signing = no dcesrv:max auth states = 0 - dns forwarder = $ip_addr1 $ip_addr2"; + dns forwarder = $ip_addr1 $ip_addr2 + + CVE_2022_38023:warn_about_unused_debug_level = 3 + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no + server reject md5 schannel:torturepacwkdes\$ = no +"; + my $extra_provision_options = ["--use-ntvfs", "--base-schema=2008_R2"]; my $ret = $self->provision($prefix, "domain controller", @@ -1732,6 +1761,14 @@ sub provision_fl2008r2dc($$$) ldap server require strong auth = no # delay by 10 seconds, 10^7 usecs ldap_server:delay_expire_disconnect = 10000 + + CVE_2022_38023:warn_about_unused_debug_level = 3 + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no + server reject md5 schannel:torturepacwkdes\$ = no "; my $extra_provision_options = ["--use-ntvfs", "--base-schema=2008_R2"]; my $ret = $self->provision($prefix, @@ -1936,9 +1973,21 @@ sub provision_ad_dc($$$$$$) lpq cache time = 0 print notify backchannel = yes - reject md5 clients = no - CVE_2020_1472:warn_about_unused_debug_level = 3 + CVE_2022_38023:warn_about_unused_debug_level = 3 + CVE_2022_38023:error_debug_level = 2 + server reject md5 schannel:schannel2\$ = no + server reject md5 schannel:schannel3\$ = no + server reject md5 schannel:schannel8\$ = no + server reject md5 schannel:schannel9\$ = no + server reject md5 schannel:torturetest\$ = no + server reject md5 schannel:tests4u2proxywk\$ = no + server reject md5 schannel:tests4u2selfbdc\$ = no + server reject md5 schannel:tests4u2selfwk\$ = no + server reject md5 schannel:torturepacbdc\$ = no + server reject md5 schannel:torturepacwksta\$ = no + server reject md5 schannel:torturepacwkdes\$ = no + server reject md5 schannel:samlogontest\$ = no server require schannel:schannel0\$ = no server require schannel:schannel1\$ = no server require schannel:schannel2\$ = no -- 2.39.0 From 1e7ad4a73328af21cca45277d41b3b2b65750967 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 16:57:24 +0100 Subject: [PATCH 23/40] CVE-2022-38023 s4:rpc_server/netlogon: split out dcesrv_netr_check_schannel() function This will allow us to reuse the function in other places. As it will also get some additional checks soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit f43dc4f0bd60d4e127b714565147f82435aa4f07) (cherry picked from commit 57986cad714cc2f738c7482208204ed4e18b1f19) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index d02e85a035e..30d7afe8621 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -844,18 +844,11 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3); } -/* - * NOTE: The following functions are nearly identical to the ones available in - * source3/rpc_server/srv_nelog_nt.c - * The reason we keep 2 copies is that they use different structures to - * represent the auth_info and the decrpc pipes. - */ -static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - const char *computer_name, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator, - struct netlogon_creds_CredentialState **creds_out) +static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint16_t opnum) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; TALLOC_CTX *frame = talloc_stackframe(); @@ -864,15 +857,11 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; - struct netlogon_creds_CredentialState *creds = NULL; int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); unsigned int dbg_lvl = DBGLVL_DEBUG; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; - uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; const char *reason = ""; @@ -880,8 +869,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc opname = ndr_table_netlogon.calls[opnum].name; } - dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { reason = "WITH SEALED"; @@ -894,17 +881,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc reason = "WITHOUT"; } - nt_status = schannel_check_creds_state(mem_ctx, - lp_ctx, - computer_name, - received_authenticator, - return_authenticator, - &creds); - if (!NT_STATUS_IS_OK(nt_status)) { - ZERO_STRUCTP(return_authenticator); - return nt_status; - } - /* * We don't use lpcfg_parm_bool(), as we * need the explicit_opt pointer in order to @@ -944,7 +920,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return nt_status; } @@ -978,8 +953,6 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); return nt_status; } @@ -1023,11 +996,56 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return NT_STATUS_OK; } +/* + * NOTE: The following functions are nearly identical to the ones available in + * source3/rpc_server/srv_nelog_nt.c + * The reason we keep 2 copies is that they use different structures to + * represent the auth_info and the decrpc pipes. + */ +static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + NTSTATUS nt_status; + struct netlogon_creds_CredentialState *creds = NULL; + 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, &auth_level); + + 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; + } + + nt_status = dcesrv_netr_check_schannel(dce_call, + creds, + auth_type, + auth_level, + dce_call->pkt.u.request.opnum); + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE(creds); + ZERO_STRUCTP(return_authenticator); + return nt_status; + } + + *creds_out = creds; + return NT_STATUS_OK; +} + /* Change the machine account password for the currently connected client. Supplies only the NT#. -- 2.39.0 From a8877919ec75e976cb352e4c7b013b64070a0195 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 17:15:36 +0100 Subject: [PATCH 24/40] CVE-2022-38023 s4:rpc_server/netlogon: make sure all dcesrv_netr_LogonSamLogon*() calls go through dcesrv_netr_check_schannel() We'll soon add some additional contraints in dcesrv_netr_check_schannel(), which are also required for dcesrv_netr_LogonSamLogonEx(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 689507457f5e6666488732f91a355a2183fb1662) (cherry picked from commit 2b0dc83e0642f7b1f41b6184fb6e20320cd96b63) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 30d7afe8621..ba2936b5e7f 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -1412,6 +1412,35 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL struct auth_usersupplied_info *user_info = NULL; NTSTATUS nt_status; struct tevent_req *subreq = NULL; + 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, &auth_level); + + switch (dce_call->pkt.u.request.opnum) { + case NDR_NETR_LOGONSAMLOGON: + case NDR_NETR_LOGONSAMLOGONWITHFLAGS: + /* + * These already called dcesrv_netr_check_schannel() + * via dcesrv_netr_creds_server_step_check() + */ + break; + case NDR_NETR_LOGONSAMLOGONEX: + default: + if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + return NT_STATUS_ACCESS_DENIED; + } + + nt_status = dcesrv_netr_check_schannel(dce_call, + creds, + auth_type, + auth_level, + dce_call->pkt.u.request.opnum); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + break; + } *r->out.authoritative = 1; @@ -1758,7 +1787,6 @@ static void dcesrv_netr_LogonSamLogon_base_reply( static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct netr_LogonSamLogonEx *r) { - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; struct dcesrv_netr_LogonSamLogon_base_state *state; NTSTATUS nt_status; @@ -1796,12 +1824,6 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, return nt_status; } - dcesrv_call_auth_info(dce_call, &auth_type, NULL); - - if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - return NT_STATUS_ACCESS_DENIED; - } - nt_status = dcesrv_netr_LogonSamLogon_base_call(state); if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { -- 2.39.0 From 04e36042023e8bd28ead7071e49a12aea0f4f7f0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 16:53:35 +0100 Subject: [PATCH 25/40] CVE-2022-38023 docs-xml/smbdotconf: add "server schannel require seal[:COMPUTERACCOUNT]" options BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 7732a4b0bde1d9f98a0371f17d22648495329470) (cherry picked from commit dba546dbfa5dcaa22ed828c2f5b7fa9c8cb6242e) --- .../smbdotconf/security/serverschannel.xml | 43 ++++++- .../security/serverschannelrequireseal.xml | 118 ++++++++++++++++++ lib/param/loadparm.c | 1 + source3/param/loadparm.c | 1 + 4 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 docs-xml/smbdotconf/security/serverschannelrequireseal.xml diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml index 3e66df1c203..42a657912ca 100644 --- a/docs-xml/smbdotconf/security/serverschannel.xml +++ b/docs-xml/smbdotconf/security/serverschannel.xml @@ -12,19 +12,37 @@ the hardcoded behavior in future). - - Samba will complain in the log files at log level 0, - about the security problem if the option is not set to "yes". + Avoid using this option! Use explicit 'no' instead! + + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'no' option + for the client. The message will indicate + the explicit 'no' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + - See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 + This allows admins to use "auto" only for a short grace period, + in order to collect the explicit + 'no' options. - If you still have legacy domain members use the option. + + See CVE-2020-1472(ZeroLogon), + https://bugzilla.samba.org/show_bug.cgi?id=14497. This option is over-ridden by the option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. + yes @@ -48,6 +66,9 @@ 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. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). @@ -56,15 +77,25 @@ - See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 + See CVE-2020-1472(ZeroLogon), + https://bugzilla.samba.org/show_bug.cgi?id=14497. This option overrides the option. + This option is over-ridden by the effective value of 'yes' from + the '' + and/or '' options. + Which means 'no' + is only useful in combination with 'no' + server require schannel:LEGACYCOMPUTER1$ = no + server require schannel seal:LEGACYCOMPUTER1$ = no server require schannel:NASBOX$ = no + server require schannel seal:NASBOX$ = no server require schannel:LEGACYCOMPUTER2$ = no + server require schannel seal:LEGACYCOMPUTER2$ = no diff --git a/docs-xml/smbdotconf/security/serverschannelrequireseal.xml b/docs-xml/smbdotconf/security/serverschannelrequireseal.xml new file mode 100644 index 00000000000..d4620d1252d --- /dev/null +++ b/docs-xml/smbdotconf/security/serverschannelrequireseal.xml @@ -0,0 +1,118 @@ + + + + + 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). + + + + This option controls whether the netlogon server (currently + only in 'active directory domain controller' mode), will + reject the usage of netlogon secure channel without privacy/enryption. + + + + The option is modelled after the registry key available on Windows. + + + + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\RequireSeal=2 + + + + Avoid using this option! Use the per computer account specific option + '' instead! + Which is available with the patches for + CVE-2022-38023 + see https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + + Samba will log an error in the log files at log level 0 + if legacy a client is rejected or allowed without an explicit, + 'no' option + for the client. The message will indicate + the explicit 'no' + line to be added, if the legacy client software requires it. (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + This allows admins to use "no" only for a short grace period, + in order to collect the explicit + 'no' options. + + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'yes'. + + + + This option is over-ridden by the option. + + + + +yes + + + + + + + If you still have legacy domain members, which required "server schannel require seal = no" before, + it is possible to specify explicit exception per computer account + by using 'server schannel require seal:COMPUTERACCOUNT = no' as option. + Note that COMPUTERACCOUNT has to be the sAMAccountName value of + the computer account (including the trailing '$' sign). + + + + Samba will log a complaint in the log files at log level 0 + about the security problem if the option is set to "no", + but the related computer does not require it. + (The log level can be adjusted with + '1' + in order to complain only at a higher log level). + + + + Samba will warn in the log files at log level 5, + if a setting is still needed for the specified computer account. + + + + See CVE-2022-38023, + https://bugzilla.samba.org/show_bug.cgi?id=15240. + + + + This option overrides the '' option. + + + + When set to 'yes' this option overrides the + '' and + '' options and implies + 'yes'. + + + + server require schannel seal:LEGACYCOMPUTER1$ = no + server require schannel seal:NASBOX$ = no + server require schannel seal:LEGACYCOMPUTER2$ = no + + + + diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 6a5b88cd43e..86d26728a0a 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -2805,6 +2805,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "winbind nss info", "template"); lpcfg_do_global_parameter(lp_ctx, "server schannel", "True"); + lpcfg_do_global_parameter(lp_ctx, "server schannel require seal", "True"); lpcfg_do_global_parameter(lp_ctx, "reject md5 clients", "True"); lpcfg_do_global_parameter(lp_ctx, "short preserve case", "True"); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 14d546d740b..1fbfacbe04e 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -658,6 +658,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) Globals.require_strong_key = true; Globals.reject_md5_servers = true; Globals.server_schannel = true; + Globals.server_schannel_require_seal = true; Globals.reject_md5_clients = true; Globals.read_raw = true; Globals.write_raw = true; -- 2.39.0 From 6b5b6caf6373606deabc25447e9738f180bd3c82 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 2 Dec 2022 14:31:26 +0100 Subject: [PATCH 26/40] CVE-2022-38023 s4:rpc_server/netlogon: add a per connection cache to dcesrv_netr_check_schannel() It's enough to warn the admin once per connection. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 3c57608e1109c1d6e8bb8fbad2ef0b5d79d00e1a) (cherry picked from commit 15792b4035d520ad5a0bf4888fa5d6bedb8937aa) --- source4/rpc_server/netlogon/dcerpc_netlogon.c | 193 ++++++++++++++---- 1 file changed, 153 insertions(+), 40 deletions(-) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index ba2936b5e7f..9451f68bdb1 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -844,23 +844,105 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3); } -static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, - const struct netlogon_creds_CredentialState *creds, - enum dcerpc_AuthType auth_type, - enum dcerpc_AuthLevel auth_level, - uint16_t opnum) +struct dcesrv_netr_check_schannel_state { + struct dom_sid account_sid; + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + + bool schannel_global_required; + bool schannel_required; + bool schannel_explicitly_set; + + NTSTATUS result; +}; + +static NTSTATUS dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state *dce_call, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + struct dcesrv_netr_check_schannel_state **_s) { struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; - TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS nt_status; int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; +#define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1) + struct dcesrv_netr_check_schannel_state *s = NULL; + NTSTATUS status; + + *_s = NULL; + + s = dcesrv_iface_state_find_conn(dce_call, + DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC, + struct dcesrv_netr_check_schannel_state); + if (s != NULL) { + if (!dom_sid_equal(&s->account_sid, creds->sid)) { + goto new_state; + } + if (s->auth_type != auth_type) { + goto new_state; + } + if (s->auth_level != auth_level) { + goto new_state; + } + + *_s = s; + return NT_STATUS_OK; + } + +new_state: + TALLOC_FREE(s); + s = talloc_zero(dce_call, + struct dcesrv_netr_check_schannel_state); + if (s == NULL) { + return NT_STATUS_NO_MEMORY; + } + + s->account_sid = *creds->sid; + s->auth_type = auth_type; + s->auth_level = auth_level; + s->result = NT_STATUS_MORE_PROCESSING_REQUIRED; + + /* + * 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(lp_ctx, + NULL, + "server require schannel", + creds->account_name); + if (explicit_opt != NULL) { + schannel_required = lp_bool(explicit_opt); + } + + s->schannel_global_required = schannel_global_required; + s->schannel_required = schannel_required; + s->schannel_explicitly_set = explicit_opt != NULL; + + status = dcesrv_iface_state_store_conn(dce_call, + DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC, + s); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *_s = s; + return NT_STATUS_OK; +} + +static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_call, + struct dcesrv_netr_check_schannel_state *s, + const struct netlogon_creds_CredentialState *creds, + uint16_t opnum) +{ + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + TALLOC_CTX *frame = talloc_stackframe(); unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; const char *reason = ""; @@ -869,37 +951,43 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname = ndr_table_netlogon.calls[opnum].name; } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { reason = "WITH SEALED"; - } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + } else if (s->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { reason = "WITH SIGNED"; } else { - smb_panic("Schannel without SIGN/SEAL"); + reason = "WITH INVALID"; + dbg_lvl = DBGLVL_ERR; + s->result = NT_STATUS_INTERNAL_ERROR; } } else { reason = "WITHOUT"; } - /* - * 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(lp_ctx, - NULL, - "server require schannel", - creds->account_name); - if (explicit_opt != NULL) { - schannel_required = lp_bool(explicit_opt); + if (!NT_STATUS_EQUAL(s->result, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + if (!NT_STATUS_IS_OK(s->result)) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + TALLOC_FREE(frame); + return s->result; } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - nt_status = NT_STATUS_OK; + if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + s->result = NT_STATUS_OK; - if (explicit_opt != NULL && !schannel_required) { + if (s->schannel_explicitly_set && !s->schannel_required) { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); - } else if (!schannel_required) { + } else if (!s->schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } @@ -910,9 +998,8 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), - nt_errstr(nt_status))); - - if (explicit_opt != NULL && !schannel_required) { + nt_errstr(s->result))); + if (s->schannel_explicitly_set && !s->schannel_required) { DEBUG(CVE_2020_1472_warn_level, ( "CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' not needed for '%s'!\n", @@ -921,13 +1008,13 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, } TALLOC_FREE(frame); - return nt_status; + return s->result; } - if (schannel_required) { - nt_status = NT_STATUS_ACCESS_DENIED; + if (s->schannel_required) { + s->result = NT_STATUS_ACCESS_DENIED; - if (explicit_opt != NULL) { + if (s->schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -940,8 +1027,8 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), - nt_errstr(nt_status))); - if (explicit_opt != NULL) { + nt_errstr(s->result))); + if (s->schannel_explicitly_set) { D_NOTICE("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = yes' " "rejects access for client.\n", @@ -954,12 +1041,12 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, log_escape(frame, creds->account_name))); } TALLOC_FREE(frame); - return nt_status; + return s->result; } - nt_status = NT_STATUS_OK; + s->result = NT_STATUS_OK; - if (explicit_opt != NULL) { + if (s->schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -972,9 +1059,9 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), - nt_errstr(nt_status))); + nt_errstr(s->result))); - if (explicit_opt != NULL) { + if (s->schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " "still needed for '%s'!\n", @@ -997,6 +1084,32 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, } TALLOC_FREE(frame); + return s->result; +} + +static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint16_t opnum) +{ + struct dcesrv_netr_check_schannel_state *s = NULL; + NTSTATUS status; + + status = dcesrv_netr_check_schannel_get_state(dce_call, + creds, + auth_type, + auth_level, + &s); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcesrv_netr_check_schannel_once(dce_call, s, creds, opnum); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return NT_STATUS_OK; } -- 2.39.0 From 5088c7b2251217a349f66b42e0f9075db84d4890 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Nov 2022 14:05:30 +0100 Subject: [PATCH 27/40] CVE-2022-38023 s4:rpc_server/netlogon: implement "server schannel require seal[:COMPUTERACCOUNT]" By default we'll now require schannel connections with privacy/sealing/encryption. But we allow exceptions for specific computer/trust accounts. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit b3ed90a0541a271a7c6d4bee1201fa47adc3c0c1) (cherry picked from commit 93e4e50d250a85c9b0308c3f899ab00f47f427df) --- selftest/target/Samba4.pm | 28 ++ source4/rpc_server/netlogon/dcerpc_netlogon.c | 244 +++++++++++++++++- 2 files changed, 271 insertions(+), 1 deletion(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index ed286ad8e13..ab2c3b9ff86 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1608,9 +1608,23 @@ sub provision_ad_dc_ntvfs($$$) server require schannel:schannel10\$ = no server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no # needed for 'samba.tests.auth_log' tests server require schannel:LOCALDC\$ = no + server schannel require seal:LOCALDC\$ = no "; push (@{$extra_provision_options}, "--use-ntvfs"); my $ret = $self->provision($prefix, @@ -2001,9 +2015,23 @@ sub provision_ad_dc($$$$$$) server require schannel:schannel10\$ = no server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no # needed for 'samba.tests.auth_log' tests server require schannel:ADDC\$ = no + server schannel require seal:ADDC\$ = no auth event notification = true dsdb event notification = true diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 9451f68bdb1..65ff9f8b6bd 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -65,9 +65,11 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx); int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); + bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx); static bool warned_global_nt4_once = false; static bool warned_global_md5_once = false; static bool warned_global_schannel_once = false; + static bool warned_global_seal_once = false; if (global_allow_nt4_crypto && !warned_global_nt4_once) { /* @@ -99,6 +101,16 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context warned_global_schannel_once = true; } + if (!global_require_seal && !warned_global_seal_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023 (and others): " + "Please configure 'server schannel require seal = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_once = true; + } + return dcesrv_interface_bind_reject_connect(context, iface); } @@ -853,6 +865,10 @@ struct dcesrv_netr_check_schannel_state { bool schannel_required; bool schannel_explicitly_set; + bool seal_global_required; + bool seal_required; + bool seal_explicitly_set; + NTSTATUS result; }; @@ -867,6 +883,9 @@ static NTSTATUS dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state *d bool schannel_global_required = (schannel == true); bool schannel_required = schannel_global_required; const char *explicit_opt = NULL; + bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx); + bool require_seal = global_require_seal; + const char *explicit_seal_opt = NULL; #define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1) struct dcesrv_netr_check_schannel_state *s = NULL; NTSTATUS status; @@ -904,6 +923,19 @@ new_state: s->auth_level = auth_level; s->result = NT_STATUS_MORE_PROCESSING_REQUIRED; + /* + * We don't use lpcfg_parm_bool(), as we + * need the explicit_opt pointer in order to + * adjust the debug messages. + */ + explicit_seal_opt = lpcfg_get_parametric(lp_ctx, + NULL, + "server schannel require seal", + creds->account_name); + if (explicit_seal_opt != NULL) { + require_seal = lp_bool(explicit_seal_opt); + } + /* * We don't use lpcfg_parm_bool(), as we * need the explicit_opt pointer in order to @@ -921,6 +953,10 @@ new_state: s->schannel_required = schannel_required; s->schannel_explicitly_set = explicit_opt != NULL; + s->seal_global_required = global_require_seal; + s->seal_required = require_seal; + s->seal_explicitly_set = explicit_seal_opt != NULL; + status = dcesrv_iface_state_store_conn(dce_call, DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC, s); @@ -942,6 +978,10 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2022_38023", "error_debug_level", DBGLVL_ERR); TALLOC_CTX *frame = talloc_stackframe(); unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; @@ -971,18 +1011,107 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca } DEBUG(dbg_lvl, ( - "CVE-2020-1472(ZeroLogon): " + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + TALLOC_FREE(frame); + return s->result; + } + + if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL && + s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) + { + s->result = NT_STATUS_OK; + + if (s->schannel_explicitly_set && !s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + if (s->seal_explicitly_set && !s->seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } else if (!s->seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " "%s request (opnum[%u]) %s schannel from " "client_account[%s] client_computer_name[%s] %s\n", opname, opnum, reason, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), nt_errstr(s->result))); + + if (s->schannel_explicitly_set && !s->schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + if (s->seal_explicitly_set && !s->seal_required) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + TALLOC_FREE(frame); return s->result; } if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (s->seal_required) { + s->result = NT_STATUS_ACCESS_DENIED; + + if (s->seal_explicitly_set) { + dbg_lvl = DBGLVL_NOTICE; + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (s->schannel_explicitly_set && !s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + if (s->seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (s->schannel_explicitly_set && !s->schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + TALLOC_FREE(frame); + return s->result; + } + s->result = NT_STATUS_OK; if (s->schannel_explicitly_set && !s->schannel_required) { @@ -990,6 +1119,11 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca } else if (!s->schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + if (s->seal_explicitly_set && !s->seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else if (!s->seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon): " @@ -1006,11 +1140,81 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name))); } + if (s->seal_explicitly_set && !s->seal_required) { + D_INFO("CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else if (!s->seal_required) { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: " + "Please use 'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } TALLOC_FREE(frame); return s->result; } + if (s->seal_required) { + s->result = NT_STATUS_ACCESS_DENIED; + + if (s->seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (!s->schannel_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } else if (s->schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(s->result))); + if (s->seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (!s->schannel_explicitly_set) { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } else if (s->schannel_required) { + D_NOTICE("CVE-2022-38023: Option " + "'server require schannel:%s = yes' " + "also rejects access for client.\n", + log_escape(frame, creds->account_name)); + } + TALLOC_FREE(frame); + return s->result; + } + if (s->schannel_required) { s->result = NT_STATUS_ACCESS_DENIED; @@ -1019,6 +1223,9 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); } + if (!s->seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " @@ -1040,12 +1247,25 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } + if (!s->seal_explicitly_set) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(frame); return s->result; } s->result = NT_STATUS_OK; + if (s->seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (s->schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { @@ -1061,6 +1281,28 @@ static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_ca log_escape(frame, creds->computer_name), nt_errstr(s->result))); + if (s->seal_explicitly_set) { + D_INFO("CVE-2022-38023: Option " + "'server schannel require seal:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Please use " + "'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + if (s->schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " -- 2.39.0 From 8ae62905cea1288aa937057cc978f2f5a2e5f30f Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 8 Feb 2021 09:48:16 +0100 Subject: [PATCH 28/40] s3:testparm: Warn about 'server schannel = no' Signed-off-by: Andreas Schneider Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Feb 9 03:08:42 UTC 2021 on sn-devel-184 (cherry picked from commit 1691cd7738b89bec284646bc81f338d8027bfc79) --- source3/utils/testparm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index f4e94b6ef74..3d8dd339245 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -522,6 +522,13 @@ static int do_global_checks(void) ret = 1; } + if (!lp_server_schannel()) { + fprintf(stderr, + "WARNING: You have configured 'server schannel = no'. " + "Your server is vulernable to \"ZeroLogon\" " + "(CVE-2020-1472)\n\n"); + } + return ret; } -- 2.39.0 From 232f4fd9fddcfcc3c7f25365582d9e666c3e0d76 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Nov 2022 15:13:47 +0100 Subject: [PATCH 29/40] CVE-2022-38023 testparm: warn about server/client schannel != yes BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit f964c0c357214637f80d0089723b9b11d1b38f7e) (cherry picked from commit 28ac3faa51c66b005a90c527393fa7c2d43d4c31) --- source3/utils/testparm.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index 3d8dd339245..f6a9bc945d2 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -522,11 +522,25 @@ static int do_global_checks(void) ret = 1; } - if (!lp_server_schannel()) { + if (lp_server_schannel() != true) { /* can be 'auto' */ fprintf(stderr, - "WARNING: You have configured 'server schannel = no'. " + "WARNING: You have not configured " + "'server schannel = yes' (the default). " "Your server is vulernable to \"ZeroLogon\" " - "(CVE-2020-1472)\n\n"); + "(CVE-2020-1472)\n" + "If required use individual " + "'server require schannel:COMPUTERACCOUNT$ = no' " + "options\n\n"); + } + if (lp_client_schannel() != true) { /* can be 'auto' */ + fprintf(stderr, + "WARNING: You have not configured " + "'client schannel = yes' (the default). " + "Your server is vulernable to \"ZeroLogon\" " + "(CVE-2020-1472)\n" + "If required use individual " + "'client schannel:NETBIOSDOMAIN = no' " + "options\n\n"); } return ret; -- 2.39.0 From a6e1c24b7df1ab5c679d208c06c0983b982c5576 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 Dec 2022 13:36:17 +0100 Subject: [PATCH 30/40] CVE-2022-38023 testparm: warn about unsecure schannel related options BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Ralph Boehme (cherry picked from commit 4d540473c3d43d048a30dd63efaeae9ff87b2aeb) (cherry picked from commit d10dfa85819750f4665dc5fa974f35ce7871acf8) --- source3/utils/testparm.c | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index f6a9bc945d2..9204608833e 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -532,6 +532,37 @@ static int do_global_checks(void) "'server require schannel:COMPUTERACCOUNT$ = no' " "options\n\n"); } + if (lp_allow_nt4_crypto()) { + fprintf(stderr, + "WARNING: You have not configured " + "'allow nt4 crypto = no' (the default). " + "Your server is vulernable to " + "CVE-2022-38023 and others!\n" + "If required use individual " + "'allow nt4 crypto:COMPUTERACCOUNT$ = yes' " + "options\n\n"); + } + if (!lp_reject_md5_clients()) { + fprintf(stderr, + "WARNING: You have not configured " + "'reject md5 clients = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023!\n" + "If required use individual " + "'server reject md5 schannel:COMPUTERACCOUNT$ = yes' " + "options\n\n"); + } + if (!lp_server_schannel_require_seal()) { + fprintf(stderr, + "WARNING: You have not configured " + "'server schannel require seal = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023!\n" + "If required use individual " + "'server schannel require seal:COMPUTERACCOUNT$ = no' " + "options\n\n"); + } + if (lp_client_schannel() != true) { /* can be 'auto' */ fprintf(stderr, "WARNING: You have not configured " @@ -542,6 +573,36 @@ static int do_global_checks(void) "'client schannel:NETBIOSDOMAIN = no' " "options\n\n"); } + if (!lp_reject_md5_servers()) { + fprintf(stderr, + "WARNING: You have not configured " + "'reject md5 servers = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023\n" + "If required use individual " + "'reject md5 servers:NETBIOSDOMAIN = no' " + "options\n\n"); + } + if (!lp_require_strong_key()) { + fprintf(stderr, + "WARNING: You have not configured " + "'require strong key = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023\n" + "If required use individual " + "'require strong key:NETBIOSDOMAIN = no' " + "options\n\n"); + } + if (!lp_winbind_sealed_pipes()) { + fprintf(stderr, + "WARNING: You have not configured " + "'winbind sealed pipes = yes' (the default). " + "Your server is vulernable to " + "CVE-2022-38023\n" + "If required use individual " + "'winbind sealed pipes:NETBIOSDOMAIN = no' " + "options\n\n"); + } return ret; } -- 2.39.0 From 19aa47e3db550fd3099f06c9b97dc5800dd5afb3 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:33:12 +0100 Subject: [PATCH 31/40] CVE-2022-38023 s3:rpc_server/netlogon: add talloc_stackframe() to dcesrv_netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 38 ++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 3221ebaa2e2..8e907e60f7e 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1070,6 +1070,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, struct netr_Authenticator *return_authenticator, struct netlogon_creds_CredentialState **creds_out) { + TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; @@ -1091,19 +1092,19 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, auth_type = p->auth.auth_type; - lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(0, ("loadparm_init_s3 failed\n")); + TALLOC_FREE(frame); return NT_STATUS_INTERNAL_ERROR; } status = schannel_check_creds_state(mem_ctx, lp_ctx, computer_name, received_authenticator, return_authenticator, &creds); - talloc_unlink(mem_ctx, lp_ctx); - if (!NT_STATUS_IS_OK(status)) { ZERO_STRUCTP(return_authenticator); + TALLOC_FREE(frame); return status; } @@ -1124,6 +1125,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, if (schannel_required) { if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -1131,13 +1133,15 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "%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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name)); TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); + TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } @@ -1156,13 +1160,14 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "%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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + log_escape(frame, creds->account_name)); *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -1171,24 +1176,25 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "%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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + log_escape(frame, 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)); + log_escape(frame, creds->account_name), + log_escape(frame, 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)); + log_escape(frame, creds->account_name)); } *creds_out = creds; + TALLOC_FREE(frame); return NT_STATUS_OK; } -- 2.39.0 From 4118bd2e1b1a31717f4c5355be5d83c121fa85dc Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 21 Dec 2022 18:17:57 +0100 Subject: [PATCH 32/40] CVE-2022-38023 s3:rpc_server/netlogon: re-order checking in netr_creds_server_step_check() This will simplify the following changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 40 ++++++++++----------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 8e907e60f7e..ba73fe3fa58 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1122,13 +1122,27 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, schannel_required = lp_bool(explicit_opt); } - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (!schannel_required) { + 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(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } + if (explicit_opt != NULL && !schannel_required) { + DBG_ERR("CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed!?\n", + log_escape(frame, creds->account_name)); } + *creds_out = creds; + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + if (schannel_required) { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " "client_account[%s] client_computer_name[%s]\n", @@ -1155,22 +1169,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); - - *creds_out = creds; - TALLOC_FREE(frame); - return NT_STATUS_OK; - } - if (explicit_opt != NULL) { DBG_INFO("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) without schannel from " -- 2.39.0 From 4e9f73ed47739f66fbf330d1f6ddb738b749395a Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:35:57 +0100 Subject: [PATCH 33/40] CVE-2022-38023 s3:rpc_server/netlogon: improve CVE-2020-1472(ZeroLogon) debug messages In order to avoid generating useless debug messages during make test, we will use 'CVE_2020_1472:warn_about_unused_debug_level = 3' and 'CVE_2020_1472:error_debug_level = 2' in order to avoid schannel warnings. Review with: git show -w BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 149 ++++++++++++++------ 1 file changed, 109 insertions(+), 40 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index ba73fe3fa58..c9401499a9b 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1077,9 +1077,14 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, const char *explicit_opt = NULL; struct loadparm_context *lp_ctx; struct netlogon_creds_CredentialState *creds = NULL; + int CVE_2020_1472_warn_level = DBGLVL_ERR; + int CVE_2020_1472_error_level = DBGLVL_ERR; + unsigned int dbg_lvl = DBGLVL_DEBUG; enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; uint16_t opnum = p->opnum; const char *opname = ""; + const char *reason = ""; static bool warned_global_once = false; if (creds_out != NULL) { @@ -1091,6 +1096,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, } auth_type = p->auth.auth_type; + auth_level = p->auth.auth_level; lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); if (lp_ctx == NULL) { @@ -1099,6 +1105,23 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, return NT_STATUS_INTERNAL_ERROR; } + CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); + CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, + "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + reason = "WITH SEALED"; + } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + reason = "WITH SIGNED"; + } else { + smb_panic("Schannel without SIGN/SEAL"); + } + } else { + reason = "WITHOUT"; + } + status = schannel_check_creds_state(mem_ctx, lp_ctx, computer_name, received_authenticator, return_authenticator, &creds); @@ -1123,40 +1146,69 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, } if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (!schannel_required) { - 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); + status = NT_STATUS_OK; + + if (explicit_opt != NULL && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon): " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (explicit_opt != NULL && !schannel_required) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(frame, creds->account_name)); + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; TALLOC_FREE(frame); - return NT_STATUS_OK; + return status; } if (schannel_required) { - 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' " - "might be needed for a legacy client.\n", - log_escape(frame, creds->account_name)); + status = NT_STATUS_ACCESS_DENIED; + + if (explicit_opt != NULL) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (explicit_opt != NULL) { + D_NOTICE("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(creds); ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); - return NT_STATUS_ACCESS_DENIED; + return status; } if (!schannel_global_required && !warned_global_once) { @@ -1169,26 +1221,43 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, warned_global_once = true; } + status = 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' still needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } 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(frame, creds->account_name), - log_escape(frame, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' might be needed!\n", - log_escape(frame, creds->account_name)); + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + + if (explicit_opt != NULL) { + D_INFO("CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server require schannel:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): " + "Please use 'server require schannel:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); } *creds_out = creds; -- 2.39.0 From 7cd2ec2b9dfd2376f08efa5194e84025bf2c1b89 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 21 Dec 2022 18:37:05 +0100 Subject: [PATCH 34/40] CVE-2022-38023 selftest:Samba3: avoid global 'server schannel = auto' Instead of using the generic deprecated option use the specific server require schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- selftest/target/Samba3.pm | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index c22c567cd65..5c1aeb0ba75 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -201,7 +201,21 @@ sub setup_nt4_dc lanman auth = yes ntlm auth = yes raw NTLMv2 auth = yes - server schannel = auto + + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no rpc_server:epmapper = external rpc_server:spoolss = external -- 2.39.0 From 24d91b96790628ba864c67cca0b97b95ad7f9555 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:42:51 +0100 Subject: [PATCH 35/40] CVE-2022-38023 s3:rpc_server/netlogon: split out netr_check_schannel() function This will allow us to reuse the function in other places. As it will also get some additional checks soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 107 ++++++++++++-------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index c9401499a9b..b254ca72a48 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1063,53 +1063,30 @@ NTSTATUS _netr_ServerAuthenticate2(struct pipes_struct *p, /************************************************************************* *************************************************************************/ -static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, - const char *computer_name, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator, - struct netlogon_creds_CredentialState **creds_out) +static NTSTATUS netr_check_schannel(struct pipes_struct *p, + const struct netlogon_creds_CredentialState *creds, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint16_t opnum) { TALLOC_CTX *frame = talloc_stackframe(); 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; - int CVE_2020_1472_warn_level = DBGLVL_ERR; - int CVE_2020_1472_error_level = DBGLVL_ERR; + int CVE_2020_1472_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2020_1472_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); unsigned int dbg_lvl = DBGLVL_DEBUG; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; - uint16_t opnum = p->opnum; const char *opname = ""; const char *reason = ""; static bool warned_global_once = false; - if (creds_out != NULL) { - *creds_out = NULL; - } - if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; } - auth_type = p->auth.auth_type; - auth_level = p->auth.auth_level; - - lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); - TALLOC_FREE(frame); - return NT_STATUS_INTERNAL_ERROR; - } - - CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL, - "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); - CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL, - "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { reason = "WITH SEALED"; @@ -1122,15 +1099,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, reason = "WITHOUT"; } - status = schannel_check_creds_state(mem_ctx, lp_ctx, - computer_name, received_authenticator, - return_authenticator, &creds); - if (!NT_STATUS_IS_OK(status)) { - ZERO_STRUCTP(return_authenticator); - TALLOC_FREE(frame); - return status; - } - /* * We don't use lp_parm_bool(), as we * need the explicit_opt pointer in order to @@ -1171,7 +1139,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return status; } @@ -1205,8 +1172,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); TALLOC_FREE(frame); return status; } @@ -1260,11 +1225,63 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, log_escape(frame, creds->computer_name))); } - *creds_out = creds; TALLOC_FREE(frame); return NT_STATUS_OK; } +static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + struct loadparm_context *lp_ctx = NULL; + NTSTATUS status; + struct netlogon_creds_CredentialState *creds = NULL; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; + uint16_t opnum = p->opnum; + + if (creds_out != NULL) { + *creds_out = NULL; + } + + auth_type = p->auth.auth_type; + auth_level = p->auth.auth_level; + + lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); + if (lp_ctx == NULL) { + DEBUG(0, ("loadparm_init_s3 failed\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + status = schannel_check_creds_state(mem_ctx, + lp_ctx, + computer_name, + received_authenticator, + return_authenticator, + &creds); + TALLOC_FREE(lp_ctx); + if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCTP(return_authenticator); + return status; + } + + status = netr_check_schannel(p, + creds, + auth_type, + auth_level, + opnum); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); + ZERO_STRUCTP(return_authenticator); + return status; + } + + *creds_out = creds; + return NT_STATUS_OK; +} /************************************************************************* *************************************************************************/ -- 2.39.0 From ec1962e20deb4cbe95e861eb57107f08cb3a6de9 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 09:29:04 +0100 Subject: [PATCH 36/40] CVE-2022-38023 s3:rpc_server/netlogon: make sure all dcesrv_netr_LogonSamLogon*() calls go through netr_check_schannel() We'll soon add some additional contraints in dcesrv_netr_check_schannel(), which are also required for dcesrv_netr_LogonSamLogonEx(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 30 ++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index b254ca72a48..a66b929b479 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1771,6 +1771,8 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, struct auth_serversupplied_info *server_info = NULL; struct auth_context *auth_context = NULL; const char *fn; + enum dcerpc_AuthType auth_type = p->auth.auth_type; + enum dcerpc_AuthLevel auth_level = p->auth.auth_level; #ifdef DEBUG_PASSWORD logon = netlogon_creds_shallow_copy_logon(p->mem_ctx, @@ -1784,11 +1786,32 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, switch (p->opnum) { case NDR_NETR_LOGONSAMLOGON: fn = "_netr_LogonSamLogon"; + /* + * Already called netr_check_schannel() via + * netr_creds_server_step_check() + */ break; case NDR_NETR_LOGONSAMLOGONWITHFLAGS: fn = "_netr_LogonSamLogonWithFlags"; + /* + * Already called netr_check_schannel() via + * netr_creds_server_step_check() + */ break; case NDR_NETR_LOGONSAMLOGONEX: + if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + return NT_STATUS_ACCESS_DENIED; + } + + status = netr_check_schannel(p, + creds, + auth_type, + auth_level, + p->opnum); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + fn = "_netr_LogonSamLogonEx"; break; default: @@ -2130,13 +2153,6 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, return status; } - /* Only allow this if the pipe is protected. */ - if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("_netr_LogonSamLogonEx: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_INVALID_PARAMETER; - } - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(0, ("loadparm_init_s3 failed\n")); -- 2.39.0 From e46fdd96cf0cea2415e7dfd49d7f204c53bac762 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:23:41 +0100 Subject: [PATCH 37/40] CVE-2022-38023 s3:rpc_server/netlogon: Rename variable This will simplify the following changes. Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index a66b929b479..b7c8e2c928e 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1071,9 +1071,10 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, { TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; + const char *explicit_opt = NULL; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; - const char *explicit_opt = NULL; + bool schannel_explicitly_set = false; int CVE_2020_1472_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, @@ -1112,11 +1113,12 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, if (explicit_opt != NULL) { schannel_required = lp_bool(explicit_opt); } + schannel_explicitly_set = explicit_opt != NULL; if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { status = NT_STATUS_OK; - if (explicit_opt != NULL && !schannel_required) { + if (schannel_explicitly_set && !schannel_required) { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); } else if (!schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); @@ -1131,7 +1133,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->computer_name), nt_errstr(status))); - if (explicit_opt != NULL && !schannel_required) { + if (schannel_explicitly_set && !schannel_required) { DEBUG(CVE_2020_1472_warn_level, ( "CVE-2020-1472(ZeroLogon): " "Option 'server require schannel:%s = no' not needed for '%s'!\n", @@ -1146,7 +1148,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, if (schannel_required) { status = NT_STATUS_ACCESS_DENIED; - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -1160,7 +1162,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), nt_errstr(status))); - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { D_NOTICE("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = yes' " "rejects access for client.\n", @@ -1188,7 +1190,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, status = NT_STATUS_OK; - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); @@ -1203,7 +1205,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->computer_name), nt_errstr(status))); - if (explicit_opt != NULL) { + if (schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " "still needed for '%s'!\n", -- 2.39.0 From b0ecb8aebf814b339afe1d2843ef53ece5cb4c9d Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:39:20 +0100 Subject: [PATCH 38/40] CVE-2022-38023 s3:rpc_server/netlogon: Return error on invalid auth level Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index b7c8e2c928e..5f89e945f9c 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1070,7 +1070,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, uint16_t opnum) { TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS status; + NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED; const char *explicit_opt = NULL; bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; @@ -1094,12 +1094,31 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { reason = "WITH SIGNED"; } else { - smb_panic("Schannel without SIGN/SEAL"); + reason = "WITH INVALID"; + dbg_lvl = DBGLVL_ERR; + status = NT_STATUS_INTERNAL_ERROR; } } else { reason = "WITHOUT"; } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + if (!NT_STATUS_IS_OK(status)) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + TALLOC_FREE(frame); + return status; + } + /* * We don't use lp_parm_bool(), as we * need the explicit_opt pointer in order to -- 2.39.0 From 037606c112ae4d1025708d2d12898e73359f0c54 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:42:37 +0100 Subject: [PATCH 39/40] CVE-2022-38023 s3:rpc_server/netlogon: Rename variable This will simplify the following changes. Signed-off-by: Samuel Cabrero --- source3/rpc_server/netlogon/srv_netlog_nt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 5f89e945f9c..f238d7ce42b 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1082,7 +1082,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; const char *reason = ""; - static bool warned_global_once = false; + static bool warned_global_schannel_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -1197,14 +1197,14 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, return status; } - if (!schannel_global_required && !warned_global_once) { + if (!schannel_global_required && !warned_global_schannel_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; + warned_global_schannel_once = true; } status = NT_STATUS_OK; -- 2.39.0 From fba17d9f8e6437fc675608c0507d6a00f830aaea Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 4 Jan 2023 17:50:04 +0100 Subject: [PATCH 40/40] CVE-2022-38023 s3:rpc_server/netlogon: implement "server schannel require seal[:COMPUTERACCOUNT]" By default we'll now require schannel connections with privacy/sealing/encryption. But we allow exceptions for specific computer/trust accounts. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero --- selftest/target/Samba3.pm | 14 ++ source3/rpc_server/netlogon/srv_netlog_nt.c | 237 +++++++++++++++++++- 2 files changed, 249 insertions(+), 2 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 5c1aeb0ba75..22eb382438f 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -217,6 +217,20 @@ sub setup_nt4_dc server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no + rpc_server:epmapper = external rpc_server:spoolss = external rpc_server:lsarpc = external diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index f238d7ce42b..df305e94479 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1075,14 +1075,22 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, bool schannel_global_required = (lp_server_schannel() == true) ? true:false; bool schannel_required = schannel_global_required; bool schannel_explicitly_set = false; + bool seal_global_required = (lp_server_schannel_require_seal() == true) ? true:false; + bool seal_required = seal_global_required; + bool seal_explicitly_set = false; int CVE_2020_1472_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR); int CVE_2020_1472_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, "CVE_2020_1472", "error_debug_level", DBGLVL_ERR); + int CVE_2022_38023_warn_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR); + int CVE_2022_38023_error_level = lp_parm_int(GLOBAL_SECTION_SNUM, + "CVE_2022_38023", "error_debug_level", DBGLVL_ERR); unsigned int dbg_lvl = DBGLVL_DEBUG; const char *opname = ""; const char *reason = ""; static bool warned_global_schannel_once = false; + static bool warned_global_seal_once = false; if (opnum < ndr_table_netlogon.num_calls) { opname = ndr_table_netlogon.calls[opnum].name; @@ -1119,6 +1127,20 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, return status; } + /* + * 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 schannel require seal", + creds->account_name, + NULL); + if (explicit_opt != NULL) { + seal_required = lp_bool(explicit_opt); + } + seal_explicitly_set = explicit_opt != NULL; + /* * We don't use lp_parm_bool(), as we * need the explicit_opt pointer in order to @@ -1134,7 +1156,96 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } schannel_explicitly_set = explicit_opt != NULL; + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL && + auth_level == DCERPC_AUTH_LEVEL_PRIVACY) + { + status = NT_STATUS_OK; + + if (schannel_explicitly_set && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level); + } else if (!schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + if (seal_explicitly_set && !seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } else if (!seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + + if (schannel_explicitly_set && !schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): " + "Option 'server require schannel:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + if (seal_explicitly_set && !seal_required) { + DEBUG(CVE_2022_38023_warn_level, ( + "CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + TALLOC_FREE(frame); + return status; + } + if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (seal_required) { + status = NT_STATUS_ACCESS_DENIED; + + if (seal_explicitly_set) { + dbg_lvl = DBGLVL_NOTICE; + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (schannel_explicitly_set && !schannel_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level); + } + + DEBUG(dbg_lvl, ( + "CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (schannel_explicitly_set && !schannel_required) { + DEBUG(CVE_2020_1472_warn_level, ( + "CVE-2020-1472(ZeroLogon): Option " + "'server require schannel:%s = no' " + "not needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + TALLOC_FREE(frame); + return status; + } + status = NT_STATUS_OK; if (schannel_explicitly_set && !schannel_required) { @@ -1142,6 +1253,11 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } else if (!schannel_required) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } + if (seal_explicitly_set && !seal_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else if (!seal_required) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon): " @@ -1151,7 +1267,6 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name), nt_errstr(status))); - if (schannel_explicitly_set && !schannel_required) { DEBUG(CVE_2020_1472_warn_level, ( "CVE-2020-1472(ZeroLogon): " @@ -1159,7 +1274,77 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->account_name), log_escape(frame, creds->computer_name))); } + if (seal_explicitly_set && !seal_required) { + D_INFO("CVE-2022-38023: " + "Option 'server schannel require seal:%s = no' still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else if (!seal_required) { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: " + "Please use 'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + + TALLOC_FREE(frame); + return status; + } + + if (seal_required) { + status = NT_STATUS_ACCESS_DENIED; + if (seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (!schannel_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); + } else if (schannel_required) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE); + } + + DEBUG(dbg_lvl, ( + "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " + "%s request (opnum[%u]) %s schannel from " + "from client_account[%s] client_computer_name[%s] %s\n", + opname, opnum, reason, + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name), + nt_errstr(status))); + if (seal_explicitly_set) { + D_NOTICE("CVE-2022-38023: Option " + "'server schannel require seal:%s = yes' " + "rejects access for client.\n", + log_escape(frame, creds->account_name)); + } else { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } + if (!schannel_explicitly_set) { + DEBUG(CVE_2020_1472_error_level, ( + "CVE-2020-1472(ZeroLogon): Check if option " + "'server require schannel:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } else if (schannel_required) { + D_NOTICE("CVE-2022-38023: Option " + "'server require schannel:%s = yes' " + "also rejects access for client.\n", + log_escape(frame, creds->account_name)); + } TALLOC_FREE(frame); return status; } @@ -1172,6 +1357,9 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } else { dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level); } + if (!seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } DEBUG(dbg_lvl, ( "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: " @@ -1193,6 +1381,13 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, "might be needed for a legacy client.\n", log_escape(frame, creds->account_name))); } + if (!seal_explicitly_set) { + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Check if option " + "'server schannel require seal:%s = no' " + "might be needed for a legacy client.\n", + log_escape(frame, creds->account_name))); + } TALLOC_FREE(frame); return status; } @@ -1207,8 +1402,24 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, warned_global_schannel_once = true; } + if (!seal_global_required && !warned_global_seal_once) { + /* + * We want admins to notice their misconfiguration! + */ + DBG_ERR("CVE-2022-38023 (and others): " + "Please configure 'server schannel require seal = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_once = true; + } + status = NT_STATUS_OK; + if (seal_explicitly_set) { + dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); + } else { + dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level); + } + if (schannel_explicitly_set) { dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO); } else { @@ -1224,6 +1435,28 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, log_escape(frame, creds->computer_name), nt_errstr(status))); + if (seal_explicitly_set) { + D_INFO("CVE-2022-38023: Option " + "'server schannel require seal:%s = no' " + "still needed for '%s'!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name)); + } else { + /* + * admins should set + * server schannel require seal:COMPUTER$ = no + * in order to avoid the level 0 messages. + * Over time they can switch the global value + * to be strict. + */ + DEBUG(CVE_2022_38023_error_level, ( + "CVE-2022-38023: Please use " + "'server schannel require seal:%s = no' " + "for '%s' to avoid this warning!\n", + log_escape(frame, creds->account_name), + log_escape(frame, creds->computer_name))); + } + if (schannel_explicitly_set) { D_INFO("CVE-2020-1472(ZeroLogon): Option " "'server require schannel:%s = no' " @@ -1247,7 +1480,7 @@ static NTSTATUS netr_check_schannel(struct pipes_struct *p, } TALLOC_FREE(frame); - return NT_STATUS_OK; + return status; } static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, -- 2.39.0