Zen Cart does a pretty decent job verifying administrators are actually authenticated, however it has some exceptions to the rule:
This code is present in /admin/includes/init_includes/init_admin_auth.php (slightly simplified code):
if (if (!isset($_SESSION['admin_id']) &&
!(basename($SERVER['PHP_SELF']) == 'password_forgotten.php')) {
zen_redirect('login.php');
}
So basically, if you are not logged in, Zen Cart will redirect you to the login page, unless you are accessing the password_forgotten.php page.
The problem here is trusting the PHP_SELF variable to determine which script is being accessed. Here a bit of strange PHP behaviour comes in. If I request http://server.com/index.php, the PHP_SELF variable will be /index.php. However if I request http://server.com/index.php/foobar , the PHP_SELF variable will be /index.php/foobar, but the script being executed will still be index.php!
So in this case we can trick Zen Cart into thinking we are accessing password_forgotten.php, while we are actually accessing a different file by requesting:
http://target/admin/customers.php/password_forgotten.php
The file we are executing is customers.php, but basename(PHP_SELF) will return password_forgotten.php! Zen Cart thinks we are accessing the ‘I forgot my password’ page, which does not require authentication and allows us to continue without logging in. We can now view a list of customers on our target site, without logging in!
The code execution exploit uses this to access an admin script that allows an administrator to create new files. The exploit uses this functionality to create a new php file on the server, this php file contains a simple backdoor and voila: remote code execution.
Luckily Zen Cart has released a fix for this (although I expect most installations are still vulnerable). I took a look at the patch and noticed it attempts to fix the bug by checking if the string '.php' appears more than once in PHP_SELF. At first this seems to be an (ugly but) effective fix and I think it is in most cases. However, Zen Cart supports multiple platforms, including Windows. As you may know, filenames on Windows are not case sensitive (foo.txt is the same as foo.TXT). The new check however only checks for lowercase instances of '.php'… So if our target is a Windows system, we can circumvent the patch by requesting:
http://target/admin/customers.PHP/password_forgotten.php
So by changing the extension of customers.php to .PHP, we modify the PHP_SELF variable so '.php' is only present once and bypass the new check! I modified the code execution exploit on milw0rm to reflect this and was able to succesfully exploit my installation of Zen Cart on a Windows platform.
Of course I notified the Zen Cart developers of the shortcoming in their patch and they have released an updated version which does a case insensitive check.