/* * ICMPv6 or ICMPv4 socket fuzzer. * * Copyright (c) 2006, Clément Lecigne */ #include #include #include #include #include #include #include #include #include #include #include //#include #include //#include //#include #define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) #define SIOCGETRPF (SIOCPROTOPRIVATE+2) /* functions */ unsigned int randaddr(void); void randsoopt(int); void randgoopt(int); void randioctl(int); void usage(char *); /* * boucle until we hit a valid socket option */ void randsoopt(int sock) { unsigned int optval; int optlen, optname, level, ret, on = rand() % 2; do { switch (rand() % 5) { case 0: level = IPPROTO_IPV6; break; case 1: level = SOL_SOCKET; break; case 2: level = IPPROTO_RAW; break; case 3: level = rand() & 0xFF; break; case 4: level = IPPROTO_IP; break; } if (rand() % 6) { optlen = rand(); optval = (unsigned int)randaddr(); } else { /* * In some cases, kernel excepts that * optlen == sizeof (int) and that's * the first bound checking. */ optlen = sizeof (int); on = rand(); optval = (unsigned int)&on; } if (rand() % 8) optname = rand() % 255; else optname = rand(); #if 0 /* * anti well know FreeBSD mbufs exhaustion. */ if (optname == 25 || optname == IPV6_IPSEC_POLICY || optname == IPV6_FW_ADD || optname == IPV6_FW_FLUSH || optname == IPV6_FW_DEL || optname == IPV6_FW_ZERO) continue; /*printf("level : %d - optname : %d - optlen : %d\n", level, optname, optlen);*/ #endif ret = setsockopt(sock, level, optname, (void *)optval, optlen); }while(ret == -1); return; } /* * ioctl ipv6 socket fuzzer. */ void randioctl(int sock) { unsigned long reqs[] = { SIOCGETSGCNT_IN6, SIOCGETMIFCNT_IN6, SIOCGETRPF}; /* GSCOPE6DEF, SIOCGLIFADDR, SIOCSIFPHYADDR_IN6, SIOCGIFNETMASK_IN6, SIOCAIFADDR_IN6, SIOCGIFDSTADDR_IN6, SIOCSIFALIFETIME_IN6, SIOCGIFADDR_IN6, SIOCGIFDSTADDR_IN6, SIOCGIFNETMASK_IN6, SIOCGIFAFLAG_IN6, SIOCGIFSTAT_IN6, SIOCGIFSTAT_ICMP6, SIOCGIFALIFETIME_IN6, SIOCSIFALIFETIME_IN6, SIOCAIFADDR_IN6, SIOCDIFADDR_IN6 }; */ unsigned int arg; int ret; unsigned long request; if (rand() % 8) request = reqs[rand() % (sizeof (reqs) / sizeof (reqs[0]))]; else request = rand() + rand(); if (rand() % 2) { arg = randaddr(); ret = ioctl(sock, request, (caddr_t)arg); } else { arg = rand(); ret = ioctl(sock, request, (int)arg); } } /* * return a random address */ unsigned int randaddr(void) { char *p = malloc(1); unsigned int heap = (unsigned int)p; free(p); switch (rand() % 4) { case 0: return (heap + (rand() & 0xFFF)); case 1: return ((unsigned int)&heap + (rand() & 0xFFF)); case 2: return (0xc0000000 + (rand() & 0xFFFF)); case 3: return (rand()); } return (0); } int main(int ac, char **av) { int32_t cc, s, occ, i, j, a, try, count, opts; u_int32_t seed, maxsize; u_int8_t ip6; char c, *buf; struct addrinfo *res, hints; struct sockaddr_in6 from; socklen_t fromlen; struct msghdr msg; struct cmsghdr *cmsg = NULL; struct iovec iov; /* default values */ seed = getpid(); count = 50; occ = 10000; maxsize = 4096; opts = 50; ip6 = 1; fromlen = sizeof(from); if (getuid()) { fprintf(stderr, " - you must be root.\n"); exit(EXIT_FAILURE); } while ((c = getopt(ac, av, "r:n:c:m:o:46")) != EOF) { switch (c) { case '6': ip6 = 1; break; case '4': ip6 = 0; break; case 'r': seed = atoi(optarg); break; case 'n': occ = atoi(optarg); break; case 'c': count = atoi(optarg); break; case 'm': maxsize = atoi(optarg); break; case 'o': opts = atoi(optarg); break; default: usage(av[0]); break; } } printf("seeding with %u\n", seed); srand(seed); buf = malloc(maxsize); if (buf == NULL) { printf("%s: out of memory.\n", av[0]); exit(EXIT_FAILURE); } memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_socktype = SOCK_RAW; if(ip6) { hints.ai_family = AF_INET6; hints.ai_protocol = IPPROTO_ICMPV6; getaddrinfo("::1", NULL, &hints, &res); } else { hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_ICMP; getaddrinfo("127.0.0.1", NULL, &hints, &res); } for (i = 0; i < occ; i++) { printf(".\n"); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //cc = bind(s, res->ai_addr, res->ai_addrlen); for (j = 0; j < opts; j++) { randsoopt(s); //randgoopt(s); randioctl(s); for (a = 0; a < 32; a++) buf[a] = rand() % 255; try = 0; do { switch(rand() % 3) { case 0: cc = sendto(s, buf, rand() % maxsize, 0, (struct sockaddr *)res->ai_addr, res->ai_addrlen); break; case 1: case 2: msg.msg_controllen = (rand() % 2) ? rand() & maxsize : 0; if (msg.msg_controllen) { if (msg.msg_controllen < sizeof (struct cmsghdr)) cmsg = (struct cmsghdr *)malloc(sizeof (struct cmsghdr)); else cmsg = (struct cmsghdr *)malloc(msg.msg_controllen); if (cmsg == NULL) goto nocmsghdr; msg.msg_control = cmsg; cmsg->cmsg_level = (rand() % 2) ? IPPROTO_IPV6 : rand(); cmsg->cmsg_type = (rand() % 2) ? rand() % 255 : rand(); cmsg->cmsg_len = (rand() % 2) ? msg.msg_controllen : rand(); } else { nocmsghdr: msg.msg_control = (rand() % 5) ? NULL : (void*)randaddr(); msg.msg_controllen = (rand() % 2) ? rand() : 0; } iov.iov_len = (rand() % 2) ? rand() : rand() & maxsize; iov.iov_base = (rand() % 2) ? (void*)randaddr() : &buf; msg.msg_iov = (rand() % 2) ? (void*)randaddr() : &iov; if (rand() % 5) { msg.msg_name = res->ai_addr; msg.msg_namelen = res->ai_addrlen; } else { msg.msg_name = (caddr_t)randaddr(); msg.msg_namelen = rand(); } msg.msg_flags = rand(); cc = sendmsg (s, &msg, rand()); } if (cmsg != NULL) { // free(cmsg); // cmsg = NULL; } try++; } while(cc == -1 && try != count); recvmsg(s, &msg, MSG_DONTWAIT); } close(s); } free(buf); freeaddrinfo(res); exit(EXIT_SUCCESS); } /* * usage */ void usage(char *prog) { printf("usage: %s [-4] [-6] [-r seed] [-c sendto-timeout]\n" " [-m maxsize] [-o maxsetsockopt] [-n occ]\n", prog); exit(EXIT_FAILURE); }