|
COMMAND myPhpAdmin SYSTEMS AFFECTED myPhpAdmin <= 2.2.0rc3 PROBLEM Carl Livitt found following. Further to the excellent research done by Shaun Clowes of Secure Reality Pty Ltd into remote command execution on webservers running myPhpAdmin, it turns out that there is another method of exploitation. For details of what phpMyAdmin does, how it works and other security issues with the product, please refer to article SRADV00008: http://oliver.efri.hr/~crv/security/bugs/Others/phpadm.html The new method involves an unchecked variable in the 'tbl_copy.php' and 'tbl_rename.php'scripts. By passing a carefully crafted URL to these scripts, it is possible to insert PHP instructions into an eval() function thereby enabling the attacker to execute arbitrary commands on the webserver with the privileges of the http daemon, typically 'nobody'. The method works perfectly on a default installation of phpMyAdmin, but has not been tested in an environment where the advanced authentication mechanism has been enabled. In addition, this method assumes that the 'test' table in the mySQL database has not been removed; in order to successfully exploit the vulnerability presented here, it is necessary to have the ability to make changes to tables within a database. It should be noted that any database that phpMyAdmin has access rights to is sufficient: the 'test' database just happens to be very handy. In 'tbl_copy.php' and 'tbl_rename.php' are these lines of code: tbl_copy.php: eval("\$message = \"$strCopyTableOK\";"); tbl_rename.php: eval("\$message = \"$strRenameTableOK\";"); These eval() functions are called if the rest of the code in the script executed successfully. If it were possible to modify the contents of $strCopyTableOK or $strRenameTableOK, it would be possible to execute arbitrary eval() code. Fortunately for an attacker, it is possible to control the contents of either of these variables. For example, by passing a URL of: http://victim/phpmyadmin/tbl_copy.php?strCopyTableOK=".passthru('cat%20/etc/passwd')." it is possible to set things up so that the script dumps /etc/passwd. But it doesn't. Why? Because earlier code stops execution before we get to the eval(): (Note that the code has been edited for brevity) if (isset($new_name) && $new_name!=""){ . $result = mysql_query($sql_structure) or mysql_die(); . $result = mysql_query($query) or mysql_die(); . $result = mysql_query($sql_structure) or mysql_die(); } else mysql_die($strTableEmpty); If any of the mysql_query() calls fail, mysql_die() is called and execution stops. This is no good to us, as we need the calls to succeed in order for eval() to be executed with our commands in it. To make sure all the calls succeed, we need to make sure that we have a database that we can create tables in. This can be done by using 'tbl_create.php' script like so: http://victim/phpmyadmin/tbl_create.php?db=test&table=haxor&query=dummy+integer+primary+key+auto_increment&submit=1 In the default installation, we don't need to specify a username or password and will now have a table called 'haxor' in the 'test' database. We're now ready to exploit the 'tbl_copy.php' script: http://victim/phpmyadmin/tbl_copy.php?db=test&table=haxor&new_name=test.haxor2&strCopyTableOK=".passthru('cat%20/etc/passwd')." Success! The contents of /etc/passwd are included in the webpage that is returned by this URL. Of course, the choice of command to execute is limited only by the imagination of the attacker. SOLUTION This is really simple to fix: just comment out the offending eval() statements in the 'tbl_copy.php' and 'tbl_rename.php' scripts. The calls to eval() are not used at any point in the script because the $strCopyTableOK and $strRenameTableOK variables are never normally defined. This means it is safe to remove them. This isn't so much a problem with phpMyAdmin as it is with PHP in general. We would HIGHLY recommend turning off register_globals in php.ini (which is the default in set in php.ini-dist for php4+). With that option disabled, the only thing that passing in extra parameters can do is create entries in the $HTTP_GET_VARS array, and it's not possible to clobber global script variables.