1 /*
2  * openldap buffer overflow dos attempt
3  *
4  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
5  * Copyright (C) 2006-2013 Sourcefire, Inc. All Rights Reserved
6  *
7  * Writen by Patrick Mullen <pmullen@sourcefire.com>
8  *
9  * This file may contain proprietary rules that were created, tested and
10  * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
11  * rules that were created by Sourcefire and other third parties and
12  * distributed under the GNU General Public License (the "GPL Rules").  The
13  * VRT Certified Rules contained in this file are the property of
14  * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
15  * The GPL Rules created by Sourcefire, Inc. are the property of
16  * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
17  * Reserved.  All other GPL Rules are owned and copyrighted by their
18  * respective owners (please see www.snort.org/contributors for a list of
19  * owners and their respective copyrights).  In order to determine what
20  * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
21  * Certified Rules License Agreement.
22  */
23 
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "sf_snort_plugin_api.h"
30 #include "sf_snort_packet.h"
31 
32 /* declare detection functions */
33 static int ruleVD_OPENLDAPeval(void *p);
34 
35 static RuleReference ruleVD_OPENLDAPref0 =
36 {
37     "bugtraq", /* type */
38     "20939" /* value */
39 };
40 static RuleReference ruleVD_OPENLDAPcve =
41 {
42     "cve", /* type */
43     "CVE-2006-5779" /* value */
44 };
45 
46 
47 static RuleReference *ruleVD_OPENLDAPrefs[] =
48 {
49     &ruleVD_OPENLDAPref0,
50     &ruleVD_OPENLDAPcve,
51     NULL
52 };
53 
54 static FlowFlags ruleVD_OPENLDAPflow =
55 {
56     FLOW_ESTABLISHED|FLOW_TO_SERVER
57 };
58 
59 static RuleOption ruleVD_OPENLDAPoption0 =
60 {
61     OPTION_TYPE_FLOWFLAGS,
62     {
63         &ruleVD_OPENLDAPflow
64     }
65 };
66 
67 static ContentInfo ruleVD_OPENLDAPcontent =
68 {
69     (u_int8_t *)"|30|",       /* pattern to search for */
70     1,                      /* depth */
71     0,                      /* offset */
72     0,                      /* flags */
73     NULL,                   /* holder for boyer/moore info */
74     NULL,                   /* holder for byte representation of "NetBus" */
75     0,                      /* holder for length of byte representation */
76     0,                      /* holder of increment length */
77     0,                      /* holder for fp offset */
78     0,                      /* holder for fp length */
79     0,                      /* holder for fp only */
80     NULL, // offset_refId
81     NULL, // depth_refId
82     NULL, // offset_location
83     NULL  // depth_location
84 };
85 
86 static RuleOption ruleVD_OPENLDAPoption1 =
87 {
88     OPTION_TYPE_CONTENT,
89     {
90         &ruleVD_OPENLDAPcontent
91     }
92 };
93 
94 
95 RuleOption *ruleVD_OPENLDAPoptions[] =
96 {
97     &ruleVD_OPENLDAPoption0,
98     &ruleVD_OPENLDAPoption1,
99     NULL
100 };
101 
102 Rule ruleVD_OPENLDAP = {
103    /* rule header */
104    {
105        IPPROTO_TCP, /* proto */
106        "any", /* SRCIP     */
107        "any", /* SRCPORT   */
108        0, /* DIRECTION */
109        HOME_NET, /* DSTIP     */
110        "389", /* DSTPORT   */
111    },
112    /* metadata */
113    {
114        3,  /* genid (HARDCODED!!!) */
115        32694, /* XXX  sigid */
116        1, /* revision  */
117 
118        "attempted-admin", /* classification, generic */
119        0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
120        "openldap buffer overflow denial of service attempt",     /* message */
121        ruleVD_OPENLDAPrefs, /* ptr to references */
122        NULL /* Meta data */
123    },
124    ruleVD_OPENLDAPoptions, /* ptr to rule options */
125    &ruleVD_OPENLDAPeval, /* ptr to rule detection function */
126    0, /* am I initialized yet? */
127    0, /* number of options */
128    0, /* don't alert */
129    NULL /* ptr to internal data... setup during rule registration */
130 };
131 
132 
133 /* detection functions */
134 
135 /* process_val
136 
137    Returns the u_int32_t value contained at the pointer after skipping
138    preceeding NULs.  Returns an error if the data does not fit into
139    a u_int32_t.
140 */
process_val(const u_int8_t * data,u_int32_t data_len,u_int32_t * retvalue)141 static int process_val(const u_int8_t *data, u_int32_t data_len, u_int32_t *retvalue) {
142    u_int32_t actual_data_len, i;
143    *retvalue = 0;
144 
145    /* Jump over NULLs */
146    i = 0;
147    while((i < data_len) && (data[i] == 0)) {
148       i++;
149    }
150    actual_data_len = data_len - i;
151    if(actual_data_len > 4) return(-1); /* Data doesn't fit into u_int32_t */
152 
153    /* Now find the actual value */
154    for(;i<data_len;i++) {
155       *retvalue += data[i]<<(8*(data_len - i - 1));
156    }
157 
158    return(0);
159 }
160 
161 
162 /* skip_over_data
163 
164    Given an SFSnortPacket and a pointer to an index into the data,
165    this function will parse the size field at that index and move
166    the index to point after the size field and the data it describes.
167 
168    Size fields are as described in BER encoding.
169 */
skip_over_data(SFSnortPacket * sp,u_int32_t * current_byte)170 static int skip_over_data(SFSnortPacket *sp, u_int32_t *current_byte) {
171    u_int32_t width = 0, value = 0;
172    int retval = 0;
173 
174    if(sp->payload[*current_byte] & 0x80) {
175       width = sp->payload[*current_byte] & 0x0F;
176       (*current_byte)++;
177 
178       if(*current_byte >= sp->payload_size - width)
179          return(-1);
180 
181       retval = process_val(&(sp->payload[*current_byte]), width, &value);
182       if(retval < 0)
183          return(-1);            /* width is > 4 */
184       *current_byte += width;   /* width of data width specifier */
185       *current_byte += value;   /* width of data itself */
186    }  else {
187       *current_byte += sp->payload[*current_byte] + 1;
188    }
189 
190    return(0);
191 }
192 
193 
194 /* Detection algorithm --
195    We're looking for more than 0x0101 (257) bytes of data in the authentication
196    mechanism data field.  To do this, we minimally parse LDAP bind packets to
197    get to the data and ensure we encounter the correct data types along the way.
198 
199    0x30 - Universal Sequence
200    [Message size] - no data type, just a size
201    [Message ID] - int data type (0x02)
202 
203    0x60 - Bind request
204    [Bind Request size] - no data type, just a size
205    [LDAP version] - int data type (0x02)
206    [DN (username)] - string data type (0x04)
207 
208    0xa3 - Extended Auth Type, SASL
209    [Auth Data Size] - no data type, just a size
210    [Mechanism Name] - string data type
211    [Mechanism Data] - string data type -- if > 0x0101 bytes long, RULE_MATCH
212 
213    Note we don't actually care if the data is present in this
214    particular packet, which reduces evasion possibilities.
215 */
ruleVD_OPENLDAPeval(void * p)216 static int ruleVD_OPENLDAPeval(void *p) {
217    u_int32_t current_byte = 0;
218    u_int32_t width, value;
219    int retval;
220 
221    const u_int8_t *cursor_normal;
222 
223    SFSnortPacket *sp = (SFSnortPacket *) p;
224 
225    if(sp == NULL)
226       return RULE_NOMATCH;
227 
228    if(sp->payload == NULL)
229       return RULE_NOMATCH;
230 
231    if(sp->payload_size <= 26)   /* Minimum SASL bind request length (minus the auth data) */
232       return RULE_NOMATCH;
233 
234    /* call flow match */
235    if (checkFlow(sp, ruleVD_OPENLDAPoptions[0]->option_u.flowFlags) <= 0 )
236       return RULE_NOMATCH;
237 
238    /* call content match */
239    if (contentMatch(sp, ruleVD_OPENLDAPoptions[1]->option_u.content, &cursor_normal) <= 0) {
240       return RULE_NOMATCH;
241    }
242 
243    /* our contentMatch already assures us the first byte is \x30, so just jump over it */
244    current_byte++;
245 
246    /* Begin packet structure processing */
247    /* Packet length (only care about width of the specifier) */
248    if(sp->payload[current_byte] & 0x80) {
249       current_byte += sp->payload[current_byte] & 0x0F;
250    }
251    current_byte++;
252 
253    /* Message number (only care about width of the specifier) */
254    if(current_byte >= (u_int32_t)(sp->payload_size - 22))
255       return RULE_NOMATCH;
256 
257    if(sp->payload[current_byte] != 0x02) /* Int data type */
258       return RULE_NOMATCH;
259    current_byte++;
260 
261    /* Skip over int width and the int value */
262    if(skip_over_data(sp, &current_byte) < 0)
263       return RULE_NOMATCH;
264 
265    if(current_byte >= (u_int32_t)(sp->payload_size - 19))
266       return RULE_NOMATCH;
267 
268    /* Bind Request */
269    if(sp->payload[current_byte] != 0x60)
270       return RULE_NOMATCH;
271 
272    current_byte++;
273 
274    /* Message length  (only care about width of the specifier) */
275    if(sp->payload[current_byte] & 0x80) {
276       current_byte += sp->payload[current_byte] & 0x0F;
277    }
278    current_byte++;
279 
280    /* ldap version */
281    if(current_byte >= (u_int32_t)(sp->payload_size - 15))
282       return RULE_NOMATCH;
283 
284    /* ldap version */
285    if(sp->payload[current_byte] != 0x02) /* Int data type */
286       return RULE_NOMATCH;
287    current_byte++;
288 
289    /* Skip over int width and the int value */
290    if(skip_over_data(sp, &current_byte) < 0)
291       return RULE_NOMATCH;
292 
293    if(current_byte >= (u_int32_t)(sp->payload_size - 12))
294       return RULE_NOMATCH;
295 
296    /* user name (DN) */
297    /* 0x04 - string data type */
298    if(sp->payload[current_byte] != 0x04) /* string data type */
299       return RULE_NOMATCH;
300    current_byte++;
301 
302    /* Skip over string length specifier and the string */
303    if(skip_over_data(sp, &current_byte) < 0)
304       return RULE_NOMATCH;
305 
306    if(current_byte >= (u_int32_t)(sp->payload_size - 10))
307       return RULE_NOMATCH;
308 
309    /* 0xA3 - Auth type: SASL */
310    if(sp->payload[current_byte] != 0xA3)
311       return RULE_NOMATCH;
312    current_byte++;
313 
314    /* Auth data length - only care about width of specifier */
315    if(sp->payload[current_byte] & 0x80) {
316       current_byte += sp->payload[current_byte] & 0x0F;
317    }
318    current_byte++;
319 
320    if(current_byte >= (u_int32_t)(sp->payload_size - 6))
321       return RULE_NOMATCH;
322 
323    /* Auth Mechanism */
324    /* 0x04 - string data type */
325    if(sp->payload[current_byte] != 0x04)  /* string data type */
326       return RULE_NOMATCH;
327    current_byte++;
328 
329    /* Skip over string length specifier and the string */
330    /* String value can be anything */
331    if(skip_over_data(sp, &current_byte) < 0)
332       return RULE_NOMATCH;
333 
334    if(current_byte >= (u_int32_t)(sp->payload_size - 4))
335       return RULE_NOMATCH;
336 
337    /* Auth data */
338    /* 0x04 - string data type */
339    if(sp->payload[current_byte] != 0x04)  /* string data type */
340       return RULE_NOMATCH;
341    current_byte++;
342 
343    /* Here we can't just jump over the value because it's what
344       we're looking for. */
345    /* length of string -- if 0x0400 (1024 dec) it's an exploit attempt */
346    if(sp->payload[current_byte] & 0x80) {
347       width = sp->payload[current_byte] & 0x0F;
348       current_byte++;
349 
350       if(current_byte >= sp->payload_size - width)
351          return RULE_NOMATCH;
352 
353       retval = process_val(&(sp->payload[current_byte]), width, &value);
354       if(retval < 0)
355          return RULE_NOMATCH;  /* width is either 0 or > 4 */
356       current_byte += width;   /* width of data width specifier */
357       /* value equals the length of the string */
358    }  else {
359       value = sp->payload[current_byte];  /* length of the string */
360       current_byte++;
361    }
362 
363    if(value > 0x0101)    /* minimum length determined through testing */
364       return RULE_MATCH;
365 
366    return RULE_NOMATCH;
367 }
368 
369 /*
370 Rule *rules[] = {
371     &ruleVD_OPENLDAP,
372     NULL
373 };
374 */
375 
376