• Delicious
  • Sales: 0800 634 6513
    General: 0845 053 0371

news and info

Block login attacks with abuseIPDB

VPOP3 will automatically block IP addresses which repeatedly try to log in with an incorrect username or password. However, to prevent blocking users who accidentally enter the wrong details for too long, this usually just blocks the IP address for a few minutes (the default is 30 minutes).

There is an online database at https://www.abuseipdb.com/ which is used by many organisations to report abusive IP addresses. This database has an API which is free for low usage (1000 or 3000 calls a day). The data from multiple users is amalgamated to give a confidence of abuse from a particular IP address. That means that if just one or two services report problems, it could be accidental failed logins or similar, so we can ignore it, but if many report problems it is more likely to be deliberate attacks, so we can take action.

This article is about using the abuseIPDB database to identify failed login attempts to VPOP3 and then blocking those IP addresses for longer periods. We will use some Lua scripting to report failed logins to abuseIPDB then utilise the ‘GeoIP’ facility in VPOP3 to block those IP addresses that are rated at ‘100%’ by abuseIPDB.

This script requires VPOP3 Enterprise v8.1 or later.

Sign up to abuseIPDB

The first step is to sign up for an abuseIPDB account. For most VPOP3 users, their free account will suffice. You can increase the free account’s 1000 API-calls-a-day limit to 3000 API calls a day if you have your own website and change the account to a ‘webmaster’ account.

To sign up for an abuseIPDB account, go to https://www.abuseipdb.com/pricing

Once you have the account, you can go to your account settings and sign up as a ‘webmaster’ user if you wish – just follow the instructions (it involves uploading a small file to a special location on your web server)

You will now need to generate an API key so that our script can report and check data on IP addresses. To do this, in your abuseIPDB account, go to the ‘API’ tab, and click on ‘Create Key’. The key is a long alphanumeric string.

Create new database tables in VPOP3

We want to create a new database table in VPOP3 so that we can track when we have blocked IP addresses, so that they can be automatically be removed after a certain amount of time.

To do this, on your VPOP3 server, go to a command prompt and navigate to the VPOP3 directory, then type ‘psql’

In the psql prompt, type:

create table geoipv4_autoblocks (addr inet, dateadded timestamp with time zone default now());
create table abuseipdb (addr inet, dateadded timestamp with time zone default now());

geoipv4_autoblocks contains the IP address and when it was added to the block list. This will be used to automatically remove blocks after a specified time.

This creates two database tables for the script to use.

abuseipdb contains IP addresses and when they were reported to abuseIPDB, so that VPOP3 will only report addresses a maximum of once per day.

Create Lua Script

In the VPOP3 settings, go to Settings -> Scripts and choose the ‘Scheduler.lua’ script from the drop-down box. For this article we will assume that there is nothing in that script. If you already have functions in this script, then you may need to modify those by adding the script here, rather than replacing or adding it.

The Scheduler.lua script can contain functions which VPOP3 will periodically run in the background. We will use this to have VPOP3 check the failed logins log database table every five minutes and act accordingly.

In this script, copy and paste the function as below (again, if you already have a ‘Sched5Min’ function, you will need to modify it accordingly):

function Sched5Min()
-- Script options
abuseipdbApikey = "<your API key>";
notificationEmail = "<your email address>";
triggerCount = 3;
purgeDays = 365;

-- delete IP addresses from the abuseipdb table after 1 day
VPOP3.PostgresQuery("delete from abuseipdb where dateadded < now() - interval '1 day';");

-- delete IP addresses from the blocklist after 'purgeDays' days
-- use a local variable for the date to purge before rather than a PostgreSQL formula 
-- to avoid race condition
purgeDate = os.date("%Y-%m-%d %H:%M:%S", os.time() - purgeDays * 24 * 60 * 60);
VPOP3.PostgresQuery(string.format([[with x as (select addr from geoipv4_autoblocks where dateadded < '%s') delete from geoipv4 using x where addr=addrfrom and result='block';]], purgeDate));
VPOP3.PostgresQuery(string.format("delete from geoipv4_autoblocks where dateadded < '%s';", purgeDate));

-- Find IP addresses which have had more than triggerCount failed logins over the past day
-- and have not yet been reported today
x = VPOP3.PostgresQuery(string.format([[with x as (select ipaddress, username, count(*) cnt, min(datetime) as datetime from loginaudit where not result and datetime>now()-interval '1 day' group by ipaddress,username) select count(*) usercount, sum(cnt) failcount, ipaddress, min(datetime) as datetime from x where ipaddress not in (select addr from abuseipdb) group by ipaddress having count(*)>=%d limit 10;]], triggerCount));

-- Process database query results
if x.Rows and x.Rows > 0 then
  for ind = 1,x.Rows do
-- report the IP address to abuseipdb and get the address status
    res = VPOP3Net.PostHTTP("https://api.abuseipdb.com/api/v2/report",
      {key=abuseipdbApikey, ip=x[ind]["ipaddress"], categories="18",
      comment= string.format("Email Auth Brute force attack %d/%d in last day", 
          x[ind]["failcount"], x[ind]["usercount"])});
    print('Post Result ', res.ErrorCode, res.HTTPResult);

    if res.ErrorCode == 0 and type(res.Body[1]) == "string" then
-- If the IP address status has a rating of 100% then do stuff
      if string.find(res.Body[1], "\"abuseConfidenceScore\":100") then
-- Notify the administrator if an email address is specified
        if notificationEmail then
          VPOP3.SendMessage(notificationEmail, notificationEmail, 
            string.format("Login Attack - %s", x[ind]["ipaddress"]), 
            string.format([[Failed logins from %s
result = %s"]], x[ind]["ipaddress"], x[ind]["ipaddress"], res.Body[1]));

-- Add the IP address to the GeoIP table                
        VPOP3.PostgresQuery(string.format("insert into geoipv4 (addrfrom, addrto, result) values('%s','%s', 'block');", x[ind]["ipaddress"], x[ind]["ipaddress"]));
-- Add the IP address to the geoipv4_autoblocks table
        VPOP3.PostgresQuery(string.format("insert into geoipv4_autoblocks (addr) values('%s');", x[ind]["ipaddress"])); 

-- if the HTTP Post to abuseIPDB succeeded, then remember that we have reported the IP address, 
-- so we don't do it again for another day
      VPOP3.PostgresQuery(string.format("insert into abuseipdb (addr) values('%s');", x[ind]["ipaddress"]));

You can change the first few lines of this function to meet your requirements. You MUST set the abuseIPDB API key and your email address as appropriate.

If you don’t want to receive notification emails, change the ‘notificationEmail’ line to:
notificationEmail = nil;

The ‘triggerCount’ value is the number of different failed usernames attempted over the past day which will trigger notification. The ‘purgeDays’ value is how long IP addresses will be blocked for if blocked by this script.

Block IP addresses

The Lua script above will create ‘GeoIP’ entries in VPOP3 with the identifier of ‘block’ if it sees repeated failed login attempts and the IP address has a 100% rating on abuseIPDB.

To use these to actually block IP addresses from trying to log into VPOP3, we need to go to the appropriate Services in the VPOP3 settings, go to the ‘IP Access Restrictions’ tab and add a new restriction to ‘block’ addresses using GeoIP lookup where the search result is ‘block’

You can add this IP Access Restriction to multiple services as you wish – eg the POP3, SMTP and IMAP4 services

Post a Comment