diff options
author | Stefan Metzmacher <metze@samba.org> | 2022-03-24 14:09:50 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2022-12-13 13:07:30 +0000 |
commit | 271cd82cd681d723572fcaeed24052dc98a83612 (patch) | |
tree | 47787c315b9f4fb175f6c859b39ad52f13113ad4 /source4/libnet | |
parent | 9e69289b099b47e0352ef67ef7e6529d11688e9a (diff) | |
download | samba-271cd82cd681d723572fcaeed24052dc98a83612.tar.gz |
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>
Diffstat (limited to 'source4/libnet')
-rw-r--r-- | source4/libnet/libnet_passwd.c | 73 | ||||
-rw-r--r-- | source4/libnet/libnet_passwd.h | 7 |
2 files changed, 80 insertions, 0 deletions
diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c index c5e15802bd2..8fc4715a209 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 f9fb5dad756..17e6aab4fca 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; |