PF-Playing with spam login attempts

edited July 2016 in phpFox

I see a lot of failed login attempts on my practically inactive site. Something like 300 per day try to login with really weird usernames that surly would never work.

The problem is that this activity uses bandwidth and someday they might get lucky and get in. They would be disappointed, but that's not the point. I just hate this kind of stuff.

I thought that maybe I could make a small plugin to cause them some headaches. Maybe I could monitor the user_ip table for a type_id of 'login_failed' and perform some kind of action if I found a large number of failed login attempts or login attempts within 0 - 1 seconds apart (too fast to be a real person).

After I identify the ip, I need to do something with it so that it will be quickly accessible for the code that will limit access to the site. For this, I decided to create a cache file with JSON data stored within.

Then, I did a plugin file as close to the start as possible that would catch the abuser and present them with a simple, low bandwidth page. I have placed this on my site and will have to wait a bit to see if the failed login rate decreases.

The changes are two plugins. The first one is:

user.service_auth_login__start.php

$iFailLimit=100;  //Set this to your login fail limit
$sIp=phpfox::getIp();
$sFile = PHPFOX_DIR_CACHE."login_fail.php";
$bBad=FALSE;

$aFails = $this->database()->select('time_stamp')
        ->from(Phpfox::getT('user_ip'))
        ->where('type_id = "login_failed" AND ip_address = "'.$sIp.'"')
        ->order('time_stamp ASC')
        ->execute('getRows');

$iCount=0;
$iTime1=0;

// Look for excess bad logins or logins within 1 second of each other
// If found, flag with $bBad
foreach($aFails as $sFail) {
    $iCount++;
    if($iCount > $iFailLimit ||  (int)$sFail['time_stamp'] == $iTime1 || (int)$sFail['time_stamp'] == $iTime1+1) {
        $bBad=TRUE;
        break;
    }
    $iTime1=(int)$sFail['time_stamp'];
}

// If greater than the set limit, do something
if($bBad) {

    // If the reference file does not exist, gather all of the violators and create file
    if(!file_exists($sFile)) {
        $aExcess = $this->database()->select('COUNT(*) AS count, ip_address')
        ->from(Phpfox::getT('user_ip'))
        ->where('type_id = "login_failed"')
        ->group('ip_address')
        ->order('count DESC')
        ->execute('getRows');

        foreach($aExcess as $aExcessRec) {
            if($aExcessRec['count'] > $iFailLimit) {
                $aExcessMod[$aExcessRec['ip_address']]=$aExcessRec['count'];
            }
        }

        $sData = json_encode($aExcessMod);
        $bGood=file_put_contents($sFile, $sData);

        // Otherwise Add this ip to the reference file
        } else {

        $sCurrent = file_get_contents($sFile);
        $aCurrent = json_decode($sCurrent, true);
        $aCurrent[$sIp] = $iCount;
        $sData = json_encode($aCurrent);
        $bGood=file_put_contents($sFile, $sData);
    }
}

This will create or write to the cache file.

Then, to prevent the abusers from having access to the site, the second plugin will be:
init.php

if(file_exists(PHPFOX_DIR_CACHE.'login_fail.php')) {
    $sLoginFail=file_get_contents(PHPFOX_DIR_CACHE.'login_fail.php');
    $aWWela=json_decode($sLoginFail, true);
} else {
    $aWWela=array();
}

if (array_key_exists($_SERVER['REMOTE_ADDR'], $aWWela)) {

    ?>

    <head>
    </head>
    <body style="background-color:004488;">
        <p style="font-size:32px;color:red;text-align:center;">
        You have too many failed login attempts.  
        </p>
        <p style="font-size:24px;color:red;text-align:center;">
        From this fact I can only assume that you are not acting in the best interest of this website.<br />Please do not attempt any further login attempts.
        </p>
    </body>

    <?php
    die();
}

This has been quickly tested and seems to work okay. If you get locked out from this plugin, you can ftp to the cache and open the login_fail.php file to manually remove your ip address. You can also clear the cache. Removing the plugin files will restore the system to normal operation.

Here is where I place the standard disclaimer about me not being liable for nothin'.

Tagged:
data66

Comments

  • LOL to the disclaimer. Great tutorial as always!

  • Yes, glad you are still with us Webwolf...even with the disclaimer :wink:

    data66
  • Wow, after I started playing with this I kind of went ocd on it. I found that many spam requests occurred in pairs with only 0-2 seconds between them. This seemed like a good way to tag spam sign-ins, so I added some code to catch those attempts and add the IPs to the file. Then I thought it might be a good idea to, when a violator is identified, do a query to find other ips with either the same username or password and ban those ips also.

    I also started worrying about using a page to tip off the spammers that they had been identified, so instead of catching and redirecting at init, I just did it all in the auth service plugin. I set the $bReturn flag and error message so the login request does not get processed at all, but returns with a normal login failed message. I doubt that spammers will give up, but this may make them continue with a futile effort instead of trying to defeat the new measures.

    Finally, I added a honeypot to the login form. It is a hidden text input element that a real human will not see, but a bot will. In it's logic, any form element should be filled in, so it will put something in the field. If the plugin finds an entry in that field, it immediately adds that ip to the ban list.

    It is still early, but I normally get around 300 login attempts that fail daily. today it is setting at 39.

    data66
  • edited July 2016

    Are you going to put it as an add on in the ST marketplace with the new stuff you added? Sounds like a handy add on. Is it for v3?

  • Okay, well now that I have the fun stuff done you are tasking me with the work part. There is more to the whole package in that I already had some extra fields in the user_ip table with a failed login report in the admincp. While working on this I added two more reports, Banned login attempts and IPs banned list with an unban option. This may need to be done as a product. I will look into this.

    data66
  • The product is ready and is available at my website. I have set a selling price of 0. Try it and,if you like it you can buy me a beer.

    It was tested for versions 2.0.7, 3.0, 3.9, and 4.4.0.

    data66
  • You can link to it here if you want to. I don't mind. :)

  • Thanks Data. You can find the product here:
    http://webwolfs-foxmods.com/product/nobots/

    I am cell phoning at this time, so I don't want to get too fancy.

    data66
Sign In or Register to comment.