iThemes Security is a know security plugin in the WordPress community since years. One week ago we discovered a security issue in their “Hide Backend” module, leaking the hidden login page.
This ByPass Vulnerability has been patched in 7.9.1, update it if you’re using it.
ITS (iThemes Security) < 7.9.1 suffers of a GET/POST/REQUEST bug that could leak the wp-login page from WordPress. The purpose of the module is broken.
This vulnerability won’t open a door to your website, not more than the native login page will do. So, that’s not a big deal, but still, when you activate a module that says “Hide Backend”, you can expect this module to… hide the backend.
Report Timings:
- 05 April 21 : Report the vulnerability
- 06 April 21 : Vulnerability confirmed with attached patch
- 07 April 21: Patch not working, received another patch
- 08 April 21 : Patch valid and confirmed.
- 14 April 21 : Versions updated
- 20 April 21 : Bounty Rewarded
Vulnerability Explained
- The HTTP request method is
POST
- The URL is pointing on
wp-login.php
- The URL parameter is “
action=postpass
” (so it’s a GET one) - The BODY parameter is “
action=login
” (so it’s a POST one)
The plugin will read the GET
and will let pass since it’s allowed (see below), but WordPress will handle the POST
one and will display the login form.
ITS 7.9.0 code
These are my comments, I’m just using the useful lines to explain.
[pastacode lang=”php” manual=”%2F*%20https%3A%2F%2Fplugins.svn.wordpress.org%2Fbetter-wp-security%2Ftags%2F7.9.0%2Fcore%2Fmodules%2Fhide-backend%2Fclass-itsec-hide-backend.php%20*%2F%0A%0A%2F%2F%20Line%2324%20On%20ITS%20init%2C%20handle%20the%20page%20request%0Aadd_action(%20’itsec_initialized’%2C%20array(%20%24this%2C%20’handle_specific_page_requests’%20)%2C%201000%20)%3B%0A%0A%2F%2F%20Line%2395%20Handle%20the%20requested%20path%0A%24this-%3Ehandle_request_path(%20%24path%20)%3B%0A%0A%2F%2F%20Line%23107-109%20Since%20we%20are%20requesting%20’wp-login.php’%20page%2C%20we%20trigger%20this%20condition%0A%7D%20elseif%20(%20in_array(%20%24request_path%2C%20array(%20’wp-login’%2C%20’wp-login.php’%20)%20)%20)%20%7B%0A%24this-%3Ehandle_canonical_login_page()%3B%0A%7D%0A%0A%2F%2F%20Line%23137%20If%20%24_GET%5B’action’%5D%20is%20equal%20to%20’postpass’%2C%20do%20nothing.%0Aprivate%20function%20handle_canonical_login_page()%20%7B%0A%24action%20%3D%20isset(%20%24_GET%5B’action’%5D%20)%20%3F%20%24_GET%5B’action’%5D%20%3A%20”%3B%0A%0Aif%20(%20’postpass’%20%3D%3D%3D%20%24action%20)%20%7B%0Areturn%3B%0A%7D” message=”” highlight=”” provider=”manual”/]
As you may now better understand, the action=postpass
is the bypass. This is why you shouldn’t use 2 different methods to read values.
WordPress does this:
[pastacode lang=”php” manual=”%2F%2F%20%2Fwp-login.php%23367%0A%24action%20%3D%20isset(%20%24_REQUEST%5B’action’%5D%20)%20%3F%20%24_REQUEST%5B’action’%5D%20%3A%20’login’%3B” message=”” highlight=”” provider=”manual”/]
So if $_REQUEST
is read, you should read it too.
Now, let’s remember what $_REQUEST
is. It’s a global array that contains both $_GET
and $_POST
values. The default order of merging if set by the server configuration and is 90% of the time GP
, meaning “GET + POST”. But you could find a server that is on PG
.
Patchs
The first patch was to replace $_GET['action']
by $_REQUEST['action']
which seems good, but not really if the server configuration is set to PG
, the flaw is still there, WordPress will load the login page again.
Did you know that WordPress will force a GP
configuration? Now you know, and it’s done with wp_magic_quotes() , cool isn’t it? But it won’t help the patch because ITS is reading the values before the usage on this function, done before setup_theme
, so ITS had to rewrite the patch just to change the hook and set it to setup_theme
.
It’s now fixed in 7.9.1, update now.
But there is still one thing to know…
This module has been developed to prevent bots and scripts from entering or brute-forcing the WordPress login page. It hasn’t been designed to be not found by humans, so you can still find a way, as a human, to get the secret token of a login page protected by ITS using… Google.
When you know the secret slug name of the login page, you are redirected on the real WordPress login page with a new parameter acting as a secret token named itsec-hb-token
. Since the parameter is a GET
one, Google can index it, this is why you will find those token on search engines.
Let’s say I’m human (this is real, I mean…) and I want to target example.com. I’ll search for “site:example.com inurl:itsec-hb-token
” and I may find something with the token in. Just click on it, if the token is still valid and TS activated, you’ll get the itsec-hb-token
cookie. Now you can visit wp-login.php
, you’re allowed.
This will not be fixed by ITS because it means a total revamp of the design of the module, and like I said, the module is designed to prevent bots and scripts.