Thursday, June 25, 2009

Zen Cart authentication bypass

Zen Cart is a popular open source e-commerce application, written in PHP. Yesterday, two exploits for Zen Cart showed up on milw0rm. The first one is a remote code execution, the second one an SQL injection exploit. The root cause of the two bugs however, is the same: an authentication bypass on the administrative interface of Zen Cart discoverd by Ghyslain/BlackH. Zen Cart has released a patch for this issue here.

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.

Thursday, June 4, 2009

Slides of my OWASP talk on CSRF

Last week I gave a VAC (Vulnerability, Attack, Countermeasure) talk at an OWASP Netherlands meeting. I picked Cross-Site Request Forgery (CSRF) as a topic as it is an often misunderstood and underestimated problem.

My slides (in English) are available on the OWASP site here. I am planning on releasing another version of the slides in the OWASP template and with speaker notes for easier reuse. The last slide lists some good resources and interesting case studies (including more information on the case studies used in the presentation).