29 #include <arpa/inet.h>
37 #ifdef HAVE_LIBPACKETDUMP
38 #include "libpacketdump.h"
50 #include "corsaro_dos.h"
61 #define CORSARO_DOS_MAGIC 0x45444F53
64 #define PLUGIN_NAME "dos"
72 #define PLUGIN_NAME_DEPRECATED "edgar_dos"
94 #define CORSARO_DOS_INTERVAL 300
97 #define CORSARO_DOS_VECTOR_TIMEOUT CORSARO_DOS_INTERVAL
100 #define CORSARO_DOS_ATTACK_VECTOR_MIN_PACKETS 25
103 #define CORSARO_DOS_ATTACK_VECTOR_MIN_DURATION 60
106 #define CORSARO_DOS_ATTACK_VECTOR_MIN_PPM 30
109 #define CORSARO_DOS_ATTACK_VECTOR_BYTECNT (4+4+4+4+4+8+4+8+4+8+4+4+4+4+4)
112 #define CORSARO_DOS_PPM_WINDOW_SIZE 60
115 #define CORSARO_DOS_PPM_WINDOW_PRECISION 10
118 #define CORSARO_DOS_PPS_BUCKET_CNT (CORSARO_DOS_PPM_WINDOW_SIZE/ \
119 CORSARO_DOS_PPM_WINDOW_PRECISION)
127 KHASH_SET_INIT_INT(32xx)
130 typedef struct ppm_window
133 uint32_t window_start;
137 uint8_t current_bucket;
146 typedef struct attack_vector
152 uint8_t *initial_packet;
155 uint32_t initial_packet_len;
158 uint32_t attacker_ip;
161 uint32_t responder_ip;
170 uint32_t interval_packet_cnt;
176 uint32_t interval_byte_cnt;
182 struct timeval start_time;
185 struct timeval latest_time;
188 kh_32xx_t *attack_ip_hash;
191 kh_32xx_t *attack_port_hash;
194 kh_32xx_t *target_port_hash;
197 uint32_t attack_ip_cnt;
214 corsaro_log(__func__, corsaro,
"could not malloc memory for attack vector");
218 av->attack_ip_hash = kh_init(32xx);
219 assert(av->attack_ip_hash != NULL);
221 av->attack_port_hash = kh_init(32xx);
222 assert(av->attack_port_hash != NULL);
224 av->target_port_hash = kh_init(32xx);
225 assert(av->target_port_hash != NULL);
241 if(av->initial_packet != NULL)
244 free(av->initial_packet);
247 if(av->attack_ip_hash != NULL)
249 kh_destroy(32xx, av->attack_ip_hash);
251 if(av->attack_port_hash != NULL)
253 kh_destroy(32xx, av->attack_port_hash);
255 if(av->target_port_hash != NULL)
257 kh_destroy(32xx, av->target_port_hash);
272 av->interval_packet_cnt = 0;
273 av->interval_byte_cnt = 0;
274 av->attack_ip_cnt = kh_size(av->attack_ip_hash);
278 #define attack_vector_hash_equal(a, b) ( \
279 (a)->target_ip == (b)->target_ip \
288 return (khint32_t)av->target_ip*59;
296 struct corsaro_dos_state_t {
298 uint32_t first_interval;
301 uint16_t number_mismatched_packets;
303 khash_t(av) *attack_hash;
309 struct corsaro_dos_in_state_t {
319 #define STATE(corsaro) \
320 (CORSARO_PLUGIN_STATE(corsaro, dos,CORSARO_PLUGIN_ID_DOS))
322 #define STATE_IN(corsaro) \
323 (CORSARO_PLUGIN_STATE(corsaro, dos_in, \
324 CORSARO_PLUGIN_ID_DOS))
326 #define PLUGIN(corsaro) \
327 (CORSARO_PLUGIN_PLUGIN(corsaro, CORSARO_PLUGIN_ID_DOS))
356 this_ppm += ppm_window->buckets[i];
358 if(this_ppm > ppm_window->max_ppm)
360 ppm_window->max_ppm = this_ppm;
448 bucket_offset = (tv.tv_sec-ppm_window->window_start)/
452 if(bucket_offset > 0)
457 for(i = 0; i < bucket_offset && i < 6; i++)
459 ppm_window->current_bucket =
461 ppm_window->buckets[ppm_window->current_bucket] = 0;
464 ppm_window->window_start += bucket_offset*
470 ppm_window->buckets[ppm_window->current_bucket]++;
486 struct timeval duration;
495 if(timeval_subtract(&duration, &vector->latest_time,
496 &vector->start_time) == 1)
498 corsaro_log(__func__, corsaro,
"last packet seen before first packet!");
508 ppm = vector->ppm_window.max_ppm;
530 tmp = htonl(vector->target_ip);
531 inet_ntop(AF_INET,&tmp, &t_ip[0], 16);
533 corsaro_file_printf(corsaro,
STATE(corsaro)->outfile,
544 ",%"PRIu32
".%06"PRIu32
545 ",%"PRIu32
".%06"PRIu32
548 kh_size(vector->attack_ip_hash),
549 kh_size(vector->attack_ip_hash)-vector->attack_ip_cnt,
550 kh_size(vector->attack_port_hash),
551 kh_size(vector->target_port_hash),
553 vector->interval_packet_cnt,
555 vector->interval_byte_cnt,
556 vector->ppm_window.max_ppm,
557 (uint32_t)vector->start_time.tv_sec,
558 (uint32_t)vector->start_time.tv_usec,
559 (uint32_t)vector->latest_time.tv_sec,
560 (uint32_t)vector->latest_time.tv_usec);
573 uint8_t *ptr = &av_bytes[0];
583 bytes_htonl(ptr, vector->target_ip);
586 bytes_htonl(ptr, kh_size(vector->attack_ip_hash));
589 bytes_htonl(ptr, kh_size(vector->attack_ip_hash)-vector->attack_ip_cnt);
592 bytes_htonl(ptr, kh_size(vector->attack_port_hash));
595 bytes_htonl(ptr, kh_size(vector->target_port_hash));
598 bytes_htonll(ptr, vector->packet_cnt);
601 bytes_htonl(ptr, vector->interval_packet_cnt);
604 bytes_htonll(ptr, vector->byte_cnt);
607 bytes_htonl(ptr, vector->interval_byte_cnt);
610 bytes_htonll(ptr, vector->ppm_window.max_ppm);
613 bytes_htonl(ptr, vector->start_time.tv_sec);
616 bytes_htonl(ptr, vector->start_time.tv_usec);
619 bytes_htonl(ptr, vector->latest_time.tv_sec);
622 bytes_htonl(ptr, vector->latest_time.tv_usec);
637 bytes_htonl(ptr, vector->initial_packet_len);
639 if(corsaro_file_write(corsaro,
STATE(corsaro)->outfile, &av_bytes[0],
643 corsaro_log(__func__, corsaro,
"could not dump vector byte array to file");
647 if(corsaro_file_write(corsaro,
STATE(corsaro)->outfile, vector->initial_packet,
648 vector->initial_packet_len) !=
649 vector->initial_packet_len)
651 corsaro_log(__func__, corsaro,
"could not dump packet to file");
665 corsaro_io_read_bytes(corsaro, record,
669 corsaro_log_in(__func__, corsaro,
"failed to read dos header from file");
681 record->
buffer)->attack_vector_cnt;
693 if(av->initial_packet_len == 0)
713 av->initial_packet_len = ntohl(av->initial_packet_len);
736 if((bytes_read = corsaro_io_read_bytes(corsaro, record, bsbread)) != bsbread)
738 corsaro_log_in(__func__, corsaro,
739 "failed to read dos attack vector from file");
746 if(validate_attack_vector(av) != 1)
748 corsaro_log_in(__func__, corsaro,
"could not validate attack vector");
755 corsaro_io_read_bytes_offset(corsaro, record,
757 av->initial_packet_len))
758 != (bsbread += av->initial_packet_len))
760 corsaro_log_in(__func__, corsaro,
761 "failed to read initial packet from file");
774 STATE_IN(corsaro)->vector_total = 0;
779 +av->initial_packet_len);
800 int corsaro_dos_probe_filename(
const char *fname)
803 if(corsaro_plugin_probe_filename(fname, &corsaro_dos_plugin) == 0)
833 struct corsaro_dos_state_t *state;
836 assert(plugin != NULL);
842 if((state = malloc_zero(
sizeof(
struct corsaro_dos_state_t))) == NULL)
844 corsaro_log(__func__, corsaro,
845 "could not malloc corsaro_dos_state_t");
852 corsaro_plugin_register_state(corsaro->
plugin_manager, plugin, state);
855 if((state->outfile = corsaro_io_prepare_file(corsaro, plugin->
name)) == NULL)
857 corsaro_log(__func__, corsaro,
"could not open %s output file",
863 state->attack_hash = kh_init(av);
868 corsaro_dos_close_output(corsaro);
874 struct corsaro_dos_in_state_t *state;
876 assert(plugin != NULL);
878 if((state = malloc_zero(
sizeof(
struct corsaro_dos_in_state_t)))
881 corsaro_log_in(__func__, corsaro,
882 "could not malloc corsaro_dos_state_t");
885 corsaro_plugin_register_state(corsaro->
plugin_manager, plugin, state);
895 corsaro_dos_close_input(corsaro);
901 struct corsaro_dos_in_state_t *state =
STATE_IN(corsaro);
910 int corsaro_dos_close_output(
corsaro_t *corsaro)
912 struct corsaro_dos_state_t *state =
STATE(corsaro);
916 if(state->attack_hash != NULL)
919 kh_destroy(av, state->attack_hash);
920 state->attack_hash = NULL;
923 if(state->outfile != NULL)
925 corsaro_file_close(corsaro, state->outfile);
926 state->outfile = NULL;
933 off_t corsaro_dos_read_record(
struct corsaro_in *corsaro,
937 struct corsaro_dos_in_state_t *state =
STATE_IN(corsaro);
939 off_t bytes_read = -1;
943 switch(state->expected_type)
947 bytes_read = corsaro_io_read_interval_start(corsaro, corsaro->
file,
948 record_type, record);
957 bytes_read = read_header(corsaro, record_type, record);
962 bytes_read = read_attack_vector(corsaro, record_type, record);
967 bytes_read = corsaro_io_read_interval_end(corsaro, corsaro->
file,
968 record_type, record);
976 corsaro_log_in(__func__, corsaro,
"invalid expected record type");
982 off_t corsaro_dos_read_global_data_record(
struct corsaro_in *corsaro,
988 if((bytes_read = corsaro_io_read_bytes(corsaro, record,
999 corsaro_log_in(__func__, corsaro,
"could not validate global header");
1013 if(
STATE(corsaro)->first_interval == 0)
1016 STATE(corsaro)->first_interval = int_start->
time-1;
1024 int this_interval = int_end->
time-
STATE(corsaro)->first_interval;
1029 int attack_arr_cnt = 0;
1043 STATE(corsaro)->first_interval = int_end->
time;
1053 kh_size(
STATE(corsaro)->attack_hash))) == NULL)
1055 corsaro_log(__func__, corsaro,
"could not malloc array for attack vectors");
1061 for(i = kh_begin(
STATE(corsaro)->attack_hash);
1062 i != kh_end(
STATE(corsaro)->attack_hash); ++i)
1064 if(kh_exist(
STATE(corsaro)->attack_hash, i))
1066 vector = kh_key(
STATE(corsaro)->attack_hash, i);
1070 kh_del(av,
STATE(corsaro)->attack_hash, i);
1079 attack_arr[attack_arr_cnt] = vector;
1089 corsaro_io_write_interval_start(corsaro,
STATE(corsaro)->outfile,
1096 corsaro_file_printf(corsaro, corsaro->
global_file,
1097 "mismatch: %"PRIu32
"\n"
1098 "attack_vectors: %"PRIu32
"\n"
1099 "non-attack_vectors: %"PRIu32
"\n",
1100 STATE(corsaro)->number_mismatched_packets,
1102 kh_size(
STATE(corsaro)->attack_hash)-attack_arr_cnt);
1105 corsaro_file_printf(corsaro,
STATE(corsaro)->outfile,
"%"PRIu32
"\n",
1108 for(i = 0; i < attack_arr_cnt; i++)
1112 corsaro_log(__func__, corsaro,
"could not dump hash");
1122 bytes_htonl(&gbuf[0],
STATE(corsaro)->number_mismatched_packets);
1123 bytes_htonl(&gbuf[4], attack_arr_cnt);
1124 bytes_htonl(&gbuf[8],
1125 kh_size(
STATE(corsaro)->attack_hash)-attack_arr_cnt);
1126 if(corsaro_file_write(corsaro, corsaro->
global_file,
1127 &gbuf[0], 12) != 12)
1129 corsaro_log(__func__, corsaro,
1130 "could not dump global stats to file");
1135 bytes_htonl(&cntbuf[0], attack_arr_cnt);
1136 if(corsaro_file_write(corsaro,
STATE(corsaro)->outfile,
1137 &cntbuf[0], 4) != 4)
1139 corsaro_log(__func__, corsaro,
1140 "could not dump vector count to file");
1144 for(i = 0; i < attack_arr_cnt; i++)
1148 corsaro_log(__func__, corsaro,
"could not dump hash");
1156 corsaro_log(__func__, corsaro,
"invalid mode");
1160 corsaro_io_write_interval_end(corsaro,
STATE(corsaro)->outfile, int_end);
1162 STATE(corsaro)->number_mismatched_packets = 0;
1172 libtrace_packet_t *ltpacket =
LT_PKT(packet);
1178 libtrace_ip_t *ip_hdr = NULL;
1179 libtrace_icmp_t *icmp_hdr = NULL;
1180 libtrace_ip_t *inner_ip_hdr = NULL;
1188 uint16_t attacker_port = 0;
1189 uint16_t target_port = 0;
1196 uint8_t *pkt_buf = NULL;
1197 libtrace_linktype_t linktype;
1201 if((packet->
state.
flags & CORSARO_PACKET_STATE_FLAG_BACKSCATTER) == 0)
1209 if((temp = trace_get_layer3(ltpacket, ðertype, &remaining)) != NULL &&
1210 ethertype == TRACE_ETHERTYPE_IP)
1212 ip_hdr = (libtrace_ip_t *)temp;
1217 corsaro_log(__func__, corsaro,
"non-ip packet found (ethertype: %x)",
1223 if((temp = trace_get_transport(ltpacket, &proto, &remaining)) == NULL)
1229 findme.target_ip = 0;
1231 if(ip_hdr->ip_p == TRACE_IPPROTO_ICMP && remaining >= 2)
1233 icmp_hdr = (libtrace_icmp_t *)temp;
1235 if((icmp_hdr->type == 3 ||
1236 icmp_hdr->type == 4 ||
1237 icmp_hdr->type == 5 ||
1238 icmp_hdr->type == 11 ||
1239 icmp_hdr->type == 12) &&
1240 ((temp = trace_get_payload_from_icmp(icmp_hdr, &remaining)) != NULL
1241 && remaining >= 20 && (inner_ip_hdr = (libtrace_ip_t *)temp) &&
1242 inner_ip_hdr->ip_v == 4))
1245 if(inner_ip_hdr->ip_src.s_addr != ip_hdr->ip_dst.s_addr)
1247 STATE(corsaro)->number_mismatched_packets++;
1250 findme.target_ip = ntohl(inner_ip_hdr->ip_dst.s_addr);
1253 if((temp = trace_get_payload_from_ip(inner_ip_hdr, NULL,
1254 &remaining)) != NULL
1257 attacker_port = ntohs(((
struct ports_t *)temp)->src);
1258 target_port = ntohs(((
struct ports_t *)temp)->dst);
1263 findme.target_ip = ntohl(ip_hdr->ip_src.s_addr);
1264 attacker_port = ntohs(icmp_hdr->code);
1265 target_port = ntohs(icmp_hdr->type);
1268 else if((ip_hdr->ip_p == TRACE_IPPROTO_TCP ||
1269 ip_hdr->ip_p == TRACE_IPPROTO_UDP) &&
1272 findme.target_ip = ntohl(ip_hdr->ip_src.s_addr);
1273 attacker_port = trace_get_destination_port(ltpacket);
1274 target_port = trace_get_source_port(ltpacket);
1277 if(findme.target_ip == 0)
1283 tv = trace_get_timeval(ltpacket);
1286 assert(
STATE(corsaro)->attack_hash != NULL);
1287 if((khiter = kh_get(av,
STATE(corsaro)->attack_hash, &findme))
1288 != kh_end(
STATE(corsaro)->attack_hash))
1291 vector = kh_key(
STATE(corsaro)->attack_hash, khiter);
1295 kh_del(av,
STATE(corsaro)->attack_hash, khiter);
1306 corsaro_log(__func__, corsaro,
"failed to create new attack vector");
1313 vector->initial_packet_len = trace_get_capture_length(ltpacket);
1315 if((vector->initial_packet = malloc(vector->initial_packet_len)) == NULL)
1317 corsaro_log(__func__, corsaro,
"could not malloc initial packet");
1321 if((pkt_buf = trace_get_packet_buffer(ltpacket,
1322 &linktype, NULL)) == NULL)
1324 corsaro_log(__func__, corsaro,
"could not get packet buffer");
1328 memcpy(vector->initial_packet, pkt_buf, vector->initial_packet_len);
1330 vector->attacker_ip = ntohl(ip_hdr->ip_dst.s_addr);
1331 vector->responder_ip = ntohl(ip_hdr->ip_src.s_addr);
1332 vector->target_ip = findme.target_ip;
1334 vector->start_time = tv;
1336 vector->ppm_window.window_start = tv.tv_sec;
1339 khiter = kh_put(av,
STATE(corsaro)->attack_hash, vector, &khret);
1342 assert(vector != NULL);
1344 vector->packet_cnt++;
1345 vector->interval_packet_cnt++;
1346 vector->byte_cnt += ntohs(ip_hdr->ip_len);
1347 vector->interval_byte_cnt += ntohs(ip_hdr->ip_len);
1349 vector->latest_time = tv;
1354 kh_put(32xx, vector->attack_ip_hash, ntohl(ip_hdr->ip_dst.s_addr), &khret);
1357 kh_put(32xx, vector->attack_port_hash, attacker_port, &khret);
1358 kh_put(32xx, vector->target_port_hash, target_port, &khret);
1365 void corsaro_dos_attack_vector_get_packet(
1367 libtrace_packet_t *packet)
1369 assert(packet != NULL);
1371 trace_construct_packet(packet, TRACE_TYPE_ETH,
1373 attack_vector->initial_packet_len);
1380 assert(corsaro != NULL);
1381 assert(file != NULL);
1382 assert(header != NULL);
1384 return corsaro_file_printf(corsaro, file,
1385 "mismatch: %"PRIu32
"\n"
1386 "attack_vectors: %"PRIu32
"\n"
1387 "non-attack_vectors: %"PRIu32
"\n",
1396 assert(header != NULL);
1398 fprintf(stdout,
"mismatch: %"PRIu32
"\n"
1399 "attack_vectors: %"PRIu32
"\n"
1400 "non-attack_vectors: %"PRIu32
"\n",
1416 assert(corsaro != NULL);
1417 assert(file != NULL);
1421 inet_ntop(AF_INET,&tmp, &t_ip[0], 16);
1423 return corsaro_file_printf(corsaro, file,
1434 ",%"PRIu32
".%06"PRIu32
1435 ",%"PRIu32
".%06"PRIu32
1458 libtrace_packet_t *packet;
1463 inet_ntop(AF_INET,&tmp, &t_ip[0], 16);
1476 ",%"PRIu32
".%06"PRIu32
1477 ",%"PRIu32
".%06"PRIu32
1495 if ((packet = trace_create_packet()) == NULL) {
1496 corsaro_log_file(__func__, NULL,
"error creating libtrace packet");
1500 corsaro_dos_attack_vector_get_packet(av, packet);
1502 #if HAVE_LIBPACKETDUMP
1503 fprintf(stdout,
"START PACKET\n");
1504 trace_dump_packet(packet);
1505 fprintf(stdout,
"\nEND PACKET\n");
1507 fprintf(stdout,
"corsaro not built with libpacketdump support\n"
1508 "not dumping initial packet\n");
1516 assert(corsaro != NULL);
1517 assert(file != NULL);
1518 assert(header != NULL);
1520 return corsaro_file_printf(corsaro, file,
1528 assert(header != NULL);
1557 corsaro_log(__func__, corsaro,
"record_type %d not a dos record",
1587 corsaro_log_file(__func__, NULL,
1588 "record_type %d not a dos record",