summaryrefslogtreecommitdiffstats
path: root/contrib/impcap/smb_parser.c
blob: e673cd31f02878bb6100ea3d17e5302f951038af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* smb_parser.c
 *
 * This file contains functions to parse SMB (version 2 and 3) headers.
 *
 * File begun on 2018-11-13
 *
 * Created by:
 *  - Théo Bertin (theo.bertin@advens.fr)
 *
 * With:
 *  - François Bernard (francois.bernard@isen.yncrea.fr)
 *  - Tianyu Geng (tianyu.geng@isen.yncrea.fr)
 *
 * This file is part of rsyslog.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *       -or-
 *       see COPYING.ASL20 in the source distribution
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "config.h"
#include "parsers.h"

/* SMB2 opCodes */
#define SMB2_NEGOTIATE        0x00
#define SMB2_SESSIONSET       0x01
#define SMB2_SESSIONLOGOFF    0x02
#define SMB2_TREECONNECT      0x03
#define SMB2_TREEDISCONNECT   0x04
#define SMB2_CREATE           0x05
#define SMB2_CLOSE            0x06
#define SMB2_FLUSH            0x07
#define SMB2_READ             0x08
#define SMB2_WRITE            0x09
#define SMB2_LOCK             0x0a
#define SMB2_IOCTL            0x0b
#define SMB2_CANCEL           0x0c
#define SMB2_KEEPALIVE        0x0d
#define SMB2_FIND             0x0e
#define SMB2_NOTIFY           0x0f
#define SMB2_GETINFO          0x10
#define SMB2_SETINFO          0x11
#define SMB2_BREAK            0x12

struct smb_header_s {
	uint32_t version;
	uint16_t headerLength;
	uint16_t padding1;
	uint32_t ntStatus;
	uint16_t opCode;
	uint16_t padding2;
	uint32_t flags;
	uint32_t chainOffset;
	uint32_t comSeqNumber[2];
	uint32_t processID;
	uint32_t treeID;
	uint32_t userID[2];
	uint32_t signature[4];
};

typedef struct smb_header_s smb_header_t;

static char flagCodes[5] = "RPCS";

/*
 *  This function parses the bytes in the received packet to extract SMB2 metadata.
 *
 *  its parameters are:
 *    - a pointer on the list of bytes representing the packet
 *        the beginning of the header will be checked by the function
 *    - the size of the list passed as first parameter
 *    - a pointer on a json_object, containing all the metadata recovered so far
 *      this is also where SMB2 metadata will be added
 *
 *  This function returns a structure containing the data unprocessed by this parser
 *  or the ones after (as a list of bytes), and the length of this data.
*/
data_ret_t *smb_parse(const uchar *packet, int pktSize, struct json_object *jparent) {
	DBGPRINTF("smb_parse\n");
	DBGPRINTF("packet size %d\n", pktSize);

	int pktSizeCpy = pktSize;
	const uchar *packetCpy = packet;

	while (pktSizeCpy > 0) {
		/* don't check packetCpy[0] to include SMB version byte at the beginning */
		if (packetCpy[1] == 'S') {
			if (packetCpy[2] == 'M') {
				if (packetCpy[3] == 'B') {
					break;
				}
			}
		}
		packetCpy++, pktSizeCpy--;
	}

	if ((int)pktSizeCpy < 64) {
		DBGPRINTF("SMB packet too small : %d\n", pktSizeCpy);
		RETURN_DATA_AFTER(0)
	}

	/* Union to prevent cast from uchar to smb_header_t */
	union {
		const uchar *pck;
		smb_header_t *hdr;
	} smb_header_to_char;

	smb_header_to_char.pck = packetCpy;
	smb_header_t *smb_header = smb_header_to_char.hdr;

	char flags[5] = {0};
	uint64_t seqNum, userID;
	uint8_t version;

	version = (smb_header->version == 0xFF) ? 1 : 2;
	seqNum = smb_header->comSeqNumber[0] | smb_header->comSeqNumber[1] << 16;
	userID = smb_header->userID[0] | smb_header->userID[1] << 16;

	uint8_t i, pos = 0;
	for (i = 0; i < 4; ++i) {
		if (smb_header->flags & (0x01 << i))
			flags[pos++] = flagCodes[i];
	}

	json_object_object_add(jparent, "SMB_version", json_object_new_int(version));
	json_object_object_add(jparent, "SMB_NTstatus", json_object_new_int64(smb_header->ntStatus));
	json_object_object_add(jparent, "SMB_operation", json_object_new_int(smb_header->opCode));
	json_object_object_add(jparent, "SMB_flags", json_object_new_string(flags));
	json_object_object_add(jparent, "SMB_seqNumber", json_object_new_int64(seqNum));
	json_object_object_add(jparent, "SMB_processID", json_object_new_int64(smb_header->processID));
	json_object_object_add(jparent, "SMB_treeID", json_object_new_int64(smb_header->treeID));
	json_object_object_add(jparent, "SMB_userID", json_object_new_int64(userID));

	RETURN_DATA_AFTER(0)
}