Affected plugin | WP SAML Auth |
Active installs | 5,000+ |
Vulnerable version | <= 2.1.3 |
Audited version | 2.1.3 |
Fully patched version | 2.1.4 |
Recommended remediation | Upgrade the plugin to 2.1.4 |
Description
The WP SAML Auth plugin allows enforcing that all users must log in via the configured SAML IDP rather than the standard WordPress login.
This can be bypassed by adding a loggedout
query parameter to any URL that allows logins.
Any SSO-provisioned user can reset their WordPress password in the WordPress admin area.
Thus, users who are removed from a company’s IDP will still be able to log into WordPress using their username and password.
Proof of concept
The plugin contains the following code, which hooks into the WordPress authenticate filter.
public function filter_authenticate( $user, $username, $password ) {
$permit_wp_login = self::get_option( 'permit_wp_login' );
if ( is_a( $user, 'WP_User' ) && $permit_wp_login ) {
return $user;
}
if ( ! empty( $_POST['SAMLResponse'] ) ) {
$user = $this->do_saml_authentication();
} elseif ( ( ! $permit_wp_login && empty( $_GET['loggedout'] ) ) || ( ! empty( $_GET['action'] ) && 'wp-saml-auth' === $_GET['action'] ) ) {
$user = $this->do_saml_authentication();
}
return $user;
}
The highlighted line shows that SAML authentication will not be performed if the loggedout
query parameter is present in the request.
This was presumably added to prevent the SAML authentication from running once a user logs out of WordPress (which would redirect them to /wp-login.php?loggedout=1).
However, it’s also possible to send query parameters via POST requests and thus bypass the SSO requirements.
curl
-X POST https://wp.test/wp-login.php?loggedout=1 \
-d "log=admin" \
-d "pwd=admin" -v
Sending the above request will return valid WordPress authentication cookies.
Proposed patch
The logic of the authenticate callback should be changed to something like the following:
function filter_authenticate( $user, $username, $password ) {
$allow_wp_login = self::get_option('permit_wp_login');
// Some other WordPress filter already authenticated the user.
if(is_a($user, 'WP_User')) {
// Unless explicitly allowed, only SAML users can be authenticated.
if(! $allow_wp_login){
$user = $this->do_saml_authentication();
}
return $user;
}
if(! $allow_wp_login){
// If wp-login is not allowed, always redirect to IDP
// unless the user just logged out.
$should_saml = !isset($_GET['loggedout']);
}else{
// If wp-login is allowed, redirect to IDP selectively.
$should_saml = isset($_POST['SAMLResponse']) || (isset($_GET['action']) && 'wp-saml-auth' === $_GET['action']);
}
if($should_saml){
return $this->do_saml_authentication();
}
return $user;
}
Here, we strictly separate the SSO enforcement (security) from the SSO redirect functionality when the user hits wp-login.php, and normal WordPress logins are not allowed (UX).
Timeline
Vendor contacted | Oktober 23, 2023 |
First Response | Oktober 23, 2023 |
Fully patched at | November 27, 2023 |
Publicly disclosed | December 30, 2023 |
Miscellaneous
Pantheon was very cooperative and fixed the issue in a timely manner using our recommended patch.
Leave a Reply