mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
CVE-2016-2111: libcli/auth: add NTLMv2_RESPONSE_verify_netlogon_creds() helper function
This is the function that prevents spoofing like Microsoft's CVE-2015-0005. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11749 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Günther Deschner <gd@samba.org>
This commit is contained in:
parent
847192d493
commit
423e95b430
@ -155,6 +155,11 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
|
||||
const DATA_BLOB *names_blob,
|
||||
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
|
||||
DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
|
||||
NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
|
||||
const char *account_domain,
|
||||
const DATA_BLOB response,
|
||||
const struct netlogon_creds_CredentialState *creds,
|
||||
const char *workgroup);
|
||||
|
||||
/***********************************************************
|
||||
encode a password buffer with a unicode password. The buffer
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "../libcli/auth/msrpc_parse.h"
|
||||
#include "../lib/crypto/crypto.h"
|
||||
#include "../libcli/auth/libcli_auth.h"
|
||||
#include "../librpc/gen_ndr/ntlmssp.h"
|
||||
#include "../librpc/gen_ndr/ndr_ntlmssp.h"
|
||||
|
||||
void SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
|
||||
{
|
||||
@ -557,6 +557,138 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
|
||||
lm_response, nt_response, lm_session_key, user_session_key);
|
||||
}
|
||||
|
||||
NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
|
||||
const char *account_domain,
|
||||
const DATA_BLOB response,
|
||||
const struct netlogon_creds_CredentialState *creds,
|
||||
const char *workgroup)
|
||||
{
|
||||
TALLOC_CTX *frame = NULL;
|
||||
/* RespType + HiRespType */
|
||||
static const char *magic = "\x01\x01";
|
||||
int cmp;
|
||||
struct NTLMv2_RESPONSE v2_resp;
|
||||
enum ndr_err_code err;
|
||||
const struct AV_PAIR *av_nb_cn = NULL;
|
||||
const struct AV_PAIR *av_nb_dn = NULL;
|
||||
|
||||
if (response.length < 48) {
|
||||
/*
|
||||
* NTLMv2_RESPONSE has at least 48 bytes.
|
||||
*/
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
cmp = memcmp(response.data + 16, magic, 2);
|
||||
if (cmp != 0) {
|
||||
/*
|
||||
* It doesn't look like a valid NTLMv2_RESPONSE
|
||||
*/
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
frame = talloc_stackframe();
|
||||
|
||||
err = ndr_pull_struct_blob(&response, frame, &v2_resp,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
|
||||
NTSTATUS status;
|
||||
status = ndr_map_error2ntstatus(err);
|
||||
DEBUG(2,("Failed to parse NTLMv2_RESPONSE "
|
||||
"length %u - %s - %s\n",
|
||||
(unsigned)response.length,
|
||||
ndr_map_error2string(err),
|
||||
nt_errstr(status)));
|
||||
dump_data(2, response.data, response.length);
|
||||
TALLOC_FREE(frame);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (DEBUGLVL(10)) {
|
||||
NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the netbios computer name in the
|
||||
* NTLMv2_RESPONSE matches the computer name
|
||||
* in the secure channel credentials for workstation
|
||||
* trusts.
|
||||
*
|
||||
* And the netbios domain name matches our
|
||||
* workgroup.
|
||||
*
|
||||
* This prevents workstations from requesting
|
||||
* the session key of NTLMSSP sessions of clients
|
||||
* to other hosts.
|
||||
*/
|
||||
if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
|
||||
av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
|
||||
MsvAvNbComputerName);
|
||||
av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
|
||||
MsvAvNbDomainName);
|
||||
}
|
||||
|
||||
if (av_nb_cn != NULL) {
|
||||
const char *v = NULL;
|
||||
char *a = NULL;
|
||||
size_t len;
|
||||
|
||||
v = av_nb_cn->Value.AvNbComputerName;
|
||||
|
||||
a = talloc_strdup(frame, creds->account_name);
|
||||
if (a == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
len = strlen(a);
|
||||
if (len > 0 && a[len - 1] == '$') {
|
||||
a[len - 1] = '\0';
|
||||
}
|
||||
|
||||
cmp = strcasecmp_m(a, v);
|
||||
if (cmp != 0) {
|
||||
DEBUG(2,("%s: NTLMv2_RESPONSE with "
|
||||
"NbComputerName[%s] rejected "
|
||||
"for user[%s\\%s] "
|
||||
"against SEC_CHAN_WKSTA[%s/%s] "
|
||||
"in workgroup[%s]\n",
|
||||
__func__, v,
|
||||
account_domain,
|
||||
account_name,
|
||||
creds->computer_name,
|
||||
creds->account_name,
|
||||
workgroup));
|
||||
TALLOC_FREE(frame);
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
}
|
||||
if (av_nb_dn != NULL) {
|
||||
const char *v = NULL;
|
||||
|
||||
v = av_nb_dn->Value.AvNbDomainName;
|
||||
|
||||
cmp = strcasecmp_m(workgroup, v);
|
||||
if (cmp != 0) {
|
||||
DEBUG(2,("%s: NTLMv2_RESPONSE with "
|
||||
"NbDomainName[%s] rejected "
|
||||
"for user[%s\\%s] "
|
||||
"against SEC_CHAN_WKSTA[%s/%s] "
|
||||
"in workgroup[%s]\n",
|
||||
__func__, v,
|
||||
account_domain,
|
||||
account_name,
|
||||
creds->computer_name,
|
||||
creds->account_name,
|
||||
workgroup));
|
||||
TALLOC_FREE(frame);
|
||||
return NT_STATUS_LOGON_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
encode a password buffer with a unicode password. The buffer
|
||||
is filled with random data to make it harder to attack.
|
||||
|
Loading…
Reference in New Issue
Block a user