Summary

addons.mozilla.org was vulnerable to a directory traversal / local file inclusion vulnerability. As a result, it was possible for an attacker to load webserver-readable files from the local filesystem (and to execute PHP stored on the server).

This vulnerability is filed as Bug #628697.

How did it work?

In the PHP code for the addons website, there’s a controller called pages_controller.php that is used to load static / semi-static pages. The exact name of the page to be loaded is determined by the query string: for example, https://addons.mozilla.org/en-US/firefox/pages/credits loads the Site Credits page, which is stored as a template in the system. In older, vulnerable versions of the code, the method for displaying a page looked like this:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php function display () { if ( ! func_num_args ()) { $this -> redirect ( '/' ); } $path = func_get_args (); $path_string = join ( '/' , $path ); if ( ! count ( $path ) || ( $path [ 0 ] == 'home' )) { $this -> redirect ( '/' ); } // ...snip... $this -> render ( $path_string ); }

This code is vulnerable to a directory traversal attack: the $path_string , which is used to load a template, is directly tied to user input (the arguments to the function here are the elements of the query string). By sending URL encoded slashes (%252F), it was possible to break out of the current directory and traverse via a relative path to any directory in the system. It was also possible to convince CakePHP (the framework used here) to load files without the .thtml file extension associated with templates by including a URL-encoded null byte (%2500) at the end of the URL.

To give one example of a possible traversal, here is the proof of concept that I included with the bug. It displayed the contents of the /etc/passwd file of the addons server (As Michael Coates properly notes, no password hashes were disclosed due to this vulnerability):

https://addons.mozilla.org/en-US/firefox/pages/..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc/passwd%2500

The vulnerability was resolved by using CakePHP’s own built-in parameter handling, which precludes an attacker from including slashes in a parameter passed via the query string. The relevant code from the latest revision looks something like this:

1 2 3 4 5 6 7 8 9 10 11 <?php function display ( $page ) { if ( empty ( $page ) || $page == 'home' ) { $this -> redirect ( '/' ); exit ; } // ...snip... $this -> render ( "/ $page " ); }

More Information

The vulnerability mentioned here has been confirmed fixed by Mozilla.

I’d like to thank Wil Clouser and Michael Coates for handling this issue. I’d especially like to applaud them for the speed with which they handled this report: the vulnerability was patched and the fix was deployed in production about an hour and a half after my initial report.

Interested readers are encouraged to take a look at other vulnerabilities I’ve reported as a part of Mozilla’s Web Security Bug Bounty.