1 /*
2     ettercap -- dissector RADIUS -- TCP/UDP 1645 1646 1812 1813
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 /*
23  *    0                   1                   2                   3
24  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
25  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26  *   |     Code      |   Identifier  |            Length             |
27  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28  *   | . . . . . . . . . . 16-Bytes Authenticator. . . . . . . . . . |
29  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30  *   | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
31  *   | . . . . . . . . . . . . . Attributes  . . . . . . . . . . . . |
32  *   | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
33  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34  *
35  *   RFC 2865
36  *
37  * The password is first
38  * padded at the end with nulls to a multiple of 16 octets.  A one-
39  * way MD5 hash is calculated over a stream of octets consisting of
40  * the shared secret followed by the Request Authenticator.  This
41  * value is XORed with the first 16 octet segment of the password and
42  * placed in the first 16 octets of the String field of the User-
43  * Password Attribute.
44  *
45  * If the password is longer than 16 characters, a second one-way MD5
46  * hash is calculated over a stream of octets consisting of the
47  * shared secret followed by the result of the first xor.  That hash
48  * is XORed with the second 16 octet segment of the password and
49  * placed in the second 16 octets of the String field of the User-
50  * Password Attribute.
51  *
52  * If necessary, this operation is repeated, with each xor result
53  * being used along with the shared secret to generate the next hash
54  * to xor the next segment of the password, to no more than 128
55  * characters.
56  */
57 
58 #include <ec.h>
59 #include <ec_decode.h>
60 #include <ec_dissect.h>
61 
62 /* globals */
63 
64 struct radius_header {
65    u_int8  code;              /* type of the packet */
66       #define RADIUS_ACCESS_REQUEST    0x1
67       #define RADIUS_ACCESS_ACCEPT     0x2
68       #define RADIUS_ACCESS_REJECT     0x3
69       #define RADIUS_ACCOUNT_REQUEST   0x4
70       #define RADIUS_ACCOUNT_RESPONSE  0x5
71    u_int8  id;                /* identifier */
72    u_int16 length;            /* packet length */
73    u_int8  auth[16];          /* authenticator */
74 };
75 
76 #define RADIUS_HEADER_LEN   0x14  /* 12 bytes */
77 
78 #define RADIUS_ATTR_USER_NAME          0x01
79 #define RADIUS_ATTR_PASSWORD           0x02
80 
81 /* proto */
82 
83 FUNC_DECODER(dissector_radius);
84 void radius_init(void);
85 static u_char * radius_get_attribute(u_int8 attr, u_int8 *attr_len, u_char *begin, u_char *end);
86 
87 /************************************************/
88 
89 /*
90  * this function is the initializer.
91  * it adds the entry in the table of registered decoder
92  */
93 
radius_init(void)94 void __init radius_init(void)
95 {
96    dissect_add("radius", APP_LAYER_UDP, 1645, dissector_radius);
97    dissect_add("radius", APP_LAYER_UDP, 1646, dissector_radius);
98    dissect_add("radius", APP_LAYER_TCP, 1812, dissector_radius);
99    dissect_add("radius", APP_LAYER_UDP, 1812, dissector_radius);
100    dissect_add("radius", APP_LAYER_TCP, 1813, dissector_radius);
101    dissect_add("radius", APP_LAYER_UDP, 1813, dissector_radius);
102 }
103 
FUNC_DECODER(dissector_radius)104 FUNC_DECODER(dissector_radius)
105 {
106    DECLARE_REAL_PTR_END(ptr, end);
107    char tmp[MAX_ASCII_ADDR_LEN];
108    struct radius_header *radius;
109    u_char *attributes;
110    char *attr;
111    u_int8 attr_len;
112    char user[0xff+1];
113    char pass[0xff+1];
114    char auth[0xff];
115    size_t i;
116 
117    /* don't complain about unused var */
118    (void) DECODE_DATA;
119    (void) DECODE_DATALEN;
120    (void) DECODED_LEN;
121 
122    DEBUG_MSG("RADIUS --> UDP dissector_radius");
123 
124    /* parse the packet as a radius header */
125    radius = (struct radius_header *)ptr;
126 
127    /* get the pointer to the attributes list */
128    attributes = (u_char *)(radius + 1);
129 
130    /* we are interested only in ACCESS REQUESTS */
131    if (radius->code != RADIUS_ACCESS_REQUEST)
132       return NULL;
133 
134    /* search for the username attribute */
135    attr = (char*)radius_get_attribute(RADIUS_ATTR_USER_NAME, &attr_len, attributes, end);
136 
137    /* if the attribute is not found, the packet is not interesting */
138    if (attr == NULL)
139       return NULL;
140 
141    /*
142     * max attr_len is 0xff
143     * copy the paramenter into the buffer and null terminate it
144     */
145    memset(user, 0, sizeof(user));
146    strncpy(user, attr, attr_len);
147 
148    /* search for the password attribute */
149    attr = (char*)radius_get_attribute(RADIUS_ATTR_PASSWORD, &attr_len, attributes, end);
150 
151    /* if the attribute is not found, the packet is not interesting */
152    if (attr == NULL)
153       return NULL;
154 
155    /*
156     * max attr_len is 0xff
157     * copy the paramenter into the buffer and null terminate it
158     */
159    memset(pass, 0, sizeof(pass));
160    strncpy(pass, attr, attr_len);
161 
162    for (i = 0; i < 16; i++)
163       snprintf(auth + i*2, 3, "%02X", radius->auth[i]);
164 
165 
166    SAFE_CALLOC(PACKET->DISSECTOR.pass, attr_len * 2 + 1, sizeof(char));
167 
168    /* save the info */
169    PACKET->DISSECTOR.user = strdup(user);
170 
171    for (i = 0; i < attr_len; i++)
172       snprintf(PACKET->DISSECTOR.pass + i*2, 3, "%02X", pass[i]);
173 
174    PACKET->DISSECTOR.info = strdup(auth);
175 
176    /* display the message */
177    DISSECT_MSG("RADIUS : %s:%d -> USER: %s  PASS: %s AUTH: %s\n", ip_addr_ntoa(&PACKET->L3.dst, tmp),
178                                     ntohs(PACKET->L4.dst),
179                                     PACKET->DISSECTOR.user,
180                                     PACKET->DISSECTOR.pass,
181                                     PACKET->DISSECTOR.info);
182 
183 
184    return NULL;
185 }
186 
187 
188 /*
189  * find a radius attribute thru the list
190  */
radius_get_attribute(u_int8 attr,u_int8 * attr_len,u_char * begin,u_char * end)191 static u_char * radius_get_attribute(u_int8 attr, u_int8 *attr_len, u_char *begin, u_char *end)
192 {
193    /* sanity check */
194    if (begin == NULL || end == NULL)
195       return NULL;
196 
197    if (begin > end)
198       return NULL;
199 
200    DEBUG_MSG("radius_get_attribute: [%d]", attr);
201 
202    /* stop when the attribute list ends */
203    while (begin < end) {
204 
205       /* get the len of the attribute and subtract the header len */
206       *attr_len = *(begin + 1) - 2;
207 
208       /* we have found our attribute */
209       if (*begin == attr) {
210          /* return the pointer to the attribute value */
211          return begin + 2;
212       }
213 
214       /* move to the next attribute */
215       if (*(begin + 1) > 0)
216          begin += *(begin + 1);
217       else
218          return NULL;
219    }
220 
221    /* not found */
222    return NULL;
223 }
224 
225 /* EOF */
226 
227 // vim:ts=3:expandtab
228 
229