192 lines
6.4 KiB
Diff
192 lines
6.4 KiB
Diff
|
|
From 1ac872983e6e1c7bc3652ce07f523de334c16280 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Date: Thu, 24 Mar 2022 14:09:50 +0100
|
||
|
|
Subject: [PATCH 40/54] CVE-2022-37966 s4:libnet: add support
|
||
|
|
LIBNET_SET_PASSWORD_SAMR_HANDLE_18 to set nthash only
|
||
|
|
|
||
|
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15237
|
||
|
|
|
||
|
|
Signed-off-by: Stefan Metzmacher <metze@samba.org>
|
||
|
|
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
|
||
|
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||
|
|
(cherry picked from commit 271cd82cd681d723572fcaeed24052dc98a83612)
|
||
|
|
|
||
|
|
Conflict: NA
|
||
|
|
Reference: https://attachments.samba.org/attachment.cgi?id=17695
|
||
|
|
---
|
||
|
|
source4/libnet/libnet_passwd.c | 73 ++++++++++++++++++++++++++++++++++
|
||
|
|
source4/libnet/libnet_passwd.h | 7 ++++
|
||
|
|
2 files changed, 80 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c
|
||
|
|
index c5e15802bd2b..8fc4715a2091 100644
|
||
|
|
--- a/source4/libnet/libnet_passwd.c
|
||
|
|
+++ b/source4/libnet/libnet_passwd.c
|
||
|
|
@@ -752,6 +752,66 @@ out:
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static NTSTATUS libnet_SetPassword_samr_handle_18(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
|
||
|
|
+{
|
||
|
|
+ NTSTATUS status;
|
||
|
|
+ struct samr_SetUserInfo2 sui;
|
||
|
|
+ union samr_UserInfo u_info;
|
||
|
|
+ struct samr_Password ntpwd;
|
||
|
|
+ DATA_BLOB ntpwd_in;
|
||
|
|
+ DATA_BLOB ntpwd_out;
|
||
|
|
+ DATA_BLOB session_key;
|
||
|
|
+ int rc;
|
||
|
|
+
|
||
|
|
+ if (r->samr_handle.in.info21) {
|
||
|
|
+ return NT_STATUS_INVALID_PARAMETER_MIX;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* prepare samr_SetUserInfo2 level 18 (nt_hash) */
|
||
|
|
+ ZERO_STRUCT(u_info);
|
||
|
|
+ E_md4hash(r->samr_handle.in.newpassword, ntpwd.hash);
|
||
|
|
+ ntpwd_in = data_blob_const(ntpwd.hash, sizeof(ntpwd.hash));
|
||
|
|
+ ntpwd_out = data_blob_const(u_info.info18.nt_pwd.hash,
|
||
|
|
+ sizeof(u_info.info18.nt_pwd.hash));
|
||
|
|
+ u_info.info18.nt_pwd_active = 1;
|
||
|
|
+ u_info.info18.password_expired = 0;
|
||
|
|
+
|
||
|
|
+ status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
|
||
|
|
+ if (!NT_STATUS_IS_OK(status)) {
|
||
|
|
+ r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
|
||
|
|
+ "dcerpc_fetch_session_key failed: %s",
|
||
|
|
+ nt_errstr(status));
|
||
|
|
+ return status;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ rc = sess_crypt_blob(&ntpwd_out, &ntpwd_in,
|
||
|
|
+ &session_key, SAMBA_GNUTLS_ENCRYPT);
|
||
|
|
+ if (rc < 0) {
|
||
|
|
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
|
||
|
|
+ goto out;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sui.in.user_handle = r->samr_handle.in.user_handle;
|
||
|
|
+ sui.in.info = &u_info;
|
||
|
|
+ sui.in.level = 18;
|
||
|
|
+
|
||
|
|
+ /* 9. try samr_SetUserInfo2 level 18 to set the password */
|
||
|
|
+ status = dcerpc_samr_SetUserInfo2_r(r->samr_handle.in.dcerpc_pipe->binding_handle, mem_ctx, &sui);
|
||
|
|
+ if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sui.out.result)) {
|
||
|
|
+ status = sui.out.result;
|
||
|
|
+ }
|
||
|
|
+ if (!NT_STATUS_IS_OK(status)) {
|
||
|
|
+ r->samr_handle.out.error_string
|
||
|
|
+ = talloc_asprintf(mem_ctx,
|
||
|
|
+ "SetUserInfo2 level 18 for [%s] failed: %s",
|
||
|
|
+ r->samr_handle.in.account_name, nt_errstr(status));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+out:
|
||
|
|
+ data_blob_clear(&session_key);
|
||
|
|
+ return status;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
* 1. try samr_SetUserInfo2 level 26 to set the password
|
||
|
|
* 2. try samr_SetUserInfo2 level 25 to set the password
|
||
|
|
@@ -770,6 +830,11 @@ static NTSTATUS libnet_SetPassword_samr_handle(struct libnet_context *ctx, TALLO
|
||
|
|
};
|
||
|
|
unsigned int i;
|
||
|
|
|
||
|
|
+ if (r->samr_handle.samr_level != 0) {
|
||
|
|
+ r->generic.level = r->samr_handle.samr_level;
|
||
|
|
+ return libnet_SetPassword(ctx, mem_ctx, r);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
for (i=0; i < ARRAY_SIZE(levels); i++) {
|
||
|
|
r->generic.level = levels[i];
|
||
|
|
status = libnet_SetPassword(ctx, mem_ctx, r);
|
||
|
|
@@ -944,6 +1009,7 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
|
||
|
|
|
||
|
|
ZERO_STRUCT(r2);
|
||
|
|
r2.samr_handle.level = LIBNET_SET_PASSWORD_SAMR_HANDLE;
|
||
|
|
+ r2.samr_handle.samr_level = r->samr.samr_level;
|
||
|
|
r2.samr_handle.in.account_name = r->samr.in.account_name;
|
||
|
|
r2.samr_handle.in.newpassword = r->samr.in.newpassword;
|
||
|
|
r2.samr_handle.in.user_handle = &u_handle;
|
||
|
|
@@ -968,6 +1034,7 @@ static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CT
|
||
|
|
|
||
|
|
ZERO_STRUCT(r2);
|
||
|
|
r2.samr.level = LIBNET_SET_PASSWORD_SAMR;
|
||
|
|
+ r2.samr.samr_level = r->generic.samr_level;
|
||
|
|
r2.samr.in.account_name = r->generic.in.account_name;
|
||
|
|
r2.samr.in.domain_name = r->generic.in.domain_name;
|
||
|
|
r2.samr.in.newpassword = r->generic.in.newpassword;
|
||
|
|
@@ -1020,6 +1087,12 @@ NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, uni
|
||
|
|
}
|
||
|
|
status = libnet_SetPassword_samr_handle_23(ctx, mem_ctx, r);
|
||
|
|
break;
|
||
|
|
+ case LIBNET_SET_PASSWORD_SAMR_HANDLE_18:
|
||
|
|
+ if (encryption_state == SMB_ENCRYPTION_REQUIRED) {
|
||
|
|
+ GNUTLS_FIPS140_SET_LAX_MODE();
|
||
|
|
+ }
|
||
|
|
+ status = libnet_SetPassword_samr_handle_18(ctx, mem_ctx, r);
|
||
|
|
+ break;
|
||
|
|
case LIBNET_SET_PASSWORD_KRB5:
|
||
|
|
status = NT_STATUS_NOT_IMPLEMENTED;
|
||
|
|
break;
|
||
|
|
diff --git a/source4/libnet/libnet_passwd.h b/source4/libnet/libnet_passwd.h
|
||
|
|
index f9fb5dad7560..17e6aab4fca7 100644
|
||
|
|
--- a/source4/libnet/libnet_passwd.h
|
||
|
|
+++ b/source4/libnet/libnet_passwd.h
|
||
|
|
@@ -76,6 +76,7 @@ enum libnet_SetPassword_level {
|
||
|
|
LIBNET_SET_PASSWORD_SAMR_HANDLE_25,
|
||
|
|
LIBNET_SET_PASSWORD_SAMR_HANDLE_24,
|
||
|
|
LIBNET_SET_PASSWORD_SAMR_HANDLE_23,
|
||
|
|
+ LIBNET_SET_PASSWORD_SAMR_HANDLE_18,
|
||
|
|
LIBNET_SET_PASSWORD_KRB5,
|
||
|
|
LIBNET_SET_PASSWORD_LDAP,
|
||
|
|
LIBNET_SET_PASSWORD_RAP
|
||
|
|
@@ -84,6 +85,7 @@ enum libnet_SetPassword_level {
|
||
|
|
union libnet_SetPassword {
|
||
|
|
struct {
|
||
|
|
enum libnet_SetPassword_level level;
|
||
|
|
+ enum libnet_SetPassword_level samr_level;
|
||
|
|
|
||
|
|
struct _libnet_SetPassword_in {
|
||
|
|
const char *account_name;
|
||
|
|
@@ -98,6 +100,7 @@ union libnet_SetPassword {
|
||
|
|
|
||
|
|
struct {
|
||
|
|
enum libnet_SetPassword_level level;
|
||
|
|
+ enum libnet_SetPassword_level samr_level;
|
||
|
|
struct _libnet_SetPassword_samr_handle_in {
|
||
|
|
const char *account_name; /* for debug only */
|
||
|
|
struct policy_handle *user_handle;
|
||
|
|
@@ -113,24 +116,28 @@ union libnet_SetPassword {
|
||
|
|
|
||
|
|
struct {
|
||
|
|
enum libnet_SetPassword_level level;
|
||
|
|
+ enum libnet_SetPassword_level samr_level;
|
||
|
|
struct _libnet_SetPassword_in in;
|
||
|
|
struct _libnet_SetPassword_out out;
|
||
|
|
} samr;
|
||
|
|
|
||
|
|
struct {
|
||
|
|
enum libnet_SetPassword_level level;
|
||
|
|
+ enum libnet_SetPassword_level samr_level;
|
||
|
|
struct _libnet_SetPassword_in in;
|
||
|
|
struct _libnet_SetPassword_out out;
|
||
|
|
} krb5;
|
||
|
|
|
||
|
|
struct {
|
||
|
|
enum libnet_SetPassword_level level;
|
||
|
|
+ enum libnet_SetPassword_level samr_level;
|
||
|
|
struct _libnet_SetPassword_in in;
|
||
|
|
struct _libnet_SetPassword_out out;
|
||
|
|
} ldap;
|
||
|
|
|
||
|
|
struct {
|
||
|
|
enum libnet_ChangePassword_level level;
|
||
|
|
+ enum libnet_SetPassword_level samr_level;
|
||
|
|
struct _libnet_SetPassword_in in;
|
||
|
|
struct _libnet_SetPassword_out out;
|
||
|
|
} rap;
|
||
|
|
--
|
||
|
|
2.34.1
|