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