1 /* Copyright (c) 2007 by Errata Security */
\r
3 #include "netframe.h"
\r
12 #define MIN(a,b) ((a)<(b)?(a):(b))
\r
15 struct SMBdgm_transact
\r
17 unsigned word_count;
\r
18 unsigned total_parm_count;
\r
19 unsigned total_data_count;
\r
20 unsigned max_parm_count;
\r
21 unsigned max_data_count;
\r
22 unsigned max_setup_count;
\r
25 unsigned parm_count;
\r
26 unsigned parm_offset;
\r
27 unsigned data_count;
\r
28 unsigned data_offset;
\r
29 unsigned setup_count;
\r
30 unsigned byte_count;
\r
31 unsigned setup_offset;
\r
32 unsigned extra_offset;
\r
33 unsigned extra_length;
\r
42 unsigned process_id_high;
\r
43 unsigned process_id;
\r
44 unsigned char signature[8];
\r
47 unsigned multiplex_id;
\r
50 struct SMBdgm_transact trans;
\r
57 const unsigned char *name;
\r
58 unsigned name_length;
\r
63 static unsigned get_byte(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)
\r
66 unsigned offset = *r_offset;
\r
68 if (offset > length)
\r
70 if (offset == length) {
\r
71 FRAMERR(frame, "smb: truncated\n");
\r
74 result = px[offset];
\r
79 static unsigned get_word(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)
\r
82 unsigned offset = *r_offset;
\r
84 if (offset > length)
\r
86 if (offset == length) {
\r
87 FRAMERR(frame, "smb: truncated\n");
\r
90 if (offset+1 == length) {
\r
91 FRAMERR(frame, "smb: truncated\n");
\r
94 result = ex16le(px+offset);
\r
99 static unsigned get_dword(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)
\r
102 unsigned offset = *r_offset;
\r
104 if (offset > length)
\r
106 if (offset == length) {
\r
107 FRAMERR(frame, "smb: truncated\n");
\r
110 if (offset+1 == length) {
\r
111 FRAMERR(frame, "smb: truncated\n");
\r
114 if (offset+2 == length) {
\r
115 FRAMERR(frame, "smb: truncated\n");
\r
118 if (offset+3 == length) {
\r
119 FRAMERR(frame, "smb: truncated\n");
\r
122 result = ex32le(px+offset);
\r
128 static int path_equals(const unsigned char *name, unsigned name_length, const char *value)
\r
132 for (i=0; i<name_length && value[i]; i++)
\r
133 if (tolower(name[i]) != tolower(value[i]))
\r
135 if (i==name_length && value[i] == '\0')
\r
141 static unsigned cleanse_netbios_name(const char *name)
\r
143 unsigned length = strlen(name);
\r
145 if (length>4 && name[length-1] == '>') {
\r
146 if (isdigit(name[length-2]) && isdigit(name[length-3]) && name[length-4] == '<')
\r
149 while (length && isspace(name[length-1]))
\r
153 void process_BROWSE(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct SMBdgm *smb)
\r
158 cmd = px[offset]; //get_byte(frame, px, length, &offset);
\r
161 case 15: /*Local Master Announcement*/
\r
162 case 9: /* Get Backup List Request*/
\r
163 case 8: /* Browser election Request */
\r
164 case 2: /* Request Announcement */
\r
166 case 12: /*0x0c - Domain/Workgroup Announcement */
\r
168 const unsigned char *workgroup = px+offset+6;
\r
169 unsigned workgroup_length;
\r
170 const char *hostname = frame->netbios_source;
\r
171 unsigned hostname_length = cleanse_netbios_name(hostname);
\r
173 /* find nul terminator */
\r
174 for (workgroup_length=0; workgroup_length<16 && workgroup[workgroup_length]; workgroup_length++)
\r
177 process_record(seap,
\r
178 "proto", REC_SZ, "MS-BROWSE", -1,
\r
179 "op", REC_SZ, "domain", -1,
\r
180 "domain", REC_PRINTABLE, workgroup, workgroup_length,
\r
181 "hostname", REC_PRINTABLE, hostname, hostname_length,
\r
182 "ip.src", REC_FRAMESRC, frame, -1,
\r
186 case 1: /*0x01 - Host Announcement */
\r
188 const unsigned char *netbios;
\r
189 unsigned netbios_length;
\r
190 unsigned major, minor;
\r
191 const unsigned char *comment;
\r
192 unsigned comment_length;
\r
195 if (offset + 22 > length) {
\r
196 FRAMERR(frame, "MS-BROWSE: truncated\n");
\r
201 netbios = px+offset;
\r
203 /* find nul terminator */
\r
204 for (netbios_length=0; offset+netbios_length<length && netbios_length<16 && netbios[netbios_length]; netbios_length++)
\r
208 process_record(seap,
\r
209 "ID-IP", REC_FRAMESRC, frame, -1,
\r
210 "netbios", REC_PRINTABLE, netbios, netbios_length,
\r
215 if (offset + 2 > length) {
\r
216 FRAMERR(frame, "MS-BROWSE: truncated\n");
\r
220 major = px[offset];
\r
221 minor = px[offset+1];
\r
222 _snprintf(winver, sizeof(winver), "%d.%d", major, minor);
\r
224 process_record(seap,
\r
225 "ID-IP", REC_FRAMESRC, frame, -1,
\r
226 "win-ver", REC_SZ, winver, -1,
\r
232 comment = px+offset;
\r
233 for (comment_length=0; offset+comment_length<length && comment[comment_length]; comment_length++)
\r
235 if (comment_length)
\r
236 process_record(seap,
\r
237 "ID-IP", REC_FRAMESRC, frame, -1,
\r
238 "comment", REC_PRINTABLE, comment, comment_length,
\r
244 FRAMERR(frame, "MSBROWSE: unknown command %d\n", cmd);
\r
248 void process_smb_mailslot(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct SMBdgm *smb)
\r
250 unsigned offset_max;
\r
253 offset = smb->dgm.trans.setup_offset;
\r
255 if (smb->dgm.trans.setup_count != 3)
\r
256 FRAMERR(frame, "smb: corrupt\n");
\r
257 smb->mailslot.opcode = get_word(frame, px, length, &offset);
\r
258 smb->mailslot.priority = get_word(frame, px, length, &offset);
\r
259 smb->mailslot.clss = get_word(frame, px, length, &offset);
\r
261 smb->mailslot.name = px+smb->dgm.trans.extra_offset;
\r
262 for (i=0; i<length; i++)
\r
263 if (smb->mailslot.name[i] == '\0')
\r
265 smb->mailslot.name_length = i;
\r
267 switch (smb->mailslot.opcode) {
\r
268 case 1: /* write mail slot */
\r
269 offset = smb->dgm.trans.data_offset;
\r
270 offset_max = smb->dgm.trans.data_count;
\r
271 if (path_equals(smb->mailslot.name, smb->mailslot.name_length, "\\MAILSLOT\\BROWSE"))
\r
272 process_BROWSE(seap, frame, px, MIN(length, offset+offset_max), offset, smb);
\r
274 FRAMERR(frame, "smb: unknown mailslot=%.*s\n", smb->mailslot.name_length, smb->mailslot.name);
\r
277 FRAMERR(frame, "smb: corrupt\n");
\r
282 void process_smb_dgm_transaction(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct SMBdgm *smb)
\r
286 smb->dgm.trans.word_count = get_byte(frame, px, length, &offset);
\r
287 smb->dgm.trans.total_parm_count = get_word(frame, px, length, &offset);
\r
288 smb->dgm.trans.total_data_count = get_word(frame, px, length, &offset);
\r
289 smb->dgm.trans.max_parm_count = get_word(frame, px, length, &offset);
\r
290 smb->dgm.trans.max_data_count = get_word(frame, px, length, &offset);
\r
291 smb->dgm.trans.max_setup_count = get_byte(frame, px, length, &offset);
\r
292 reserved = get_byte(frame, px, length, &offset);
\r
293 smb->dgm.trans.flags = get_word(frame, px, length, &offset);
\r
294 smb->dgm.trans.timeout = get_dword(frame, px, length, &offset);
\r
295 reserved = get_word(frame, px, length, &offset);
\r
296 smb->dgm.trans.parm_count = get_word(frame, px, length, &offset);
\r
297 smb->dgm.trans.parm_offset = get_word(frame, px, length, &offset);
\r
298 smb->dgm.trans.data_count = get_word(frame, px, length, &offset);
\r
299 smb->dgm.trans.data_offset = get_word(frame, px, length, &offset);
\r
300 smb->dgm.trans.setup_count = get_byte(frame, px, length, &offset);
\r
301 reserved = get_byte(frame, px, length, &offset);
\r
302 smb->dgm.trans.setup_offset = offset;
\r
303 offset += smb->dgm.trans.setup_count*2;
\r
304 smb->dgm.trans.byte_count = get_word(frame, px, length, &offset);
\r
305 smb->dgm.trans.extra_offset = offset;
\r
307 if (offset+10 < length && memicmp(px+offset, "\\MAILSLOT\\", 10)==0)
\r
308 process_smb_mailslot(seap, frame, px, length, offset, smb);
\r
310 FRAMERR(frame, "smb: unknow transact command\n");
\r
314 void process_smb_dgm(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)
\r
321 FRAMERR(frame, "smb: truncated\n");
\r
326 smb.command = get_byte(frame, px, length, &offset);
\r
327 smb.err = get_byte(frame, px, length, &offset);
\r
328 reserved = get_byte(frame, px, length, &offset);
\r
329 smb.errcode = get_word(frame, px, length, &offset);
\r
330 smb.flags = get_byte(frame, px, length, &offset);
\r
331 smb.flags2 = get_word(frame, px, length, &offset);
\r
332 smb.process_id_high = get_word(frame, px, length, &offset);
\r
333 memcpy(smb.signature, px+offset, 8);
\r
335 reserved = get_word(frame, px, length, &offset);
\r
336 smb.tree_id = get_word(frame, px, length, &offset);
\r
337 smb.process_id = get_word(frame, px, length, &offset);
\r
338 smb.user_id = get_word(frame, px, length, &offset);
\r
339 smb.multiplex_id = get_word(frame, px, length, &offset);
\r
341 switch (smb.command) {
\r
342 case 0x25: /* Transaction Request*/
\r
343 process_smb_dgm_transaction(seap, frame, px, length, offset, &smb);
\r
346 FRAMERR(frame, "smb: unknow dgm command\n");
\r