MAGIC Enterprise Multiple Vulnerabilities

From: Stephan Holtwisch (shat_private)
Date: Mon Dec 17 2001 - 13:48:03 PST

  • Next message: Tabor J. Wells: "[ph10at_private: [Exim] Potential security problem]"

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1
    
                            
    immutec Security Advisory
                                   
    ID:       SA-MAGIC-001
    Date:     2001/12/17
    Version:  0.2
    
    Magic Enterprise multiple vulnerabilities
    
    
    
    Affected Software/System:
    =========================
    
      Vendor    : Magic Software (http://www.magicsoftware.com)
      Product   : Magic Enterprise Edition
      Version   : 8.30-5 and prior, 9.x not fully tested
      Platform  : Solaris, Linux, AIX, HP/UX, SCO, Digital Unix, AS/400, NT
    
    
    Vulnerability Types:
    ====================
    
      Memory Corruption       : remote/local
      Shell Command Execution : local
      Temporary File Handling : local
      Insecure Permissions    : local (filesystem)
    
    
    Product Description:
    ====================
    
      The Magic Enterprise Edition Version 8 is a multi-platform, flexible
      application which supports well known web browsers, web servers,
      application servers and databases. Magic v8 gives a developer the 
      ability to create portable and scalable client-/server-based or 
      web-based applications.
    
      Magic is used by important eCommerce sites, payment systems, banks, big
      automobile companies and even on government servers.
    
    
    Vulnerability Description:
    ==========================
    
      Serveral security holes were found in Magic Enterprise Edition Version 8
      (Solaris) while doing a penetration test for a customer.
      In depth analysis was performed for the Linux version. Version 9 was not
      fully tested, but at least some issues were also verified for Version 9.
    
      a.)  Memory Corruption: remote
    
      The CGI executable 'mgrqcgi' is used as a kind of gateway to handle 
      different tasks.
      
      mgrqcgi reads different variables from the QUERY_STRING environment
      variable, which is set by the HTTP server.
      The names of the variables:
    
        + APPNAME
        + PRGNAME
        + ARGUMENTS
        + PageID
        + mgaction
        + H_ShopID
        + H_SID
        + H_WID
        + H_INF
        + and much more
    
      The variable data is copied into local variables using the non-bound
      checking library function strcpy(3).
      This can be easily verified by triggering the overflow using a standart 
      web browser. Overwriting the memory for APPNAME bytewise results in 
      overwriting PRGNAME input until an internal server error occurs.
    
      Attached ltrace output (comments included in []):
    
        [...]
     
        17:00:03.769509 [08049794] getenv("REQUEST_METHOD") = "GET"
        17:00:03.769680 [080497ae] strcmp("GET", "POST")  = -9
        17:00:03.769817 [080497ce] strcmp("GET", "GET")   = 0
    
    
        [QUERY_STRING read and splitted up]
    
        17:00:03.769942 [08049915] getenv("QUERY_STRING") =
        "APPNAME=test&PRGNAME=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAA"
        17:00:03.770687 [08049b81] strchr("APPNAME=test&PRGNAME=AAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        ,'=') = "=test&PRGNAME=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAA"
        17:00:03.772443 [08049bb7] strchr("test&PRGNAME=AAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        '&') = "&PRGNAME=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAA"
        17:00:03.773713 [08049df3] malloc(8)              = 0x08077458
        17:00:03.773811 [08049d30] realloc(NULL, 8)       = 0x08077468
        17:00:03.773929 [08049df3] malloc(6)              = 0x08077478
    
    
        [variable name seperated from variable data]
    
        17:00:03.774025 [08049b81] strchr("PRGNAME=AAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        '=') = "=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AA"
        17:00:03.776353 [08049bb7] strchr("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        '&') = NULL
        17:00:03.777015 [08049bf0] strlen(0xbffffa2a, 0x080498f8, 0x40014ce4,
        0x08077458, 0x080613d8) = 200
        17:00:03.777157 [08049df3] malloc(8)              = 0x08077488
        17:00:03.777253 [08049d30] realloc(0x08077468, 16) = 0x08077498
        17:00:03.777974 [08049df3] malloc(202)            = 0x080774b0
        17:00:03.778077 [0804acdf] malloc(32)             = 0x08077580
        17:00:03.778191 [0804acf4] memset(0x08077580, '\000', 32) = 0x08077580
    
    
        [variable name made upper case]
    
        17:00:03.778302 [0804dcec] toupper('A')           = 'A'
        17:00:03.778413 [0804dcfd] toupper('C')           = 'C'
        17:00:03.778521 [0804dd1c] toupper('A')           = 'A'
        17:00:03.778785 [0804dd2d] toupper('C')           = 'C'
        17:00:03.778892 [0804dcec] toupper('A')           = 'A'
        17:00:03.778999 [0804dcfd] toupper('A')           = 'A'
        17:00:03.779107 [0804dcec] toupper('P')           = 'P'
        17:00:03.779213 [0804dcfd] toupper('P')           = 'P'
        17:00:03.779320 [0804dcec] toupper('P')           = 'P'
        17:00:03.779427 [0804dcfd] toupper('P')           = 'P'
        17:00:03.779534 [0804dcec] toupper('N')           = 'N'
        17:00:03.779641 [0804dcfd] toupper('N')           = 'N'
        17:00:03.779748 [0804dcec] toupper('A')           = 'A'
        17:00:03.779854 [0804dcfd] toupper('A')           = 'A'
        17:00:03.779962 [0804dcec] toupper('M')           = 'M'
        17:00:03.780068 [0804dcfd] toupper('M')           = 'M'
        17:00:03.780175 [0804dcec] toupper('E')           = 'E'
        17:00:03.780300 [0804dcfd] toupper('E')           = 'E'
        17:00:03.780408 [0804dd1c] toupper('\000')        = '\000'
        17:00:03.780517 [0804dd2d] toupper('\000')        = '\000'
    
    
        [APPNAME content copied into stack memory WITHOUT length checking]
    
        17:00:03.780626 [0804ae56] strcpy(0xbfffee68, "test") = 0xbfffee68
    
    
        [variable name to upper case]
    
        17:00:03.835647 [0804dcec] toupper('P')           = 'P'
        17:00:03.835828 [0804dcfd] toupper('C')           = 'C'
        17:00:03.835936 [0804dd1c] toupper('P')           = 'P'
        17:00:03.836043 [0804dd2d] toupper('C')           = 'C'
        17:00:03.836150 [0804dcec] toupper('P')           = 'P'
        17:00:03.836257 [0804dcfd] toupper('P')           = 'P'
        17:00:03.836364 [0804dcec] toupper('R')           = 'R'
        17:00:03.836471 [0804dcfd] toupper('R')           = 'R'
        17:00:03.836577 [0804dcec] toupper('G')           = 'G'
        17:00:03.836684 [0804dcfd] toupper('G')           = 'G'
        17:00:03.837645 [0804dcec] toupper('N')           = 'N'
        17:00:03.837766 [0804dcfd] toupper('N')           = 'N'
        17:00:03.837873 [0804dcec] toupper('A')           = 'A'
        17:00:03.837980 [0804dcfd] toupper('A')           = 'A'
        17:00:03.838103 [0804dcec] toupper('M')           = 'M'
        17:00:03.838210 [0804dcfd] toupper('M')           = 'M'
        17:00:03.838317 [0804dcec] toupper('E')           = 'E'
        17:00:03.838423 [0804dcfd] toupper('E')           = 'E'
        17:00:03.838530 [0804dd1c] toupper('\000')        = '\000'
        17:00:03.838639 [0804dd2d] toupper('\000')        = '\000'
    
    
        [PRGNAME content copied into stack memory WITHOUT length checking]
        [BUFFER OVERFLOW triggered here]
    
        17:00:03.838748 [0804ae70] strcpy(0xbfffee48,
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
        = 0xbfffee48
    
    
        [segmentation fault occuring]
    
        17:00:03.839409 [080497f5] getenv("HTTP_COOKIE")  = NULL
        17:00:03.839545 [08049ac0] getenv("REMOTE_ADDR")  = NULL
        17:00:03.839687 [0805aff4] memset(0x08076e68, '\000', 120) = 
        0x08076e68
        17:00:03.839801 [08053971] strcpy(0x08077334, "otaku") = 0x08077334
        17:00:03.839920 [0804cdb7] malloc(1508)           = 0x080775a8
        17:00:03.840018 [0804cad0] memcpy(0x080775b0, "\001\001", 1500) =
        0x080775b0
        17:00:03.840160 [08052f00] strlen(0xbfffedc8, 0x08049ab4, 0xbfffee00,
        0xbfffedc8, 0x080775b0) = 0
        17:00:03.840308 [08052f5b] strlen(0xbfffed48, 0x08049ab4, 0xbfffee00,
        0xbfffed48, 0x080775b0) = 0
        17:00:03.840440 [080519d5] memcpy(0x08076e60, "\001\001", 1500) =
        0x08076e60
        17:00:03.840577 [0804cef0] free(0x080775a8)       = <void>
        17:00:03.840672 [0804b52c] memset(0xbfffeef8, '\000', 16) = 0xbfffeef8
        17:00:03.840782 [0804b54c] malloc(200)            = 0x080775a8
        17:00:03.841364 [0804afe6] --- SIGSEGV (Segmentation fault) ---
        17:00:03.841890 [ffffffff] +++ killed by SIGSEGV +++
    
    
      The GNU Debugger output:
          
        [...]
    
        Starting program: /usr/local/httpd/cgi-bin/mgrqcgi
        (no debugging symbols found)...(no debugging symbols found)...(no
        debugging symbols found)...
        (no debugging symbols found)...
        Program received signal SIGSEGV, Segmentation fault.
        0x0804b103 in strcpy ()
        (gdb) info stack
        #0  0x0804b103 in strcpy ()
        #1  0x41414141 in ?? ()
        #2  0x0804a440 in strcpy ()
        #3  0x08049b18 in strcpy ()
        #4  0x41414141 in ?? ()
       
        [...]
    
      Some characters could not be used while overflowing the internal
      buffers, because they have other meanings in the CGI context or are 
      filtered.
      Characters that could not be used:
    
        + 0x00
        + 0x09
        + 0x0A
        + 0x0B
        + 0x0C
        + 0x0D
        + 0x20
        + 0x23
        + 0x25
        + 0x26
    
    
      b.) Memory Corruption: local
    
      The Linux RPM comes with one setuid root application:
    
        + /usr/magicadm/servers/mgdispatch
    
      There seem to be serveral buffer overflows in the code of mgdispatch.
      One example of missing bounds checking occurs very early in the program
      code while reading an environment variable called MGDISPATCH_LOG.
      The destination buffer is about 3000 bytes big, so an attacker has 
      enough space for stuffing the shellcode in and execute arbitrary 
      commands.
    
      ltrace output:
     
        [...]
    
        getenv("MGDISPATCH_LOG")                          =
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"...
        strcpy(0xbfffd87c, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"...) = 
        0xbfffd87c
        getenv("MG_DOS_CLIENTS" <unfinished ...>
        --- SIGSEGV (Segmentation fault) ---
        +++ killed by SIGSEGV +++
    
    
      The GNU Debugger output::
        
        [...]
          
        (gdb) r 78
        Starting program: ./mgdispatch 78
        (no debugging symbols found)...(no debugging symbols found)...
        (no debugging symbols found)...(no debugging symbols found)...
        Program received signal SIGSEGV, Segmentation fault.
        0x4008d63b in getenv () from /lib/libc.so.6
        (gdb) bt
        #0  0x4008d63b in getenv () from /lib/libc.so.6
        #1  0x0804dec8 in strcpy ()
        #2  0x41414141 in ?? ()
         
        [...]
    
    
      c.) Temporary File Handling
    
      Some shell script files included in the Linux RPM (probably applies
      to other versions as well) do insecure temporary file handling, 
      allowing symlink attacks, replacing information and execution 
      of commands.
    
      This list includes shell script names and the appropriate lines:
    
        + /usr/magicadm/api/mkuserproc:40:tmpfile=/tmp/mg.$$
        + /usr/magicadm/sbin/mgrnt:42:$AWK -F= '/^[^#]/ {if (NF > 0) print
                                      "export " $1}' $MAGIC_HOME/etc/mgenv >
                                      /tmp/mg$$
        + /usr/magicadm/sbin/mgrnt:43:. /tmp/mg$$
        + /usr/magicadm/sbin/mgrnt:44:rm -f /tmp/mg$$
        + /usr/magicadm/sbin/mgrnt:63:$AWK -F= '/^[^#]/ {if (NF > 0)
                                      print "export " $1}' $EnvUserFile > 
                                      /tmp/mgu$$
        + /usr/magicadm/sbin/mgrnt:64:. /tmp/mgu$$
        + /usr/magicadm/sbin/mgrnt:65:rm /tmp/mgu$$
        + /usr/magicadm/servers/mgdatasrvr.sc:51:$AWK -F= '/^[^#]/ {if (NF >
                                                 0) print "export " $1}' 
                                                 $MAGIC_HOME/etc/mgenv > 
                                                 /tmp/mg$$
        + /usr/magicadm/servers/mgdatasrvr.sc:52:. /tmp/mg$$
        + /usr/magicadm/servers/mgdatasrvr.sc:53:rm -f /tmp/mg$$
        + /usr/magicadm/servers/mgdatasrvr.sc:75:$AWK -F= '/^[^#]/
                                                 {if (NF > 0) print "export 
                                                 " $1}' $EnvUserFile > 
                                                 /tmp/mgu$$
        + /usr/magicadm/servers/mgdatasrvr.sc:76:. /tmp/mgu$$
        + /usr/magicadm/servers/mgdatasrvr.sc:77:rm /tmp/mgu$$
    
    
      d.) Insecure Permissions
        
      The RPM file installs some files and directories group 'users' 
      writeable.
      This includes the Magic Admin home directory /usr/magicadm (a magicadm
      account is created in /etc/passwd), the license directory and various
      executables.
      The list of group writeable executables:
      
        + /usr/magicadm/bin/magicrnt
        + /usr/magicadm/bin/mdinformix
        + /usr/magicadm/bin/mdmssql
        + /usr/magicadm/bin/mdoracle
        + /usr/magicadm/bin/mgcircvr
        + /usr/magicadm/bin/mgcisam
        + /usr/magicadm/bin/mginformix
        + /usr/magicadm/bin/mgmemory
        + /usr/magicadm/bin/mgoracle
        + /usr/magicadm/bin/mgtcp
        + /usr/magicadm/broker/mgrqcmdl
        + /usr/magicadm/broker/mgrqmrb
        + /usr/magicadm/cgibin/mgrqcgi
        + /usr/magicadm/servers/mgdatasrvr
    
      This allows an attacker to replace these writeable executeables to gain
      higher privileges and even any other file to exploit trusted 
      information.
    
    
      e.) Miscellaneous
        
      The symbols that are exported by the executables and by the
      Magic-Request API library reveal, that there are even more insecure C-
      library functions like system(3), strcpy(3), strcat(3) and sprintf(3)
      and alike.
    
    
    Vendor Response:
    ================
    
      Vendor contacted at 11.12.2001 according to 'Full Disclosure Policy 2.0',
      however we got no appropriate response.
    
    
    Solution/Fix:
    =============
    
      none yet
    
    
    Contact:
    ========
    
      immutec GmbH
      Mendelstr. 11
      48149 Muenster
      Germany
    
      infoat_private
      http://www.immutec.com
      Phone: ++49 (0) 251/980-1230
      Fax:   ++49 (0) 251/980-1231
    
    
    Authors:
    ========
    
      Thomas Biege <tbat_private>
      Stephan Holtwisch <shat_private>
    
    
    Disclaimer:
    ===========
    
     This advisory does not claim to be complete or to be usable for any 
     purpose. Especially information on the vulnerable systems may be
     inaccurate or wrong. Possible supplied exploit code is not to be used
     for malicious purposes, but for educational purposes only.
    
    
    Copyrights:
    ===========
     
     Copyright (c) 2001, immutec GmbH
    
     Redistribution without modification is permitted.
     Redistribution with modification is permitted if the copyright notice,
     disclaimer and authors notice are retained.
    
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.0.6 (IRIX64)
    Comment: For info see http://www.gnupg.org
    
    iEYEARECAAYFAjweY2kACgkQhMXODxDcN5JXRQCeK9Zcp0bEXjCtWPJ9Ey+kLt3V
    kD8AoJtJYNLDRgjaP2YOO5wCk+G6+Sbl
    =5bBe
    -----END PGP SIGNATURE-----
    



    This archive was generated by hypermail 2b30 : Wed Dec 19 2001 - 10:53:55 PST