|
COMMAND Magic Enterprise multiple vulnerabilities SYSTEMS AFFECTED Magic Enterprise Edition 8.30-5 and prior, 9.x not fully tested PROBLEM In immutec Security Advisory SA-MAGIC-001, multiple vulnerabilities are explained about Magic Enterprise Edition : 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. Authors: ======== Thomas Biege <tb@immutec.com> Stephan Holtwisch <sh@immutec.com> 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. SOLUTION Nothing yet.