Recently around april, 19th 2016, iThemes Security got patched against a vulnerability discovered by our team, a lack of capability check, allowing any member with any role to perform an Administrator action.
When a file has changed on your installation, iThemes Security will warn you in your backend, using the admin notices.
In this notice you’ll find a little button to dismiss this warning. Logically, only administrators can dismiss this message.
But the vulnerability let anyone “fake click” on this button, hiding the changes to the administrator.
Read the following if you want to know where was the flaw and how to exploit it.
In the file /core/modules/file-changes/class-itsec-file-change-admin.php
you will find the function wp_ajax_itsec_file_
[pastacode lang=”php” message=”” highlight=”” provider=”manual” manual=”%09public%20function%20wp_ajax_itsec_file_change_warning_ajax()%20%7B%0A%0A%09%09if%20(%20!%20wp_verify_nonce(%20sanitize_text_field(%20%24_POST%5B’nonce’%5D%20)%2C%20’itsec_file_change_warning’%20)%20)%20%7B%0A%09%09%09die(%20__(%20’Security%20error!’%2C%20’better-wp-security’%20)%20)%3B%0A%09%09%7D%0A%0A%09%09die(%20delete_site_option(%20’itsec_file_change_warning’%20)%20)%3B%0A%0A%09%7D”/]
As you can see, a nonce token is checked, but not the role. So, usually a nonce token can be enough to block bad requests on this ajax action. But not if the token is known for everyone, let see this now.
Same file, we can read this:
[pastacode lang=”php” message=”” highlight=”” provider=”manual” manual=”add_action(%20’admin_enqueue_scripts’%2C%20array(%20%24this%2C%20’admin_enqueue_scripts’%20)%20)%3B%20%2F%2Fenqueue%20scripts%20for%20admin%20page”/]
A part of the function admin_enqueue_scripts()
does this :
[pastacode lang=”php” message=”” highlight=”” provider=”manual” manual=”%09%09wp_register_script(%20’itsec_file_change_warning_js’%2C%20%24this-%3Emodule_path%20.%20’js%2Fadmin-file-change-warning.js’%2C%20array(%20’jquery’%20)%2C%20%24itsec_globals%5B’plugin_build’%5D%20)%3B%0A%09%09wp_enqueue_script(%20’itsec_file_change_warning_js’%20)%3B%0A%09%09wp_localize_script(%0A%09%09%09’itsec_file_change_warning_js’%2C%0A%09%09%09’itsec_file_change_warning’%2C%0A%09%09%09array(%0A%09%09%09%09’nonce’%20%3D%3E%20wp_create_nonce(%20’itsec_file_change_warning’%20)%2C%0A%09%09%09%09’url’%20%20%20%3D%3E%20admin_url()%20.%20’admin.php%3Fpage%3Dtoplevel_page_itsec_logs%26itsec_log_filter%3Dfile_change’%2C%0A%09%09%09)%0A%09%09)%3B”/]
So, the nonce is written in the backend source code, for everyone, no restriction.
A simple subscriber can read this token, call the ajax file from WP with the action itsec_file_
and the warning admin notice will be gone until the next file change.
The solution brought by the iThemes Security Dev Team have been to not print the nonce for everyone AND check the role when checking the nonce.
You always have to check both, nonce and role when you do this kind of verification. Also, never ever print tokens for everyone if they don’t need it. Last, always use different and correct nonces names to avoid action replication.