CVE-2022-37966 s4:libnet: add support LIBNET_SET_PASSWORD_SAMR_HANDLE_18 to set nthas...
authorStefan Metzmacher <metze@samba.org>
Thu, 24 Mar 2022 13:09:50 +0000 (14:09 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 14 Dec 2022 10:28:17 +0000 (10:28 +0000)
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)

source4/libnet/libnet_passwd.c
source4/libnet/libnet_passwd.h

index d97e05c58ecdaddecdebdd2000c73167f775a630..bb99b5c5405aae94042b9a4d99a6a6dde2b4006c 100644 (file)
@@ -644,6 +644,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
@@ -662,6 +722,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);
@@ -836,6 +901,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;
@@ -860,6 +926,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;
@@ -912,6 +979,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;
index f9fb5dad7560b935421b08cdbb687ea7877ef35f..17e6aab4fca7423a2ef9b74265a7f9c316000123 100644 (file)
@@ -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;