00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 #include <sys/types.h>
00068 #include <stdlib.h>
00069 #include <string.h>
00070 #include <stdio.h>
00071 #if !defined(WIN32)
00072 #include <sys/time.h>
00073 #include <sys/socket.h>
00074 #include <netinet/in.h>
00075 #include <arpa/inet.h>
00076 #elif defined(WIN32)
00077 #include <time.h>
00078 #endif
00079
00080 #include "generators.h"
00081 #include "log.h"
00082 #include "detect.h"
00083 #include "decode.h"
00084 #include "event.h"
00085 #include "plugbase.h"
00086 #include "parser.h"
00087 #include "mstring.h"
00088 #include "debug.h"
00089 #include "util.h"
00090 #include "event_queue.h"
00091
00092
00093
00094 #define MODNAME "spp_arpspoof"
00095 #define WITHUNICAST "-unicast"
00096
00097
00098
00099 typedef struct _IPMacEntry
00100 {
00101 u_int32_t ipv4_addr;
00102 u_int8_t mac_addr[6];
00103 u_int8_t pad[2];
00104 } IPMacEntry;
00105
00106 typedef struct _IPMacEntryListNode
00107 {
00108 IPMacEntry *ip_mac_entry;
00109 struct _IPMacEntryListNode *next;
00110 } IPMacEntryListNode;
00111
00112 typedef struct _IPMacEntryList
00113 {
00114 int size;
00115 IPMacEntryListNode *head;
00116 IPMacEntryListNode *tail;
00117 } IPMacEntryList;
00118
00119
00120
00121 int check_unicast_arp, check_overwrite;
00122 u_int8_t bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
00123 static IPMacEntryList *ipmel = NULL;
00124
00125
00126
00127 void ARPspoofInit(u_char *args);
00128 void ARPspoofHostInit(u_char *args);
00129 void ParseARPspoofArgs(char *args);
00130 void ParseARPspoofHostArgs(char *args);
00131 void DetectARPattacks(Packet *p, void *context);
00132 void ARPspoofCleanExit(int signal, void *unused);
00133 void FreeIPMacEntryList(IPMacEntryList *ip_mac_entry_list);
00134 int AddIPMacEntryToList(IPMacEntryList *ip_mac_entry_list,
00135 IPMacEntry *ip_mac_entry);
00136 IPMacEntry *LookupIPMacEntryByIP(IPMacEntryList *ip_mac_entry_list,
00137 u_int32_t ipv4_addr);
00138 #if defined(DEBUG)
00139 void PrintIPMacEntryList(IPMacEntryList *ip_mac_entry_list);
00140 #endif
00141
00142
00143 void SetupARPspoof(void)
00144 {
00145 RegisterPreprocessor("arpspoof", ARPspoofInit);
00146 RegisterPreprocessor("arpspoof_detect_host", ARPspoofHostInit);
00147
00148 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
00149 "Preprocessor: ARPspoof is setup...\n"););
00150
00151 return;
00152 }
00153
00154
00155 void ARPspoofInit(u_char *args)
00156 {
00157 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
00158 "Preprocessor: ARPspoof Initialized\n"););
00159
00160
00161 ParseARPspoofArgs(args);
00162
00163
00164 AddFuncToPreprocList(DetectARPattacks);
00165
00166
00167 AddFuncToCleanExitList(ARPspoofCleanExit, NULL);
00168 AddFuncToRestartList(ARPspoofCleanExit, NULL);
00169
00170 return;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 void ParseARPspoofArgs(char *args)
00182 {
00183 char **toks;
00184 int num_toks;
00185 int num;
00186
00187 if (!args)
00188 return;
00189
00190 toks = mSplit(args, " ", 2, &num_toks, '\\');
00191
00192 if (num_toks > 1)
00193 {
00194 FatalError(MODNAME ": ERROR: %s (%d) => ARPspoof configuration "
00195 "format: -unicast\n", file_name, file_line);
00196 }
00197
00198 for (num = 0; num < num_toks; num++)
00199 {
00200 if (!strncasecmp(WITHUNICAST, toks[num], sizeof WITHUNICAST))
00201 check_unicast_arp = 1;
00202 }
00203
00204 mSplitFree(&toks, num_toks);
00205 }
00206
00207
00208 void ARPspoofHostInit(u_char *args)
00209 {
00210 DEBUG_WRAP(DebugMessage(DEBUG_INIT,
00211 "Preprocessor: ARPspoof (overwrite list) Initialized\n"););
00212
00213 if (ipmel == NULL)
00214 ipmel = (IPMacEntryList *)SnortAlloc(sizeof(IPMacEntryList));
00215
00216
00217 ParseARPspoofHostArgs(args);
00218
00219 if (check_overwrite == 0)
00220 check_overwrite = 1;
00221
00222 return;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 void ParseARPspoofHostArgs(char *args)
00234 {
00235 char **toks;
00236 char **macbytes;
00237 int num_toks, num_macbytes;
00238 int i;
00239 struct in_addr IP_struct;
00240 IPMacEntry *ipme = NULL;
00241
00242 if (ipmel == NULL)
00243 {
00244 FatalError("%s(%d) => Please activate arpspoof before trying to "
00245 "use arpspoof_detect_host\n", file_name, file_line);
00246 }
00247
00248 toks = mSplit(args, " ", 2, &num_toks, '\\');
00249
00250 if (num_toks != 2)
00251 {
00252 FatalError("Arpspoof %s(%d) => Invalid arguments to "
00253 "arpspoof_detect_host\n", file_name, file_line);
00254 }
00255
00256
00257 ipme = (IPMacEntry *)SnortAlloc(sizeof(IPMacEntry));
00258
00259 if ((IP_struct.s_addr = inet_addr(toks[0])) == -1)
00260 {
00261 FatalError("Arpspoof %s(%d) => Invalid IP address as first argument of "
00262 "IP/MAC pair to arpspoof_detect_host\n", file_name, file_line);
00263 }
00264
00265 ipme->ipv4_addr = (u_int32_t)IP_struct.s_addr;
00266
00267 macbytes = mSplit(toks[1], ":", 6, &num_macbytes, '\\');
00268
00269 if (num_macbytes < 6)
00270 {
00271 FatalError("Arpspoof %s(%d) => Invalid MAC address as second "
00272 "argument of IP/MAC pair to arpspoof_detect_host\n",
00273 file_name, file_line);
00274 }
00275 else
00276 {
00277 for (i = 0; i < 6; i++)
00278 ipme->mac_addr[i] = (u_int8_t) strtoul(macbytes[i], NULL, 16);
00279 }
00280
00281 AddIPMacEntryToList(ipmel, ipme);
00282
00283 mSplitFree(&toks, num_toks);
00284 mSplitFree(&macbytes, num_macbytes);
00285
00286 #if defined(DEBUG)
00287 PrintIPMacEntryList(ipmel);
00288 #endif
00289
00290 return;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 void DetectARPattacks(Packet *p, void *context)
00303 {
00304 IPMacEntry *ipme;
00305
00306
00307 if (p == NULL)
00308 return;
00309
00310
00311 if(!(p->preprocessors & PP_ARPSPOOF))
00312 return;
00313
00314
00315 if (p->eh == NULL || p->ah == NULL)
00316 return;
00317
00318
00319 if ((ntohs(p->ah->ea_hdr.ar_hrd) != 0x0001) ||
00320 (ntohs(p->ah->ea_hdr.ar_pro) != ETHERNET_TYPE_IP))
00321 return;
00322
00323 switch(ntohs(p->ah->ea_hdr.ar_op))
00324 {
00325 case ARPOP_REQUEST:
00326 if (check_unicast_arp)
00327 {
00328 if (memcmp((u_char *)p->eh->ether_dst, (u_char *)bcast, 6) != 0)
00329 {
00330 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
00331 ARPSPOOF_UNICAST_ARP_REQUEST, 1, 0, 3,
00332 ARPSPOOF_UNICAST_ARP_REQUEST_STR, 0);
00333
00334 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00335 "MODNAME: Unicast request\n"););
00336 }
00337 }
00338 else if (memcmp((u_char *)p->eh->ether_src,
00339 (u_char *)p->ah->arp_sha, 6) != 0)
00340 {
00341 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
00342 ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC, 1, 0, 3,
00343 ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 0);
00344
00345 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00346 "MODNAME: Ethernet/ARP mismatch request\n"););
00347 }
00348 break;
00349 case ARPOP_REPLY:
00350 if (memcmp((u_char *)p->eh->ether_src,
00351 (u_char *)p->ah->arp_sha, 6) != 0)
00352 {
00353 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
00354 ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC, 1, 0, 3,
00355 ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 0);
00356
00357 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00358 "MODNAME: Ethernet/ARP mismatch reply src\n"););
00359 }
00360 else if (memcmp((u_char *)p->eh->ether_dst,
00361 (u_char *)p->ah->arp_tha, 6) != 0)
00362 {
00363 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
00364 ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST, 1, 0, 3,
00365 ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST_STR, 0);
00366
00367 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00368 "MODNAME: Ethernet/ARP mismatch reply dst\n"););
00369 }
00370 break;
00371 }
00372
00373
00374 if (!check_overwrite)
00375 return;
00376
00377
00378 if ((ipme = LookupIPMacEntryByIP(ipmel,
00379 *(u_int32_t *)&p->ah->arp_spa)) == NULL)
00380 {
00381 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00382 "MODNAME: LookupIPMacEntryByIp returned NULL\n"););
00383 return;
00384 }
00385 else
00386 {
00387 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00388 "MODNAME: LookupIPMacEntryByIP returned %p\n", ipme););
00389
00390
00391
00392
00393 if ((memcmp((u_int8_t *)p->eh->ether_src,
00394 (u_int8_t *)ipme->mac_addr, 6)) ||
00395 (memcmp((u_int8_t *)p->ah->arp_sha,
00396 (u_int8_t *)ipme->mac_addr, 6)))
00397 {
00398 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
00399 ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK, 1, 0, 3,
00400 ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK_STR, 0);
00401
00402 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00403 "MODNAME: Attempted ARP cache overwrite attack\n"););
00404
00405 return;
00406 }
00407 }
00408 }
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 int AddIPMacEntryToList(IPMacEntryList *ip_mac_entry_list,
00420 IPMacEntry *ip_mac_entry)
00421 {
00422 IPMacEntryListNode *newNode;
00423
00424 if (ip_mac_entry == NULL || ip_mac_entry_list == NULL)
00425 return 1;
00426
00427 newNode = (IPMacEntryListNode *)malloc(sizeof(IPMacEntryListNode));
00428
00429 newNode->ip_mac_entry = ip_mac_entry;
00430 newNode->next = NULL;
00431
00432 if (ip_mac_entry_list->head == NULL)
00433 {
00434 ip_mac_entry_list->head = newNode;
00435 ip_mac_entry_list->size = 1;
00436 }
00437 else
00438 {
00439 ip_mac_entry_list->tail->next = newNode;
00440 ip_mac_entry_list->size += 1;
00441 }
00442 ip_mac_entry_list->tail = newNode;
00443 return 0;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 IPMacEntry *LookupIPMacEntryByIP(IPMacEntryList *ip_mac_entry_list,
00456 u_int32_t ipv4_addr)
00457 {
00458 IPMacEntryListNode *current;
00459 #if defined(DEBUG)
00460 struct in_addr ina, inb;
00461 char *cha, *chb;
00462 #endif
00463
00464 if (ip_mac_entry_list == NULL)
00465 return NULL;
00466
00467 for (current = ip_mac_entry_list->head; current != NULL;
00468 current = current->next)
00469 {
00470 #if defined(DEBUG)
00471 ina.s_addr = ipv4_addr;
00472 inb.s_addr = current->ip_mac_entry->ipv4_addr;
00473 cha = strdup(inet_ntoa(ina));
00474 chb = strdup(inet_ntoa(inb));
00475
00476 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00477 "MODNAME: LookupIPMacEntryByIP() comparing %s to %s\n", cha, chb););
00478 #endif
00479 if (current->ip_mac_entry->ipv4_addr == ipv4_addr)
00480 {
00481 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00482 "MODNAME: LookupIPMecEntryByIP() match!"););
00483
00484 return current->ip_mac_entry;
00485 }
00486 }
00487 return NULL;
00488 }
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 void FreeIPMacEntryList(IPMacEntryList *ip_mac_entry_list)
00499 {
00500 IPMacEntryListNode *prev;
00501 IPMacEntryListNode *current;
00502
00503 if (ip_mac_entry_list == NULL)
00504 return;
00505
00506 current = ip_mac_entry_list->head;
00507 while (current != NULL)
00508 {
00509 if (current->ip_mac_entry != NULL)
00510 free(current->ip_mac_entry);
00511
00512 prev = current;
00513 current = current->next;
00514 free(prev);
00515 }
00516 ip_mac_entry_list->head = NULL;
00517 ip_mac_entry_list->size = 0;
00518
00519 return;
00520 }
00521
00522
00523 void ARPspoofCleanExit(int signal, void *unused)
00524 {
00525 if (ipmel != NULL)
00526 {
00527 FreeIPMacEntryList(ipmel);
00528 free(ipmel);
00529 ipmel = NULL;
00530 }
00531 check_unicast_arp = check_overwrite = 0;
00532 return;
00533 }
00534
00535
00536 #if defined(DEBUG)
00537
00538
00539
00540
00541
00542
00543
00544 void PrintIPMacEntryList(IPMacEntryList *ip_mac_entry_list)
00545 {
00546 IPMacEntryListNode *current;
00547 int i;
00548 struct in_addr in;
00549 if (ip_mac_entry_list == NULL)
00550 return;
00551
00552 current = ip_mac_entry_list->head;
00553 printf("Arpspoof IPMacEntry List");
00554 printf(" Size: %i\n", ip_mac_entry_list->size);
00555 while (current != NULL)
00556 {
00557 in.s_addr = current->ip_mac_entry->ipv4_addr;
00558 printf("%s -> ", inet_ntoa(in));
00559 for (i = 0; i < 6; i++)
00560 {
00561 printf("%02x", current->ip_mac_entry->mac_addr[i]);
00562 if (i != 5)
00563 printf(":");
00564 }
00565 printf("\n");
00566 current = current->next;
00567 }
00568 return;
00569 }
00570 #endif