Announcement

Collapse
No announcement yet.

fail2ban & WordPress Plugin: some help with PHP please?

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    fail2ban & WordPress Plugin: some help with PHP please?

    Evening all,

    I've been tinkering with fail2ban on my RasPi server. I'd like to use it with a WordPress plugin called "WP fail2ban" so that login attempts are written to a log file and fail2ban can monitor them.

    The problem is: successful login attempts are logged, but unsuccessful attempts are not!

    Here's an example:

    Code:
    #/var/log/auth.log
    Jan 17 18:57:37 samhobbs wordpress(www.samhobbs.co.uk)[18819]: Accepted password for USERNAME from 192.168.1.1
    ...and here's the plugin's PHP code.

    Code:
    <?php
    /*
    Plugin Name: WP fail2ban
    Plugin URI: https://charles.lecklider.org/wordpress/wp-fail2ban/
    Description: Write all login attempts to syslog for integration with fail2ban.
    Version: 2.1.0
    Author: Charles Lecklider
    Author URI: https://charles.lecklider.org/
    License: GPL2
    */
    
    /*  Copyright 2012-13  Charles Lecklider  (email : wordpress@charles.lecklider.org)
    
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License, version 2, as
        published by the Free Software Foundation.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    */
    
    namespace org\lecklider\charles\wp_fail2ban;
    
    function openlog()
    {
            \openlog('wordpress('.$_SERVER['HTTP_HOST'].')',
                             LOG_NDELAY|LOG_PID,
                             defined(WP_FAIL2BAN_LOG) ? WP_FAIL2BAN_LOG : LOG_AUTH);
    }
    
    function bail()
    {
            ob_end_clean();
            header('HTTP/1.0 403 Forbidden');
            header('Content-Type: text/plain');
            exit('Forbidden');
    }
    
    function remote_addr()
    {
            if (defined('WP_FAIL2BAN_PROXIES')) {
                    if (array_key_exists('HTTP_X_FORWARDED_FOR',$_SERVER)) {
                            $ip = ip2long($_SERVER['REMOTE_ADDR']);
                            foreach(explode(',',WP_FAIL2BAN_PROXIES) as $proxy) {
                                    if (2 == count($cidr = explode('/',$proxy))) {
                                            $net = ip2long($cidr[0]);
                                            $mask = ~ ( (2 ^ (32 - $cidr[1])) - 1 );
                                    } else {
                                            $net = ip2long($proxy);
                                            $mask = -1;
                                    }
                                    if ($net == $ip & $mask) {
                                            return (false===($len = strpos($_SERVER['HTTP_X_FORWARDED_FOR'],',')))
                                                            ? $_SERVER['HTTP_X_FORWARDED_FOR']
                                                            : substr($_SERVER['HTTP_X_FORWARDED_FOR'],0,$len);
                                    }
                            }
                    }
            }
    
            return $_SERVER['REMOTE_ADDR'];
    }
    
    if (defined('WP_FAIL2BAN_BLOCKED_USERS')) {
            add_action( 'authenticate',
                                    function($user, $username, $password)
                                    {
                                            if (!empty($username) && preg_match('/'.WP_FAIL2BAN_BLOCKED_USERS.'/i', $username)) {
                                                    openlog();
                                                    \syslog(LOG_NOTICE,"Blocked authentication attempt for $username from ".remote_addr());
                                                    bail();
                                            }
     
                                            return $user;
                                    },1,3);
    }
    if (defined('WP_FAIL2BAN_BLOCK_USER_ENUMERATION')) {
            add_filter( 'redirect_canonical',
                                    function($redirect_url, $requested_url)
                                    {
                                            if (intval(@$_GET['author'])) {
                                                    openlog();
                                                    \syslog(LOG_NOTICE,'Blocked user enumeration attempt from '.remote_addr());
                                                    bail();
                                            }
    
                                            return $redirect_url;
                                    },10,2); 
    }
    add_action( 'wp_login',
                            function($user_login, $user)
                            {
                                    openlog();
                                    \syslog(LOG_INFO,"Accepted password for $user_login from ".remote_addr());
                            },10,2);
    add_action( 'wp_login_failed',
                            function($username)  
                            {
                                    openlog();
                                    \syslog(LOG_NOTICE,"Authentication failure for $username from ".remote_addr());
                            });
    I looked up syslog in the PHP manual (here) which says that LOG_NOTICE has a higher priority than LOG_INFO. If anything, based on the PHP above I'd expect only the unsuccessful logins to appear in /var/log/auth.log if the log level was set to ignore the lower priority stuff.

    I've also checked syslog to see if there was anything in there... no dice.

    Can anyone with a little knowledge of PHP help me out?

    Thanks,

    Feathers
    samhobbs.co.uk

    #2
    The code would appear to be writing to /var/log/syslog. Have you checked there?

    Comment


      #3
      Originally posted by Feathers McGraw View Post
      I've also checked syslog to see if there was anything in there... no dice.
      I thought it should be writing to syslog, but the successful attempts are appearing in auth.log, and nothing is appearing in syslog :/
      samhobbs.co.uk

      Comment


        #4
        Ok I take it back, It seems that Wordpress has written it once. It just wasn't writing failed attempts when I tried it myself, deliberately using the wrong password.

        Code:
        [B]cat auth.log | grep wordpress\([/B]
        Jan 17 18:57:37 samhobbs wordpress(www.samhobbs.co.uk)[18819]: Accepted password for samhobbs from 192.168.1.1
        Jan 17 20:10:09 samhobbs wordpress(www.samhobbs.co.uk)[19151]: Accepted password for samhobbs from 192.168.1.1
        Jan 17 21:25:58 samhobbs wordpress(www.samhobbs.co.uk)[19467]: Accepted password for samhobbs from 192.168.1.1
        Jan 17 22:44:50 samhobbs wordpress(www.samhobbs.co.uk)[19769]: Accepted password for samhobbs from 192.168.1.1
        Jan 18 10:49:22 samhobbs wordpress(www.samhobbs.co.uk)[21060]: Authentication failure for dayncchaigh from 37.187.79.141
        So, now the problem is with my fail2ban configuration.

        Code:
        #/var/log/fail2ban.log
        2014-01-17 21:09:48,991 fail2ban.actions.action: ERROR  iptables -N fail2ban-wordpress
        iptables -A fail2ban-wordpress -j RETURN
        iptables -I INPUT -p tcp -m multiport --dports 80, 443 -j fail2ban-wordpress returned 200
        2014-01-18 10:49:23,756 fail2ban.actions: WARNING [wordpress] Ban 37.187.79.141
        2014-01-18 10:49:23,824 fail2ban.actions.action: ERROR  iptables -n -L INPUT | grep -q fail2ban-wordpress returned 100
        2014-01-18 10:49:23,827 fail2ban.actions.action: ERROR  Invariant check failed. Trying to restore a sane environment
        2014-01-18 10:49:23,936 fail2ban.actions.action: ERROR  iptables -N fail2ban-wordpress
        iptables -A fail2ban-wordpress -j RETURN
        iptables -I INPUT -p tcp -m multiport --dports 80, 443 -j fail2ban-wordpress returned 200
        2014-01-18 10:49:23,975 fail2ban.actions.action: ERROR  iptables -n -L INPUT | grep -q fail2ban-wordpress returned 100
        2014-01-18 10:49:23,978 fail2ban.actions.action: CRITICAL Unable to restore environment
        The plugin comes with a configuration file, the instructions for installation are:

        Code:
        == Installation ==
        
        1. Upload the plugin to your plugins directory
        1. Activate the plugin through the 'Plugins' menu in WordPress
        1. Copy `wordpress.conf` to your `fail2ban/filters.d` directory
        1. Edit `jail.local` to include something like:
        
                `[wordpress]`
                `enabled = true`
                `filter = wordpress`
                `logpath = /var/log/auth.log`
        
        1. Reload or restart `fail2ban`
        and the config file is:

        Code:
        # Fail2Ban configuration file
        #
        # Author: Charles Lecklider
        #
        
        [INCLUDES]
        
        # Read common prefixes. If any customizations available -- read them from
        # common.local
        before = common.conf
        
        
        [Definition]
        
        _daemon = wordpress
        
        # Option:  failregex
        # Notes.:  regex to match the password failures messages in the logfile. The
        #          host must be matched by a group named "host". The tag "<HOST>" can
        #          be used for standard IP/hostname matching and is only an alias for
        #          (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
        # Values:  TEXT
        #
        failregex = ^%(__prefix_line)sAuthentication failure for .* from <HOST>$
                    ^%(__prefix_line)sBlocked authentication attempt for .* from <HOST>$
                    ^%(__prefix_line)sBlocked user enumeration attempt from <HOST>$
        
        # Option:  ignoreregex
        # Notes.:  regex to ignore. If this regex matches, the line is ignored.
        # Values:  TEXT
        #
        ignoreregex =
        My /etc/fail2ban/jail.local file contains:

        Code:
        [DEFAULT]
        
        ignoreip = 127.0.0.1 192.168.1.0/24
        
        [wordpress]
        
        enabled = true
        filter = wordpress
        logpath = /var/log/auth.log
        port = 80, 443
        maxretry = 1
        bantime = 86400
        Sorry there's so much information there, I'm not sure where the problem is so I'm not sure what you need to know!

        Feathers
        samhobbs.co.uk

        Comment


          #5
          Hmm, I removed the space here between 80 and 443 and I don't get errors when restarting fail2ban any more:

          Code:
          #/etc/fail2ban/jail.local
          [DEFAULT]
          
          ignoreip = 127.0.0.1 192.168.1.0/24
          
          [wordpress]
          
          enabled = true
          filter = wordpress
          logpath = /var/log/auth.log
          [B]port = 80, 443[/B]
          maxretry = 1
          bantime = 86400
          samhobbs.co.uk

          Comment


            #6
            So all is working now, then?

            Comment


              #7
              Depends... try and log in, and we'll see

              Sent from my Nexus 7 using Tapatalk
              samhobbs.co.uk

              Comment


                #8
                Okie, didja see me?

                It failed, BTW.

                Comment


                  #9
                  Code:
                  Jan 18 22:54:03 samhobbs wordpress(www.samhobbs.co.uk)[4587]: Authentication failure for h4x0rd00d from X.X.X.X
                  This'll be you, then? I'm surprised your username didn't contain any innuendo. You're slipping, Riley.
                  samhobbs.co.uk

                  Comment


                    #10
                    Well, when I saw that photo of you on your blog, I thought, "he looks too innocent. I don't want be the complete reason for his utter corruption."

                    Comment


                      #11
                      Originally posted by SteveRiley View Post
                      Well, when I saw that photo of you on your blog, I thought, "he looks too innocent. I don't want be the complete reason for his utter corruption."
                      Good - the veneer of innocence is working, then.

                      When you say "it failed", what do you mean? You couldn't log in, or your IP address was blocked, or what? At present, I'm expecting it to take 3 attempts to result in a block.

                      Does fail2ban store failure counts somewhere on the system in a file, or does it continually read the log files to determine when to block an IP address?
                      samhobbs.co.uk

                      Comment


                        #12
                        Originally posted by Feathers McGraw View Post
                        veneer of innocence
                        Yeah, I think we all knew it's just for show. Deep down you're as twisted as the rest of us!

                        OK, I tried three times, with a little bit of SQL even. Attemps one and two returned the "invalid login" error, while attempt three just hang. Looks like Fail2Ban did its job.

                        To see current bans, run
                        Code:
                        sudo iptables -L
                        Some discussion about how Fail2Ban watches log files and builds its block files: http://stuffphilwrites.com/2013/03/p...ders-fail2ban/
                        Last edited by SteveRiley; Jan 18, 2014, 06:40 PM.

                        Comment


                          #13
                          Yep, your domain name appears there.

                          I'm just surprised that only one of those login attempts was written to the log file (initially), and yet you were still banned! Or do you mean you were banned on your second iteration, when you were using a much more appropriately suggestive username?

                          Code:
                          Jan 18 10:49:22 samhobbs wordpress(www.samhobbs.co.uk)[21060]: Authentication failure for dayncchaigh from 37.187.79.141
                          Jan 18 17:23:34 samhobbs wordpress(www.samhobbs.co.uk)[3766]: Authentication failure for admin from 86.173.246.243
                          Jan 18 22:54:03 samhobbs wordpress(www.samhobbs.co.uk)[4587]: Authentication failure for h4x0rd00d from 24.19.53.43
                          Jan 19 00:32:42 samhobbs wordpress(www.samhobbs.co.uk)[4913]: Authentication failure for insertinto from 24.19.53.43
                          Jan 19 00:32:50 samhobbs wordpress(www.samhobbs.co.uk)[4884]: Authentication failure for insertinto from 24.19.53.43
                          Jan 19 00:32:59 samhobbs wordpress(www.samhobbs.co.uk)[4844]: Authentication failure for insertinto from 24.19.53.43
                          Lol...
                          samhobbs.co.uk

                          Comment


                            #14
                            My earlier round was only a one-shot thing. The ban happened on the third shot from my second round. If Fail2Ban is banning after the third failed attempt from the same source IP address, then it makes sense that the third attempt from my second round got hung -- that would be my fourth attempt from the same source IP address, which by definition is "anything after the third."

                            Comment


                              #15
                              Thanks for the link.

                              That's cool, I just wanted to be clear on what you meant when you said it "failed" - just the login or your entire connection to the server.

                              Glad it's working, thanks for your help testing.

                              Unfortunately, you won't be able to access my turbo instructive tutorials for a few hours!! I'm sure you're inconsolable!

                              Moving on...

                              As I understand it, iptables rules don't survive a reboot. What's the best way to make sure they are restored? I've read a few things, but most of them seem to be working around Network Manager. I'm pretty sure the Pi doesn't have NM...
                              samhobbs.co.uk

                              Comment

                              Working...
                              X