Tag Archives: XMLrpc vulnerability

Securing your WordPress site with a little code.

WordPress Brute Force Attacks, WordPress Development
Brute force attempts ro crack passwords

Table of Contents

Introduction.

Limiting the number of login attempts.

Denying xmlrpc Requests.

Hiding your wp-login.php file.

Credits.

Updated: 3rd January 2023

Introduction.

Websites are increasing under brute force hacking attempts and distributed denial of service attacks (DDOS) .

As a WordPress website administrator you can secure your site with a little bit of code if you feel confident enough. There are security plugins for WordPress should you wish to go down that route. I haven’t tried any of them and so cannot make a recommendation. The advantages of not using unnecessary plugins is increased code processing efficiency and hence better performance of a website. In addition there is the benefit from the security perspective of avoiding the possibility of getting stuck with outdated and unsupported plugins.

The three setups described below that I recommend are limiting the number of login attempts , denying xmlrpc requests and hiding your wp-admin.php page.

Ideally, you should not edit the functions.php file of the theme you are using. This is because changes will be lost when the theme is updated by the theme’s developers. Instead you should create a child theme and edit the functions.php of this.

Here is a link on how to create a child theme. https://developer.wordpress.org/themes/advanced-topics/child-themes/

Limiting the number of login attempts.

To do this you can put the following code in your WordPress theme’s functions.php file.

// code to limit no. of login attempts - lock for 30 mins function check_attempted_login( $user, $username, $password ) {
if ( get_transient( 'attempted_login' ) ) {
$datas = get_transient( 'attempted_login' );
if ( $datas['tried'] >= 3 ) {
$until = get_option( 'transient_timeout' . 'attempted_login' );
$time = time_to_go( $until );
return new WP_Error( 'too_many_tried', sprintf( __( 'ERROR: You have reached authentication limit, you will be able to try again in %1$s.' ) , $time ) );
}
}
return $user;
}
add_filter( 'authenticate', 'check_attempted_login', 30, 3 );
function login_failed( $username ) {
if ( get_transient( 'attempted_login' ) ) {
$datas = get_transient( 'attempted_login' );
$datas['tried']++;
if ( $datas['tried'] <= 3 ) set_transient( 'attempted_login', $datas , 1800 ); } else { $datas = array( 'tried' => 1
);
set_transient( 'attempted_login', $datas , 1800 );
}
}
add_action( 'wp_login_failed', 'login_failed', 10, 1 );
function time_to_go($timestamp)
{
// converting the mysql timestamp to php time
$periods = array(
"second",
"minute",
"hour",
"day",
"week",
"month",
"year"
);
$lengths = array(
"60",
"60",
"24",
"7",
"4.35",
"12"
);
$current_timestamp = time();
$difference = abs($current_timestamp - $timestamp);
for ($i = 0; $difference >= $lengths[$i] && $i < count($lengths) - 1; $i ++) {
$difference /= $lengths[$i];
}
$difference = round($difference);
if (isset($difference)) {
if ($difference != 1)
$periods[$i] .= "s";
$output = "$difference $periods[$i]";
return $output;
}
}
// end code to limit no. of login attempts - lock for 30 mins

You can change the lock out time by changing the third argument in the set_transient function which is currently set to 1800 seconds (30 mins.)
This code will stop bots making brute force dictionary attacks on your username and password.

Denying xmlrpc Requests.

XMLrpc is a legacy protocol that used to be used for WordPress ping backs. It relies on transmission of the username and password. So an attacker can use bots to try and gain access to your website by guessing at passwords and usernames.

Another from of attack that uses XMLrpc is DDOS where thousands and even hundreds of thousands of XMLrpc requests are made to a website overwhelming it.

Please refer to the excellent document by SiteGround in the Credits to understand more about the XMLrpc and the vulnerability it poses to WordPress websites.

To disable XMLrpc insert the following code in the functions.php file of your theme.

// refuse XMLRPC requests
add_filter( 'xmlrpc_enabled', '__return_false' );
//end of refuse XMLRPC requests

Important! Make sure you use the correct type of single quotes.

add_filter( 'xmlrpc_enabled', '__return_false' ); will work okay while add_filter( ‘xmlrpc_enabled’, ‘__return_false’ ); will generate Warning: Use of undefined constant ‘xmlrpc_enabled’ - assumed '‘xmlrpc_enabled’' (this will throw an Error in a future version of PHP) in functions.php in a child theme.

You can also add the above code to the wp-config-php file. Add it after the require_once(ABSPATH . 'wp-settings.php'); line. There are a couple more ways to block XMLrpc requests. One being via the web server’s configuration file and the other via a plugin. Please refer to the SiteGround and the debugbar documents.

Hiding your wp-login.php file.

Some experts discourage doing it this as wp-login.php gets updated when the core WordPress version gets updated. If you remember this and update the changes manually this method is fine. It is also inadvisable if your website needs to provide login access to site members other than a handful of admin and authors.

Hiding your wp-login.php is very effective as bots target the wp-login.php either with password crackers or a DDOS attack once they know your website is powered by WordPress. Each wp-login request is costly as as information gets sent to and from the MySql database of the WordPress site.

The steps.

1) Backup your wp-login.php file. Then rename it on the web server.
2) Create a new .php file with a text editor like Notepad, Notepad++, Gedit (on Linux Ubuntu) etc. Name it whatever you want as long as you can remember it when you login e.g foxy-roxy.php
3) Copy all the contents from wp-login.php into foxy-roxy.php or whatever you named the new file. Use Crtl+Alt to select all and Paste.
4) Search and replace every occurrence of wp-login.php with foxy-roxy.php or whatever the file is called. Save the file.
5) The next step is to update the default login and logout URLs This is done via
hooks in the theme’s functions.php .
Add the following code to functions.php of the theme.

add_filter( 'logout_url', 'custom_logout_url' );
function custom_logout_url( $default )
{
return str_replace( 'wp-login', 'foxy-roxy', $default );
}
add_filter( 'login_url', 'custom_login_url' );
function custom_login_url( $default )
{
return str_replace( 'wp-login', 'foxy-roxy', $default );
}

(remember to change ‘foxy-roxy’ to whatever your file is called. )

Add the following code to handle a safe logout and redirect to your home page.

// WP Redirect the user to the homepage after logout add_action('wp_logout','auto_redirect_after_logout');
function auto_redirect_after_logout(){
wp_safe_redirect( home_url() );
exit();
}
//end WP Redirect the user to the homepage after logout

6) Next test your new login page URL. Website name/ foxy-roxy.php. Attempting to login with Website name/wp-login should produce a resource not found error.

7) Finally, delete the renamed wp-login.php from the web server.

Notes: Known vunerabilities with the above method. Due to the login code being hard coded in several places in WordPress , the name of your secret login page can get exposed by calls made wp-admin by an intelligent attacker rather than a bot. I think this can be taken care of by some sort of redirect but I haven't got the time to experiment.

One way to mitigate against this is to limit access to the login process to trusted IPs. This is done by editing the .htaccess file in the root WordPress installation directory and adding the following code. Remember to backup your .htaccess file before editing it.

#Limit access to website administration
<Limit GET POST PUT>
order deny,allow
deny from all
# admins IP
allow from xxx.xxx.xxx.xxx
</Limit>

where xxx.xxx.xxx.xxx is the IP number. You can add as many allow from IPs as you need or allow a whole Class C subnet with allow from xxx.xxx.xxx.0/24

In closing.

These three methods will certainly help secure your WordPress site and help counter the effects of a DDOS attack if you are subject to one.

Credits.

Phpot.com on Limiting the number of login attempts (09/12/2022):

https://phppot.com/wordpress/how-to-limit-login-attempts-in-wordpress/

SiteGround on XMLrpc (09/12/2022): https://www.siteground.com/blog/xmlrpc/#Brute_Force_Attacks_via_XMLRPC

Martin Aronovitch (09/12/2022): https://wpmudev.com/blog/hide-wordpress-login-page/#hidewithoutplugin

Debugbar.com How to block XML-RPC on WordPress 03/01/2023 https://www.debugbar.com/how-to-block-xml-rpc/