WP fail2ban - Version 3.0.2

Version Description

  • Prevent double logging in WP 4.5.x for XML-RPC authentication failure
Download this release

Release Info

Developer invisnet
Plugin Icon 128x128 WP fail2ban
Version 3.0.2
Comparing to
See all releases

Code changes from version 3.0.1 to 3.0.2

Files changed (2) hide show
  1. readme.txt +91 -94
  2. wp-fail2ban.php +19 -10
readme.txt CHANGED
@@ -4,8 +4,8 @@ Author URI: https://charles.lecklider.org/
4
  Plugin URI: https://charles.lecklider.org/wordpress/wp-fail2ban/
5
  Tags: fail2ban, login, security, syslog
6
  Requires at least: 3.4.0
7
- Tested up to: 4.4.2
8
- Stable tag: 3.0.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -13,15 +13,15 @@ Write all login attempts to syslog for integration with fail2ban.
13
 
14
  == Description ==
15
 
16
- [fail2ban](http://www.fail2ban.org/) is one of the simplest and most effective security measures you can implement to prevent brute-force password-guessing attacks.
17
-
18
- *WP fail2ban* logs all login attempts, whether successful or not, to syslog using LOG_AUTH. To make log parsing as simple as possible *WPf2b* uses the same format as sshd. For example:
19
-
20
- Oct 17 20:59:54 foobar wordpress(www.example.com)[1234]: Authentication failure for admin from 192.168.0.1
21
- Oct 17 21:00:00 foobar wordpress(www.example.com)[2345]: Accepted password for admin from 192.168.0.1
22
-
23
- *WPf2b* comes with two `fail2ban` filters, `wordpress-hard.conf` and `wordpress-soft.conf`, designed to allow a split between immediate banning and the traditional more graceful approach.
24
-
25
  Requires PHP 5.3 or later.
26
 
27
  = Other Features =
@@ -50,124 +50,121 @@ Requires PHP 5.3 or later.
50
 
51
  == Installation ==
52
 
53
- 1. Upload the plugin to your plugins directory
54
- 1. Activate the plugin through the 'Plugins' menu in WordPress
55
- 1. Copy `wordpress-hard.conf` and `wordpress-soft.conf` to your `fail2ban/filters.d` directory
56
- 1. Edit `jail.local` to include something like:
57
- ~~~
58
- [wordpress-hard]
59
- enabled = true
60
- filter = wordpress-hard
61
- logpath = /var/log/auth.log
62
- maxretry = 1
63
-
64
- [wordpress-soft]
65
- enabled = true
66
- filter = wordpress-soft
67
- logpath = /var/log/auth.log
68
- maxretry = 3
69
- ~~~
70
- 5. Reload or restart `fail2ban`
71
-
 
 
72
  You may want to set `WP_FAIL2BAN_BLOCK_USER_ENUMERATION`, `WP_FAIL2BAN_PROXIES` and/or `WP_FAIL2BAN_BLOCKED_USERS`; see the FAQ for details.
73
 
74
  == Frequently Asked Questions ==
75
 
76
  = wordpress-hard.conf vs wordpress-soft.conf =
77
 
78
- There are some things that are almost always malicious, e.g. blocked users and pingbacks with errors. `wordpress-hard.conf` is designed to catch these so that you can ban the IP immediately.
79
-
80
- Other things are relatively benign, like a failed login. You can't let people try forever, but banning the IP immediately would be wrong too. `wordpress-soft.conf` is designed to catch these so that you can set a higher retry limit before banning the IP.
81
-
82
  For the avoidance of doubt: you should be using *both* filters.
83
 
84
  = WP_FAIL2BAN_HTTP_HOST – what’s it for? =
85
 
86
- This is for some flavours of Linux where `WP_FAIL2BAN_SYSLOG_SHORT_TAG` isn't enough.
87
-
88
- If you configure your web server to set an environment variable named `WP_FAIL2BAN_SYSLOG_SHORT_TAG` on a per-virtual host basis, *WPf2b* will use that in the syslog tag. This allows you to configure a unique tag per site in a way that makes sense for your configuration, rather than some arbitrary truncation or hashing within the plugin.
89
-
90
  **NB:** This feature has not been tested as extensively as others. While I'm confident it works, FreeBSD doesn't have this problem so this feature will always be second-tier.
91
 
92
  = WP_FAIL2BAN_SYSLOG_SHORT_TAG – what’s it for? =
93
 
94
- Some flavours of Linux come with a `syslogd` that can't cope with the normal message format *WPf2b* uses; basically, they assume that the first part of the message (the tag) won't exceed some (small) number of characters, and mangle the message if it does. This breaks the regex in the *fail2ban* filter and so nothing gets blocked.
95
-
96
- Adding:
97
-
98
- define('WP_FAIL2BAN_SYSLOG_SHORT_TAG',true);
99
-
100
  to `functions.php` will make *WPf2b* use `wp` as the syslog tag, rather than the normal `wordpress`. This buys you 7 characters which may be enough to work around the problem, but if it's not enough you should look at `WP_FAIL2BAN_HTTP_HOST` too.
101
 
102
  = WP_FAIL2BAN_BLOCKED_USERS – what’s it all about? =
103
 
104
- The bots that try to brute-force WordPress logins aren't that clever (no doubt that will change), but they may only make one request per IP every few hours in an attempt to avoid things like `fail2ban`. With large botnets this can still create significant load.
105
-
106
- Based on a suggestion from *jmadea*, *WPf2b* now allows you to specify a regex that will shortcut the login process if the requested username matches.
107
-
108
- For example, putting the following in `wp-config.php`:
109
-
110
- define('WP_FAIL2BAN_BLOCKED_USERS','^admin$');
111
-
112
- will block any attempt to log in as `admin` before most of the core WordPress code is run. Unless you go crazy with it, a regex is usually cheaper than a call to the database so this should help keep things running during an attack.
113
-
114
  *WPf2b* doesn't do anything to the regex other than make it case-insensitive.
115
 
116
  = WP_FAIL2BAN_PROXIES – what’s it all about? =
117
 
118
- The idea here is to list the IP addresses of the trusted proxies that will appear as the remote IP for the request. When defined:
119
-
120
- * If the remote address appears in the `WP_FAIL2BAN_PROXIES` list, *WPf2b* will log the IP address from the `X-Forwarded-For` header
121
- * If the remote address does not appear in the `WP_FAIL2BAN_PROXIES` list, *WPf2b* will return a 403 error
122
- * If there's no X-Forwarded-For header, *WPf2b* will behave as if `WP_FAIL2BAN_PROXIES` isn't defined
123
-
124
- To set `WP_FAIL2BAN_PROXIES`, add something like the following to `wp-config.php`:
125
-
126
- define('WP_FAIL2BAN_PROXIES','192.168.0.42,192.168.42.0/24');
127
-
128
  *WPf2b* doesn't do anything clever with the list - beware of typos!
129
 
130
  = WP_FAIL2BAN_BLOCK_USER_ENUMERATION – what’s it all about? =
131
 
132
- Brute-forcing WP requires knowing a valid username. Unfortunately, WP makes this all but trivial.
133
-
134
- Based on a suggestion from *geeklol* and a plugin by *ROIBOT*, *WPf2b* can now block user enumeration attempts. Just add the following to `wp-config.php`:
135
-
136
  define('WP_FAIL2BAN_BLOCK_USER_ENUMERATION',true);
137
 
138
  = WP_FAIL2BAN_LOG_PINGBACKS – what’s it all about? =
139
 
140
- Based on a suggestion from *maghe*, *WPf2b* can now log pingbacks. To enable this feature, add the following to `wp-config.php`:
141
-
142
- define('WP_FAIL2BAN_LOG_PINGBACKS',true);
143
-
144
- By default, *WPf2b* uses LOG_USER for logging pingbacks. If you'd rather it used a different facility you can change it by adding something like the following to `wp-config.php`:
145
-
146
  define('WP_FAIL2BAN_PINGBACK_LOG',LOG_LOCAL3);
147
 
148
  = WP_FAIL2BAN_AUTH_LOG – what’s it all about? =
149
 
150
- By default, *WPf2b* uses LOG_AUTH for logging authentication success or failure. However, some systems use LOG_AUTHPRIV instead, but there's no good run-time way to tell. If your system uses LOG_AUTHPRIV you should add the following to `wp-config.php`:
151
-
152
- define('WP_FAIL2BAN_AUTH_LOG',LOG_AUTHPRIV);
153
-
154
- = Why is fail2ban complaining on my flavour of Linux? =
155
 
156
- Depending on your `fail2ban` configuration, you may need to add a line like:
157
-
158
- port = http,https
159
-
160
- to the `[wordpress]` section in `jail.local`.
161
 
162
  == Changelog ==
163
 
 
 
 
164
  = 3.0.1 =
165
  * Fix regex in `wordpress-hard.conf`
166
 
167
  = 3.0.0 =
168
- * Add `WP_FAIL2BAN_SYSLOG_SHORT_TAG`.
169
- * Add `WP_FAIL2BAN_HTTP_HOST`.
170
- * Log XML-RPC authentication failure.
171
  * Add better support for MU deployment.
172
 
173
  = 2.3.2 =
@@ -180,22 +177,22 @@ to the `[wordpress]` section in `jail.local`.
180
  * Fix stupid mistake with `WP_FAIL2BAN_BLOCKED_USERS`.
181
 
182
  = 2.2.0 =
183
- * Custom authentication log is now called `WP_FAIL2BAN_AUTH_LOG`
184
- * Add logging for pingbacks
185
  * Custom pingback log is called `WP_FAIL2BAN_PINGBACK_LOG`
186
 
187
  = 2.1.1 =
188
  * Minor bugfix.
189
 
190
  = 2.1.0 =
191
- * Add support for blocking user enumeration; see `WP_FAIL2BAN_BLOCK_USER_ENUMERATION`
192
  * Add support for CIDR notation in `WP_FAIL2BAN_PROXIES`.
193
 
194
  = 2.0.1 =
195
  * Bugfix in *experimental* `WP_FAIL2BAN_PROXIES` code.
196
 
197
  = 2.0.0 =
198
- * Add *experimental* support for X-Forwarded-For header; see `WP_FAIL2BAN_PROXIES`
199
  * Add *experimental* support for regex-based login blocking; see `WP_FAIL2BAN_BLOCKED_USERS`
200
 
201
  = 1.2.1 =
@@ -222,9 +219,9 @@ Fix for `WP_FAIL2BAN_PROXIES`; if you're not using it you can safely skip this r
222
  Bugfix.
223
 
224
  = 2.2.0 =
225
- BREAKING CHANGE: `WP_FAIL2BAN_LOG` has been renamed to `WP_FAIL2BAN_AUTH_LOG`
226
-
227
- Pingbacks are getting a lot of attention recently, so *WPf2b* can now log them.
228
  The `wordpress.conf` filter has been updated; you will need to update your `fail2ban` configuration.
229
 
230
  = 2.1.0 =
4
  Plugin URI: https://charles.lecklider.org/wordpress/wp-fail2ban/
5
  Tags: fail2ban, login, security, syslog
6
  Requires at least: 3.4.0
7
+ Tested up to: 4.5.3
8
+ Stable tag: 3.0.2
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
13
 
14
  == Description ==
15
 
16
+ [fail2ban](http://www.fail2ban.org/) is one of the simplest and most effective security measures you can implement to prevent brute-force password-guessing attacks.
17
+
18
+ *WP fail2ban* logs all login attempts, whether successful or not, to syslog using LOG_AUTH. To make log parsing as simple as possible *WPf2b* uses the same format as sshd. For example:
19
+
20
+ Oct 17 20:59:54 foobar wordpress(www.example.com)[1234]: Authentication failure for admin from 192.168.0.1
21
+ Oct 17 21:00:00 foobar wordpress(www.example.com)[2345]: Accepted password for admin from 192.168.0.1
22
+
23
+ *WPf2b* comes with two `fail2ban` filters, `wordpress-hard.conf` and `wordpress-soft.conf`, designed to allow a split between immediate banning and the traditional more graceful approach.
24
+
25
  Requires PHP 5.3 or later.
26
 
27
  = Other Features =
50
 
51
  == Installation ==
52
 
53
+ 1. Upload the plugin to your plugins directory
54
+ 1. Activate the plugin through the 'Plugins' menu in WordPress
55
+ 1. Copy `wordpress-hard.conf` and `wordpress-soft.conf` to your `fail2ban/filters.d` directory
56
+ 1. Edit `jail.local` to include something like:
57
+ ~~~
58
+ [wordpress-hard]
59
+ enabled = true
60
+ filter = wordpress-hard
61
+ logpath = /var/log/auth.log
62
+ maxretry = 1
63
+ port = http,https
64
+
65
+ [wordpress-soft]
66
+ enabled = true
67
+ filter = wordpress-soft
68
+ logpath = /var/log/auth.log
69
+ maxretry = 3
70
+ port = http,https
71
+ ~~~
72
+ 5. Reload or restart `fail2ban`
73
+
74
  You may want to set `WP_FAIL2BAN_BLOCK_USER_ENUMERATION`, `WP_FAIL2BAN_PROXIES` and/or `WP_FAIL2BAN_BLOCKED_USERS`; see the FAQ for details.
75
 
76
  == Frequently Asked Questions ==
77
 
78
  = wordpress-hard.conf vs wordpress-soft.conf =
79
 
80
+ There are some things that are almost always malicious, e.g. blocked users and pingbacks with errors. `wordpress-hard.conf` is designed to catch these so that you can ban the IP immediately.
81
+
82
+ Other things are relatively benign, like a failed login. You can't let people try forever, but banning the IP immediately would be wrong too. `wordpress-soft.conf` is designed to catch these so that you can set a higher retry limit before banning the IP.
83
+
84
  For the avoidance of doubt: you should be using *both* filters.
85
 
86
  = WP_FAIL2BAN_HTTP_HOST – what’s it for? =
87
 
88
+ This is for some flavours of Linux where `WP_FAIL2BAN_SYSLOG_SHORT_TAG` isn't enough.
89
+
90
+ If you configure your web server to set an environment variable named `WP_FAIL2BAN_SYSLOG_SHORT_TAG` on a per-virtual host basis, *WPf2b* will use that in the syslog tag. This allows you to configure a unique tag per site in a way that makes sense for your configuration, rather than some arbitrary truncation or hashing within the plugin.
91
+
92
  **NB:** This feature has not been tested as extensively as others. While I'm confident it works, FreeBSD doesn't have this problem so this feature will always be second-tier.
93
 
94
  = WP_FAIL2BAN_SYSLOG_SHORT_TAG – what’s it for? =
95
 
96
+ Some flavours of Linux come with a `syslogd` that can't cope with the normal message format *WPf2b* uses; basically, they assume that the first part of the message (the tag) won't exceed some (small) number of characters, and mangle the message if it does. This breaks the regex in the *fail2ban* filter and so nothing gets blocked.
97
+
98
+ Adding:
99
+
100
+ define('WP_FAIL2BAN_SYSLOG_SHORT_TAG',true);
101
+
102
  to `functions.php` will make *WPf2b* use `wp` as the syslog tag, rather than the normal `wordpress`. This buys you 7 characters which may be enough to work around the problem, but if it's not enough you should look at `WP_FAIL2BAN_HTTP_HOST` too.
103
 
104
  = WP_FAIL2BAN_BLOCKED_USERS – what’s it all about? =
105
 
106
+ The bots that try to brute-force WordPress logins aren't that clever (no doubt that will change), but they may only make one request per IP every few hours in an attempt to avoid things like `fail2ban`. With large botnets this can still create significant load.
107
+
108
+ Based on a suggestion from *jmadea*, *WPf2b* now allows you to specify a regex that will shortcut the login process if the requested username matches.
109
+
110
+ For example, putting the following in `wp-config.php`:
111
+
112
+ define('WP_FAIL2BAN_BLOCKED_USERS','^admin$');
113
+
114
+ will block any attempt to log in as `admin` before most of the core WordPress code is run. Unless you go crazy with it, a regex is usually cheaper than a call to the database so this should help keep things running during an attack.
115
+
116
  *WPf2b* doesn't do anything to the regex other than make it case-insensitive.
117
 
118
  = WP_FAIL2BAN_PROXIES – what’s it all about? =
119
 
120
+ The idea here is to list the IP addresses of the trusted proxies that will appear as the remote IP for the request. When defined:
121
+
122
+ * If the remote address appears in the `WP_FAIL2BAN_PROXIES` list, *WPf2b* will log the IP address from the `X-Forwarded-For` header
123
+ * If the remote address does not appear in the `WP_FAIL2BAN_PROXIES` list, *WPf2b* will return a 403 error
124
+ * If there's no X-Forwarded-For header, *WPf2b* will behave as if `WP_FAIL2BAN_PROXIES` isn't defined
125
+
126
+ To set `WP_FAIL2BAN_PROXIES`, add something like the following to `wp-config.php`:
127
+
128
+ define('WP_FAIL2BAN_PROXIES','192.168.0.42,192.168.42.0/24');
129
+
130
  *WPf2b* doesn't do anything clever with the list - beware of typos!
131
 
132
  = WP_FAIL2BAN_BLOCK_USER_ENUMERATION – what’s it all about? =
133
 
134
+ Brute-forcing WP requires knowing a valid username. Unfortunately, WP makes this all but trivial.
135
+
136
+ Based on a suggestion from *geeklol* and a plugin by *ROIBOT*, *WPf2b* can now block user enumeration attempts. Just add the following to `wp-config.php`:
137
+
138
  define('WP_FAIL2BAN_BLOCK_USER_ENUMERATION',true);
139
 
140
  = WP_FAIL2BAN_LOG_PINGBACKS – what’s it all about? =
141
 
142
+ Based on a suggestion from *maghe*, *WPf2b* can now log pingbacks. To enable this feature, add the following to `wp-config.php`:
143
+
144
+ define('WP_FAIL2BAN_LOG_PINGBACKS',true);
145
+
146
+ By default, *WPf2b* uses LOG_USER for logging pingbacks. If you'd rather it used a different facility you can change it by adding something like the following to `wp-config.php`:
147
+
148
  define('WP_FAIL2BAN_PINGBACK_LOG',LOG_LOCAL3);
149
 
150
  = WP_FAIL2BAN_AUTH_LOG – what’s it all about? =
151
 
152
+ By default, *WPf2b* uses LOG_AUTH for logging authentication success or failure. However, some systems use LOG_AUTHPRIV instead, but there's no good run-time way to tell. If your system uses LOG_AUTHPRIV you should add the following to `wp-config.php`:
 
 
 
 
153
 
154
+ define('WP_FAIL2BAN_AUTH_LOG',LOG_AUTHPRIV);
 
 
 
 
155
 
156
  == Changelog ==
157
 
158
+ = 3.0.2 =
159
+ * Prevent double logging in WP 4.5.x for XML-RPC authentication failure
160
+
161
  = 3.0.1 =
162
  * Fix regex in `wordpress-hard.conf`
163
 
164
  = 3.0.0 =
165
+ * Add `WP_FAIL2BAN_SYSLOG_SHORT_TAG`.
166
+ * Add `WP_FAIL2BAN_HTTP_HOST`.
167
+ * Log XML-RPC authentication failure.
168
  * Add better support for MU deployment.
169
 
170
  = 2.3.2 =
177
  * Fix stupid mistake with `WP_FAIL2BAN_BLOCKED_USERS`.
178
 
179
  = 2.2.0 =
180
+ * Custom authentication log is now called `WP_FAIL2BAN_AUTH_LOG`
181
+ * Add logging for pingbacks
182
  * Custom pingback log is called `WP_FAIL2BAN_PINGBACK_LOG`
183
 
184
  = 2.1.1 =
185
  * Minor bugfix.
186
 
187
  = 2.1.0 =
188
+ * Add support for blocking user enumeration; see `WP_FAIL2BAN_BLOCK_USER_ENUMERATION`
189
  * Add support for CIDR notation in `WP_FAIL2BAN_PROXIES`.
190
 
191
  = 2.0.1 =
192
  * Bugfix in *experimental* `WP_FAIL2BAN_PROXIES` code.
193
 
194
  = 2.0.0 =
195
+ * Add *experimental* support for X-Forwarded-For header; see `WP_FAIL2BAN_PROXIES`
196
  * Add *experimental* support for regex-based login blocking; see `WP_FAIL2BAN_BLOCKED_USERS`
197
 
198
  = 1.2.1 =
219
  Bugfix.
220
 
221
  = 2.2.0 =
222
+ BREAKING CHANGE: `WP_FAIL2BAN_LOG` has been renamed to `WP_FAIL2BAN_AUTH_LOG`
223
+
224
+ Pingbacks are getting a lot of attention recently, so *WPf2b* can now log them.
225
  The `wordpress.conf` filter has been updated; you will need to update your `fail2ban` configuration.
226
 
227
  = 2.1.0 =
wp-fail2ban.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: https://charles.lecklider.org/wordpress/wp-fail2ban/
5
  * Description: Write all login attempts to syslog for integration with fail2ban.
6
  * Text Domain: wp-fail2ban
7
- * Version: 3.0.1
8
  * Author: Charles Lecklider
9
  * Author URI: https://charles.lecklider.org/
10
  * License: GPL2
@@ -12,7 +12,7 @@
12
  */
13
 
14
  /**
15
- * Copyright 2012-15 Charles Lecklider (email : wordpress@charles.lecklider.org)
16
  *
17
  * This program is free software; you can redistribute it and/or modify
18
  * it under the terms of the GNU General Public License, version 2, as
@@ -142,19 +142,28 @@ if (!defined('WP_FAIL2BAN')) {
142
  $msg = (wp_cache_get($username, 'userlogins'))
143
  ? "Authentication failure for $username from "
144
  : "Authentication attempt for unknown user $username from ";
 
 
 
 
145
  openlog();
146
- \syslog(LOG_NOTICE,$msg.remote_addr());
147
  });
148
  /*
149
  * @since 3.0.0
150
  */
151
- add_action( 'xmlrpc_login_error',
152
- function($error, $user)
153
- {
154
- openlog();
155
- \syslog(LOG_NOTICE,'XML-RPC authentication failure from '.remote_addr());
156
- bail();
157
- },10,2);
 
 
 
 
 
158
  /*
159
  * @since 3.0.0
160
  */
4
  * Plugin URI: https://charles.lecklider.org/wordpress/wp-fail2ban/
5
  * Description: Write all login attempts to syslog for integration with fail2ban.
6
  * Text Domain: wp-fail2ban
7
+ * Version: 3.0.2
8
  * Author: Charles Lecklider
9
  * Author URI: https://charles.lecklider.org/
10
  * License: GPL2
12
  */
13
 
14
  /**
15
+ * Copyright 2012-16 Charles Lecklider (email : wordpress@charles.lecklider.org)
16
  *
17
  * This program is free software; you can redistribute it and/or modify
18
  * it under the terms of the GNU General Public License, version 2, as
142
  $msg = (wp_cache_get($username, 'userlogins'))
143
  ? "Authentication failure for $username from "
144
  : "Authentication attempt for unknown user $username from ";
145
+ $msg .= remote_addr();
146
+ if (class_exists('wp_xmlrpc_server',false)) {
147
+ $msg .= ' via XML-RPC';
148
+ }
149
  openlog();
150
+ \syslog(LOG_NOTICE,$msg);
151
  });
152
  /*
153
  * @since 3.0.0
154
  */
155
+ $v = explode('.',$wp_version);
156
+ if (4 == $v[0] && 5 > $v[1]) {
157
+ // prevent double logging
158
+ // will be removed for WP4.7
159
+ add_action( 'xmlrpc_login_error',
160
+ function($error, $user)
161
+ {
162
+ openlog();
163
+ \syslog(LOG_NOTICE,'XML-RPC authentication failure from '.remote_addr());
164
+ bail();
165
+ },10,2);
166
+ }
167
  /*
168
  * @since 3.0.0
169
  */