void smb_ntlmssp_negotiate(const char *host, const char *domain, smb_buffer *token) { smb_ntlmssp_nego *nego; assert(host != NULL && domain != NULL && token != NULL); token->size = sizeof(smb_ntlmssp_nego) + strlen(host) + strlen(domain); if (token->size % 2) // Align on Word token->size += 1; smb_buffer_alloc(token, token->size); // fprintf(stderr, "Token size if %ld\n", token->size); nego = (smb_ntlmssp_nego *)token->data; nego->type = SMB_NTLMSSP_CMD_NEGO; nego->flags = 0x60088215;//0x20080205; nego->domain_len = nego->domain_maxlen = strlen(domain); nego->domain_offset = 32; nego->host_len = nego->host_maxlen = strlen(host); nego->host_offset = 32 + strlen(domain); memcpy(nego->id, "NTLMSSP", 8); memcpy(nego->names, domain, strlen(domain)); memcpy(nego->names + strlen(domain), domain, strlen(domain)); }
uint8_t *smb_ntlm2_response(smb_ntlmh hash_v2, uint64_t srv_challenge, smb_buffer *blob) { smb_buffer data; uint8_t *response, hmac[16]; if (smb_buffer_alloc(&data, sizeof(uint64_t) + blob->size) == 0) return NULL; memcpy(data.data, (void *)&srv_challenge, sizeof(uint64_t)); memcpy((uint8_t*)data.data + sizeof(uint64_t), blob->data, blob->size); HMAC_MD5(hash_v2, SMB_NTLM_HASH_SIZE, data.data, data.size, &hmac); smb_buffer_free(&data); response = malloc(blob->size + 16); if (!response) return NULL; memcpy(response, (void *)hmac, 16); memcpy(response + 16, blob->data, blob->size); return response; }
void smb_ntlmssp_response(uint64_t srv_challenge, uint64_t srv_ts, const char *host, const char *domain, const char *user, const char *password, smb_buffer *target, smb_buffer *token) { smb_ntlmssp_auth *auth; smb_ntlm_blob *blob; smb_ntlmh hash_v2, xkey, xkey_crypt; smb_buffer buf; void *lm2, *ntlm2; size_t blob_size, utf_sz, cursor = 0; uint64_t user_challenge; char *utf; assert(host != NULL && domain != NULL && user != NULL && password != NULL); assert(token != NULL && target != NULL); //// We compute most of the data first to know the final token size smb_ntlm2_hash(user, password, domain, &hash_v2); user_challenge = smb_ntlm_generate_challenge(); smb_ntlm_generate_xkey(&xkey); blob_size = smb_ntlm_make_blob(&blob, srv_ts, user_challenge, target); lm2 = smb_lm2_response(&hash_v2, srv_challenge, smb_ntlm_generate_challenge()); smb_buffer_init(&buf, blob, blob_size); ntlm2 = smb_ntlm2_response(&hash_v2, srv_challenge, &buf); smb_ntlm2_session_key(&hash_v2, ntlm2, &xkey, &xkey_crypt); smb_buffer_init(&buf, NULL, 0); free(blob); // Compute size of and allocate token token->size = sizeof(smb_ntlmssp_auth) + strlen(host) * 2 + strlen(domain) * 2 + strlen(user) * 2 + blob_size + 16 // Blob + HMAC + 8 + 16 // LM2 Response (miniblob=user_challenge + HMAC) + 16; // Session Key if (token->size % 2) // Align on Word token->size += 1; smb_buffer_alloc(token, token->size); auth = (smb_ntlmssp_auth *)token->data; memset(auth, 0, token->size); memcpy(auth->id, "NTLMSSP", 8); auth->type = SMB_NTLMSSP_CMD_AUTH; auth->flags = 0x60088215; __AUTH_APPEND(lm, lm2, 24, cursor) __AUTH_APPEND(ntlm, ntlm2, blob_size + 16, cursor) utf_sz = smb_to_utf16(domain, strlen(domain), &utf); __AUTH_APPEND(domain, utf, utf_sz, cursor) free(utf); utf_sz = smb_to_utf16(user, strlen(user), &utf); __AUTH_APPEND(user, utf, utf_sz, cursor) free(utf); utf_sz = smb_to_utf16(host, strlen(host), &utf); __AUTH_APPEND(host, utf, utf_sz, cursor) free(utf); __AUTH_APPEND(session_key, &xkey_crypt, 16, cursor) free(lm2); free(ntlm2); }
static int challenge(smb_session *s) { char err_desc[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; char resp_token[256]; smb_message msg; smb_session_xsec_resp *resp; smb_ntlmssp_challenge *challenge; ASN1_TYPE token; int res, resp_token_size = 256; assert(s != NULL); if (smb_session_recv_msg(s, &msg) == 0) { BDSM_dbg("spnego challenge(): Unable to receive message\n"); return DSM_ERROR_NETWORK; } if (msg.packet->header.status != NT_STATUS_MORE_PROCESSING_REQUIRED) { BDSM_dbg("spnego challenge(): Bad status (0x%x)\n", msg.packet->header.status); return DSM_ERROR_GENERIC; } resp = (smb_session_xsec_resp *)msg.packet->payload; asn1_create_element(s->spnego_asn1, "SPNEGO.NegotiationToken", &token); res = asn1_der_decoding(&token, resp->payload, resp->xsec_blob_size, err_desc); if (res != ASN1_SUCCESS) { asn1_delete_structure(&token); asn1_display_error("NegTokenResp parsing", res); BDSM_dbg("Parsing error detail: %s\n", err_desc); return DSM_ERROR_GENERIC; } // XXX Check the value of "negTokenResp.negResult" res = asn1_read_value(token, "negTokenResp.responseToken", resp_token, &resp_token_size); asn1_delete_structure(&token); if (res != ASN1_SUCCESS) { asn1_display_error("NegTokenResp read responseToken", res); return DSM_ERROR_GENERIC; } // We got the server challenge, yeaaah. challenge = (smb_ntlmssp_challenge *)resp_token; if (smb_buffer_alloc(&s->xsec_target, challenge->tgt_len) == 0) return DSM_ERROR_GENERIC; memcpy(s->xsec_target.data, challenge->data + challenge->tgt_offset - sizeof(smb_ntlmssp_challenge), s->xsec_target.size); s->srv.challenge = challenge->challenge; s->srv.uid = msg.packet->header.uid; BDSM_dbg("Server challenge is 0x%"PRIx64"\n", s->srv.challenge); return DSM_SUCCESS; }