summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2020-09-16 19:20:25 +0200
committerKarolin Seeger <kseeger@samba.org>2020-09-18 12:58:23 +0200
commite799c47b6e0ec996099612a7f287888ed4d5559f (patch)
treea810502b02aeb1b5eb18bb7993f9740cf528e517
parentbffdfb129cead0448ad233fd8b94da9e7fb5aeca (diff)
downloadsamba-e799c47b6e0ec996099612a7f287888ed4d5559f.tar.gz
CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: protect netr_ServerPasswordSet2 against unencrypted passwords
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 Signed-off-by: Stefan Metzmacher <metze@samba.org>
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index de260d8051d..acbf077c6c7 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -722,7 +722,10 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
struct NL_PASSWORD_VERSION version = {};
const uint32_t *new_version = NULL;
NTSTATUS nt_status;
- DATA_BLOB new_password;
+ DATA_BLOB new_password = data_blob_null;
+ size_t confounder_len;
+ DATA_BLOB dec_blob = data_blob_null;
+ DATA_BLOB enc_blob = data_blob_null;
int ret;
struct samr_CryptPassword password_buf;
@@ -780,6 +783,61 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
return NT_STATUS_WRONG_PASSWORD;
}
+ /*
+ * Make sure the length field was encrypted,
+ * otherwise we are under attack.
+ */
+ if (new_password.length == r->in.new_password->length) {
+ DBG_WARNING("Length[%zu] field not encrypted\n",
+ new_password.length);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * We don't allow empty passwords for machine accounts.
+ */
+ if (new_password.length < 2) {
+ DBG_WARNING("Empty password Length[%zu]\n",
+ new_password.length);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * Make sure the confounder part of CryptPassword
+ * buffer was encrypted, otherwise we are under attack.
+ */
+ confounder_len = 512 - new_password.length;
+ enc_blob = data_blob_const(r->in.new_password->data, confounder_len);
+ dec_blob = data_blob_const(password_buf.data, confounder_len);
+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
+ DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n",
+ confounder_len);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * Check that the password part was actually encrypted,
+ * otherwise we are under attack.
+ */
+ enc_blob = data_blob_const(r->in.new_password->data + confounder_len,
+ new_password.length);
+ dec_blob = data_blob_const(password_buf.data + confounder_len,
+ new_password.length);
+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) {
+ DBG_WARNING("Password buffer not encrypted Length[%zu]\n",
+ new_password.length);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /*
+ * don't allow zero buffers
+ */
+ if (all_zero(new_password.data, new_password.length)) {
+ DBG_WARNING("Password zero buffer Length[%zu]\n",
+ new_password.length);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
/* fetch the old password hashes (at least one of both has to exist) */
ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs,