Popular content management systems, such as Joomla! are under attack around the clock.

A common attack is trying out user names and passwords. If the Joomla! contains known or too simple combinations of user name and password, you can use them to break into the Joomla! and then possibly make nonsense, for example sending spam.

This article shows a way to automatically block the IP addresses from which many such login attempts are made with Fail2ban. In this example, the lock is activated after 5 incorrect logins within a period of 10 minutes, also 10 minutes after the lock is removed. This slows down automated login attempts.

The article is aimed at server administrators and web hosters.

How does the login attack take place?

The login URLs for Joomla" (and other CMS) are always the same:

  • Admin Login: www.meinejoomlaseite123.de/administrator
  • Frontend-Login: www.meinejoomlaseite123.de/index.php?option=com_users&view=login

Even if no menu item has been created for a login, the "com_users" component and the "login" view with the URL just shown can be called on any Joomla! page.

How can the login attack be detected?

Apache-Log

Normally the accesses end up in the Apache log.

For example, a login looks like this:

2003:ee:63e2:c300:: joomlatest25052018.andrehotzler.de - [25/May/2018:23:44:22 +0200] "POST /administrator/index.php HTTP/1.1" 200 2358 "https://joomlatest25052018.andrehotzler.de/administrator/index.php" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" 944 2922

This entry is of little use to us, as the following problems arise:

  • The IP address is incomplete in this example because it has been anonymized by the web hoster for data protection reasons.
  • "POST /administrator/index.php" shows a login in this example.
    Other actions in the backend create the same entry in the Apache log.
    So we cannot distinguish between "legal" use and unintentional use.

User Log

Joomla creates another log file called "error.php" by default. It is located in the "path to log folder", which can be configured under "System Settings".

Joomla! log directory
Joomla! log directory

And this is what entries in "error.php" look like after faulty logins have been performed:

12136# cat error.php
#
#<?php die('Forbidden.'); ?>
#Date: 2018-05-25 22:10:19 UTC
#Software: Joomla Platform 13.1.0 Stable [ Curiosity ] 24-Apr-2013 00:00 GMT

#Fields: datetime       priority clientip       category        message
2018-05-25T22:10:19+00:00       INFO 2003:ee:63e2:c300:a126:145c:1acb:47a5      joomlafailure   Benutzername und Passwort falsch oder das Benutzerkonto existiert noch nicht!
2018-05-25T22:10:26+00:00       INFO 2003:ee:63e2:c300:a126:145c:1acb:47a5      joomlafailure   Username and password do not match or you do not have an account yet.

As you can see, the IP address and an error message are logged in the language displayed at the login.

The entries are generated by the "User Logging" plugin:

Joomla! User Log
Joomla! User Log

If the plugin is switched off, no logging takes place. With the plugin enabled and the associated logging of the IP address, data protection aspects may have to be taken into account; a data protection expert can provide secure information here.

Fail2ban-Rule for "error.php"

The rules described here refer to Fail2ban 0.10 (with support for ipv6), tested with Joomla! 3.8.8. Under Debian/GNU Linux, the stable/oldstable/testing version can be taken from "testing". On other systems, the folders and files may have different names and must be adapted to your environment.

We need to create a filter and a jail in Fail2ban. To do this, we create the following files:

  • /etc/fail2ban/filter.d/joomla-login-errors.conf
    [Definition]
    failregex = ^.*INFO <HOST>.*joomlafailure.*(Benutzername|Username).*​
    It is important to filter only those lines that refer to the word "Username" and contain "joomlafailure". In the Regex OR rule (in brackets), the word "Username" must be entered in all languages supported by the site.
  • /etc/fail2ban/jail.d/joomla-login-errors.conf
    [joomla-login-errors]
    enabled = true
    filter = joomla-login-errors
    port   = http,https
    logpath = /var/www/*/tmp/error.php
              /var/www/*/htdocs/tmp/error.php
              /var/www/*/htdocs/logs/error.php
              /var/www/*/apps/*/error.php​
    In this jail the appropriate paths must be entered on the web server. The example here covers common paths on servers managed with Liveconfig.

Result in Fail2Ban

The following extract from the Fail2ban logfile (loglevel=3) shows the start of Fail2ban and the ban of an IP after 5 failed attempts. "banTime", "maxRetry" etc. are standard values in this example.

2018-05-26 00:21:29,814 fail2ban.server         [302]: INFO    Starting Fail2ban v0.10.2
2018-05-26 00:21:29,816 fail2ban.database       [302]: INFO    Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2018-05-26 00:21:29,833 fail2ban.jail           [302]: INFO    Creating new jail 'joomla-login-errors'
2018-05-26 00:21:29,834 fail2ban.jail           [302]: INFO    Jail 'joomla-login-errors' uses poller {}
2018-05-26 00:21:29,834 fail2ban.jail           [302]: INFO    Initiated 'polling' backend
2018-05-26 00:21:29,851 fail2ban.filter         [302]: INFO    Added logfile: '/var/www/joomlatest/htdocs/logs/error.php' (pos = 0, hash = 9762053d4defb8be822cb0957983a6b8796976d6)
2018-05-26 00:21:29,866 fail2ban.filter         [302]: INFO      encoding: UTF-8
2018-05-26 00:21:29,866 fail2ban.filter         [302]: INFO      maxRetry: 5
2018-05-26 00:21:29,866 fail2ban.filter         [302]: INFO      findtime: 600
2018-05-26 00:21:29,866 fail2ban.actions        [302]: INFO      banTime: 600
2018-05-26 00:21:29,868 fail2ban.jail           [302]: INFO    Jail 'joomla-login-errors' started
2018-05-26 00:21:43,934 fail2ban.filter         [302]: INFO    [joomla-login-errors] Found 2003:ee:63e2:c300:a126:145c:1acb:47a5 - 2018-05-26 00:21:43
2018-05-26 00:21:47,147 fail2ban.filter         [302]: INFO    [joomla-login-errors] Found 2003:ee:63e2:c300:a126:145c:1acb:47a5 - 2018-05-26 00:21:46
2018-05-26 00:21:48,352 fail2ban.filter         [302]: INFO    [joomla-login-errors] Found 2003:ee:63e2:c300:a126:145c:1acb:47a5 - 2018-05-26 00:21:48
2018-05-26 00:21:49,556 fail2ban.filter         [302]: INFO    [joomla-login-errors] Found 2003:ee:63e2:c300:a126:145c:1acb:47a5 - 2018-05-26 00:21:49
2018-05-26 00:21:53,569 fail2ban.filter         [302]: INFO    [joomla-login-errors] Found 2003:ee:63e2:c300:a126:145c:1acb:47a5 - 2018-05-26 00:21:53
2018-05-26 00:21:53,907 fail2ban.actions        [302]: NOTICE  [joomla-login-errors] Ban 2003:ee:63e2:c300:a126:145c:1acb:47a5