void smb_ntlm2_hash(const char *user, const char *password, const char *dest, smb_ntlmh *hash) { smb_ntlmh hash_v1; char *ucs_user, *ucs_dest, *data, user_upper[64]; size_t ucs_user_len, ucs_dest_len, data_len; smb_ntlm_hash(password, &hash_v1); strlcpy(user_upper, user, 64); _upcase(user_upper); ucs_user_len = smb_to_utf16(user_upper, strlen(user_upper), &ucs_user); ucs_dest_len = smb_to_utf16(dest, strlen(dest), &ucs_dest); data_len = ucs_user_len + ucs_dest_len; data = alloca(data_len); memcpy(data, ucs_user, ucs_user_len); memcpy(data + ucs_user_len, ucs_dest, ucs_dest_len); HMAC_MD5(hash_v1, SMB_NTLM_HASH_SIZE, data, data_len, hash); free(ucs_user); free(ucs_dest); }
void smb_ntlm_hash(const char *password, smb_ntlmh *hash) { MD4_CTX ctx; char *ucs2le_pass; size_t sz; assert(password != NULL && hash != NULL); sz = smb_to_utf16(password, strlen(password), &ucs2le_pass); memset((void *)hash, 0, SMB_NTLM_HASH_SIZE); MD4_Init(&ctx); MD4_Update(&ctx, (uint8_t *)ucs2le_pass, sz); MD4_Final((uint8_t *)hash, &ctx); free(ucs2le_pass); }
smb_fd smb_fopen(smb_session *s, smb_tid tid, const char *path, uint32_t o_flags) { smb_share *share; smb_file *file; smb_message *req_msg, resp_msg; smb_create_req req; smb_create_resp *resp; size_t path_len; int res; char *utf_path; assert(s != NULL && path != NULL); if ((share = smb_session_share_get(s, tid)) == NULL) return (0); path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path); if (path_len == 0) return (0); req_msg = smb_message_new(SMB_CMD_CREATE); if (!req_msg) { free(utf_path); return (0); } // Set SMB Headers req_msg->packet->header.tid = tid; // Create AndX Params SMB_MSG_INIT_PKT_ANDX(req); req.wct = 24; req.flags = 0; req.root_fid = 0; req.access_mask = o_flags; req.alloc_size = 0; req.file_attr = 0; req.share_access = SMB_SHARE_READ | SMB_SHARE_WRITE; req.disposition = 1; // 1 = Open and file if doesn't exist req.create_opts = 0; // We dont't support create req.impersonation = 2; // ????? req.security_flags = 0; // ??? req.path_length = path_len; req.bct = path_len + 1; SMB_MSG_PUT_PKT(req_msg, req); // Create AndX 'Body' smb_message_put8(req_msg, 0); // Align beginning of path smb_message_append(req_msg, utf_path, path_len); free(utf_path); // smb_message_put16(req_msg, 0); // ?? res = smb_session_send_msg(s, req_msg); smb_message_destroy(req_msg); if (!res) return (0); if (!smb_session_recv_msg(s, &resp_msg)) return (0); if (resp_msg.packet->header.status != NT_STATUS_SUCCESS) return (0); resp = (smb_create_resp *)resp_msg.packet->payload; file = calloc(1, sizeof(smb_file)); if (!file) return (0); file->fid = resp->fid; file->tid = tid; file->created = resp->created; file->accessed = resp->accessed; file->written = resp->written; file->changed = resp->changed; file->alloc_size = resp->alloc_size; file->size = resp->size; file->attr = resp->attr; file->is_dir = resp->is_dir; smb_session_file_add(s, tid, file); // XXX Check return return (SMB_FD(tid, file->fid)); }
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); }
int smb_tree_connect(smb_session *s, const char *name, smb_tid *tid) { smb_tree_connect_req req; smb_tree_connect_resp *resp; smb_message resp_msg; smb_message *req_msg; smb_share *share; size_t path_len, utf_path_len; char *path, *utf_path; assert(s != NULL && name != NULL && tid != NULL); if( s != NULL && name != NULL && tid != NULL ) { req_msg = smb_message_new(SMB_CMD_TREE_CONNECT); if (!req_msg) return DSM_ERROR_GENERIC; // Build \\SERVER\Share path from name path_len = strlen(name) + strlen(s->srv.name) + 4; path = alloca(path_len); snprintf(path, path_len, "\\\\%s\\%s", s->srv.name, name); utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path); // Packet headers req_msg->packet->header.tid = 0xffff; // Behavior of libsmbclient smb_message_set_andx_members(req_msg); // Packet payload SMB_MSG_INIT_PKT_ANDX(req); req.wct = 4; req.flags = 0x0c; // (??) req.passwd_len = 1; // Null byte req.bct = utf_path_len + 6 + 1; SMB_MSG_PUT_PKT(req_msg, req); smb_message_put8(req_msg, 0); // Ze null byte password; smb_message_append(req_msg, utf_path, utf_path_len); free(utf_path); smb_message_append(req_msg, "?????", strlen("?????") + 1); if (!smb_session_send_msg(s, req_msg)) { smb_message_destroy(req_msg); return DSM_ERROR_NETWORK; } smb_message_destroy(req_msg); if (!smb_session_recv_msg(s, &resp_msg)) return DSM_ERROR_NETWORK; if (!smb_session_check_nt_status(s, &resp_msg)) return DSM_ERROR_NT; resp = (smb_tree_connect_resp *)resp_msg.packet->payload; share = calloc(1, sizeof(smb_share)); if (!share) return DSM_ERROR_GENERIC; share->tid = resp_msg.packet->header.tid; share->opts = resp->opt_support; share->rights = resp->max_rights; share->guest_rights = resp->guest_rights; smb_session_share_add(s, share); *tid = share->tid; return 0; } return DSM_ERROR_GENERIC; }
smb_file *smb_fstat(smb_session *s, smb_tid tid, const char *path) { smb_message *msg, reply; smb_trans2_req tr2; smb_trans2_resp *tr2_resp; smb_tr2_query query; smb_tr2_path_info *info; smb_file *file; size_t utf_path_len, msg_len; char *utf_path; int res, padding = 0; assert(s != NULL && path != NULL); utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path); if (utf_path_len == 0) return 0; msg_len = sizeof(smb_trans2_req) + sizeof(smb_tr2_query); msg_len += utf_path_len; if (msg_len %4) padding = 4 - msg_len % 4; msg = smb_message_new(SMB_CMD_TRANS2); if (!msg) { free(utf_path); return 0; } msg->packet->header.tid = tid; SMB_MSG_INIT_PKT(tr2); tr2.wct = 15; tr2.total_param_count = utf_path_len + sizeof(smb_tr2_query); tr2.param_count = tr2.total_param_count; tr2.max_param_count = 2; // ?? Why not the same or 12 ? tr2.max_data_count = 0xffff; tr2.param_offset = 68; // Offset of find_first_params in packet; tr2.data_count = 0; tr2.data_offset = 96; // Offset of pattern in packet tr2.setup_count = 1; tr2.cmd = SMB_TR2_QUERY_PATH; tr2.bct = sizeof(smb_tr2_query) + utf_path_len + padding; SMB_MSG_PUT_PKT(msg, tr2); SMB_MSG_INIT_PKT(query); query.interest = SMB_FIND2_QUERY_FILE_ALL_INFO; SMB_MSG_PUT_PKT(msg, query); smb_message_append(msg, utf_path, utf_path_len); free(utf_path); // Adds padding at the end if necessary. while (padding--) smb_message_put8(msg, 0); res = smb_session_send_msg(s, msg); smb_message_destroy(msg); if (!res) { BDSM_dbg("Unable to query pattern: %s\n", path); return NULL; } if (!smb_session_recv_msg(s, &reply) || reply.packet->header.status != NT_STATUS_SUCCESS) { BDSM_dbg("Unable to recv msg or failure for %s\n", path); return NULL; } tr2_resp = (smb_trans2_resp *)reply.packet->payload; info = (smb_tr2_path_info *)(tr2_resp->payload + 4); //+4 is padding file = calloc(1, sizeof(smb_file)); if (!file) return NULL; file->name_len = smb_from_utf16((const char *)info->name, info->name_len, &file->name); file->name[info->name_len / 2] = 0; file->created = info->created; file->accessed = info->accessed; file->written = info->written; file->changed = info->changed; file->alloc_size = info->alloc_size; file->size = info->size; file->attr = info->attr; file->is_dir = info->is_dir; return file; }
static smb_message *smb_trans2_find_next (smb_session *s, smb_tid tid, uint16_t resume_key, uint16_t sid, const char *pattern) { smb_message *msg_find_next2 = NULL; smb_trans2_req tr2_find_next2; smb_tr2_findnext2 find_next2; size_t utf_pattern_len, tr2_bct, tr2_param_count; char *utf_pattern; int res; unsigned int padding = 0; assert(s != NULL && pattern != NULL); utf_pattern_len = smb_to_utf16(pattern, strlen(pattern) + 1, &utf_pattern); if (utf_pattern_len == 0) return NULL; tr2_bct = sizeof(smb_tr2_findnext2) + utf_pattern_len; tr2_param_count = tr2_bct; tr2_bct += 3; // Adds padding at the end if necessary. while ((tr2_bct % 4) != 3) { padding++; tr2_bct++; } msg_find_next2 = smb_message_new(SMB_CMD_TRANS2); if (!msg_find_next2) { free(utf_pattern); return NULL; } msg_find_next2->packet->header.tid = tid; SMB_MSG_INIT_PKT(tr2_find_next2); tr2_find_next2.wct = 0x0f; tr2_find_next2.total_param_count = tr2_param_count; tr2_find_next2.total_data_count = 0x0000; tr2_find_next2.max_param_count = 10; // ?? Why not the same or 12 ? tr2_find_next2.max_data_count = 0xffff; //max_setup_count //reserved //flags //timeout //reserve2 tr2_find_next2.param_count = tr2_param_count; tr2_find_next2.param_offset = 68; // Offset of find_next_params in packet; tr2_find_next2.data_count = 0; tr2_find_next2.data_offset = 88; // Offset of pattern in packet tr2_find_next2.setup_count = 1; //reserve3 tr2_find_next2.cmd = SMB_TR2_FIND_NEXT; tr2_find_next2.bct = tr2_bct; //3 == padding SMB_MSG_PUT_PKT(msg_find_next2, tr2_find_next2); SMB_MSG_INIT_PKT(find_next2); find_next2.sid = sid; find_next2.count = 255; find_next2.interest = SMB_FIND2_INTEREST_BOTH_DIRECTORY_INFO; find_next2.flags = SMB_FIND2_FLAG_CLOSE_EOS|SMB_FIND2_FLAG_CONTINUE; find_next2.resume_key = resume_key; SMB_MSG_PUT_PKT(msg_find_next2, find_next2); smb_message_append(msg_find_next2, utf_pattern, utf_pattern_len); while (padding--) smb_message_put8(msg_find_next2, 0); res = smb_session_send_msg(s, msg_find_next2); smb_message_destroy(msg_find_next2); free(utf_pattern); if (!res) { BDSM_dbg("Unable to query pattern: %s\n", pattern); return NULL; } msg_find_next2 = smb_tr2_recv(s); return msg_find_next2; }
static smb_message *smb_trans2_find_first (smb_session *s, smb_tid tid, const char *pattern) { smb_message *msg; smb_trans2_req tr2; smb_tr2_findfirst2 find; size_t utf_pattern_len, tr2_bct, tr2_param_count; char *utf_pattern; int res; unsigned int padding = 0; assert(s != NULL && pattern != NULL); utf_pattern_len = smb_to_utf16(pattern, strlen(pattern) + 1, &utf_pattern); if (utf_pattern_len == 0) return NULL; tr2_bct = sizeof(smb_tr2_findfirst2) + utf_pattern_len; tr2_param_count = tr2_bct; tr2_bct += 3; // Adds padding at the end if necessary. while ((tr2_bct % 4) != 3) { padding++; tr2_bct++; } msg = smb_message_new(SMB_CMD_TRANS2); if (!msg) { free(utf_pattern); return NULL; } msg->packet->header.tid = tid; SMB_MSG_INIT_PKT(tr2); tr2.wct = 15; tr2.max_param_count = 10; // ?? Why not the same or 12 ? tr2.max_data_count = 0xffff;; tr2.param_offset = 68; // Offset of find_first_params in packet; tr2.data_count = 0; tr2.data_offset = 88; // Offset of pattern in packet tr2.setup_count = 1; tr2.cmd = SMB_TR2_FIND_FIRST; tr2.total_param_count = tr2_param_count; tr2.param_count = tr2_param_count; tr2.bct = tr2_bct; //3 == padding SMB_MSG_PUT_PKT(msg, tr2); SMB_MSG_INIT_PKT(find); find.attrs = SMB_FIND2_ATTR_DEFAULT; find.count = 1366; // ?? find.flags = SMB_FIND2_FLAG_CLOSE_EOS | SMB_FIND2_FLAG_RESUME; find.interest = SMB_FIND2_INTEREST_BOTH_DIRECTORY_INFO; SMB_MSG_PUT_PKT(msg, find); smb_message_append(msg, utf_pattern, utf_pattern_len); while (padding--) smb_message_put8(msg, 0); res = smb_session_send_msg(s, msg); smb_message_destroy(msg); free(utf_pattern); if (!res) { BDSM_dbg("Unable to query pattern: %s\n", pattern); return NULL; } msg = smb_tr2_recv(s); return msg; }