· 6 years ago · Jul 11, 2019, 11:08 AM
1# Centralize Fail2Ban
2
3## Warding potential server attacks with a centralized Fail2Ban
4
5### System Requirements
6This HowTo assumes that fail2ban, iptables, mysql and php is installed functional on the system.
7On Ubuntu, you can quickly do:
8
9```bash
10root@devserv3:~# sudo apt-get install php5 mysql-server fail2ban iptables
11```
12
13Next, we have to create a database in MySql, the database called "fail2ban". In this database, a table is created:
14
15```sql
16CREATE TABLE IF NOT EXISTS `fail2ban` (
17 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
18 `hostname` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
19 `created` datetime NOT NULL,
20 `name` text COLLATE utf8_unicode_ci NOT NULL,
21 `protocol` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
22 `port` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
23 `ip` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
24 PRIMARY KEY (`id`),
25 KEY `hostname` (`hostname`,`ip`)
26) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
27
28```
29
30### PHP script for passing the fail2ban IP
31Now comes a small PHP script to use, which will accept the IP address, port, protocol, and the fail2ban Jailnamen and writes to the MySQL database.
32The PHP script is created in the directory: /root and we make it executable. In addition, read permissions should be revoked for unauthorized persons!
33```
34root@devserv3:~# cd /root && touch fail2ban.php && chmod +x fail2ban.php
35```
36
37fail2ban.php is filled with the following content:
38
39```php
40#!/usr/bin/php -n
41<?php
42$name = $_SERVER["argv"][1];
43$protocol = $_SERVER["argv"][2];
44$port = $_SERVER["argv"][3];
45if (!preg_match('/^\d{1,5}$/', $port))
46 $port = getservbyname($_SERVER["argv"][3], $protocol);
47$ip = $_SERVER["argv"][4];
48
49$hostname = gethostname();
50
51// connect to mysql by hostname, username and password
52$link = mysql_connect('devserv3', 'fail2ban', 'password') or die('Could not connect: ' . mysql_error());
53mysql_select_db('fail2ban') or die('Could not select database');
54$query = 'INSERT INTO `fail2ban` set hostname="' . addslashes($hostname) . '", name="' . addslashes($name) . '", protocol="' . addslashes($protocol) . '", port="' . addslashes($port) . '", ip="' . addslashes($ip) . '", created=NOW()';
55$result = mysql_query($query) or die('Query failed: ' . mysql_error());
56mysql_close($link);
57exit;
58```
59
60Now you can test the script and check if datas in database arrive.
61
62```
63root@devserv3:~# ./fail2ban.php jailname ssh 22 123.123.123.123
64```
65
66### Connection to Fail2Ban
67If the script works we can create the connection to Fail2Ban.
68To do this, change to the fail2ban configuration directory.
69
70```
71root@devserv3:~# cd /etc/fail2ban/ && ls -al
72total 28
73drwxr-xr-x 4 root root 4096 Feb 13 14:56 .
74drwxr-xr-x 97 root root 4096 Feb 13 15:28 ..
75drwxr-xr-x 2 root root 4096 Feb 13 14:56 action.d
76-rw-r--r-- 1 root root 853 Nov 29 2011 fail2ban.conf
77drwxr-xr-x 2 root root 4096 Feb 13 14:56 filter.d
78-rw-r--r-- 1 root root 7346 Jun 18 2013 jail.conf
79root@devserv3:/etc/fail2ban#
80```
81
82In the files jail.conf and jail.local (must not be present), the jails and the banaction are defined.
83Here once the example from Jail "pam-generic".
84
85```ini
86[pam-generic]
87enabled = true
88filter = pam-generic
89port = all
90banaction = iptables-multiport
91logpath = /var/log/auth.log
92```
93
94The line with the banaction sets with which action the IP to be treated.
95If no banaction at Jail specified, the default banaction is used. This is defined in the same file, in the [DEFAULT]. In general, the action is the iptables-multiport.
96In the action folder "action.d" the file iptables multiport.conf should be found.
97This file is now extended that, when a IP is banned then also our PHP script is called. Calling all parameters such as IP, port, etc. are passed.
98After the line with actionban = ..... a new row inserted to invoke the PHP script:
99
100```
101actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP /root/fail2ban.php <name> <protocol> <port> <ip>
102```
103
104Now fail2ban even have to be restarted. In the fail2ban logs can be checked whether there was an error.
105```
106root@devserv3:~# /etc/init.d/fail2ban restart
107root@devserv3:~# cat /var/log/fail2ban.log
108```
109
110From now on, intrusions are detected and logged in the database.
111In the second part of the HOWTO (coming soon) will be described how to distribute the IP addresses from the database on another server.
112
113Now the Fail2Ban configuration file will be prepared. For this purpose, the supplied with Fail2Ban file is copied and edited (Nano is the editor) opened.
114
115```
116cd /etc/fail2ban && cp jail.conf jail.local && nano jail.local
117```
118
119In the jail.local a jail at the end of the default block is inserted. The name of the jail "blocklist"
120
121```ini
122[blocklist]
123enabled = true
124port = ssh
125filter = sshd
126logpath = /etc/fail2ban/empty.log
127maxretry = 1
128banaction = iptables-allports
129action = %(action_)s
130```
131
132With this blocklist we define a file /etc/fail2ban/empty.log to be monitored. The maximum break-in attempt is set to 1, so that the first appearance of an IP address will be blocked. The type of blocking is set with banaction and means in the example a blocking of the IP on all ports.
133For the attacker behind the locked IP, the server is no longer accessible. Here it is important to ensure that you do not lock out yourself!
134
135Now must Fail2Ban be restarted once and it can be tested whether Fail2Ban IP takes in the blocklist.
136For this purpose, an IP address will be passed to Fail2Ban to be locked and a "-" is written into emptly-log to indicate a change to Fail2Ban. Then Fail2Ban will block the given IP.
137
138```
139root@devserv3:~# service fail2ban restart
140 * Restarting authentication failure monitor fail2ban [ OK ]
141```
142
143```
144fail2ban-client set blocklist banip 1.168.100.1 echo "-" > /etc/fail2ban/empty.log;
145```
146If there was no error message has all worked out. If an error occurs take a look in the log file to get more informations (/var/log/fail2ban.log). In iptables, the IP should now be also listed.
147
148```
149root@devserv3:~# iptables -L
150Chain INPUT (policy ACCEPT)
151target prot opt source destination
152fail2ban-blocklist tcp -- anywhere anywhere
153fail2ban-ssh tcp -- anywhere anywhere multiport dports ssh
154
155Chain FORWARD (policy ACCEPT)
156target prot opt source destination
157
158Chain OUTPUT (policy ACCEPT)
159target prot opt source destination
160
161Chain fail2ban-blocklist (1 references)
162target prot opt source destination
163DROP all -- 1-168-100-1.dynamic.hinet.net anywhere
164RETURN all -- anywhere anywhere
165
166Chain fail2ban-ssh (1 references)
167target prot opt source destination
168RETURN all -- anywhere anywhere
169```
170
171### PHP script to get the IP from the database
172Now a small PHP script is used, the read from the central database, the IP addresses.
173To prevent that all IP addresses are repeatedly read from the database, the database column "created" be used as a helper. So only the entries of the last 60 seconds are fetched in the script.
174The name of the script is fail2ban.get.php
175
176```php
177#!/usr/bin/php -n
178<?php
179// connect to mysql by hostname, username and password
180$link = mysql_connect('devserv3', 'fail2ban', 'password') or die('Could not connect: ' . mysql_error());
181mysql_select_db('fail2ban') or die('Could not select database');
182$query = 'SELECT ip FROM `fail2ban` where created>DATE_ADD(NOW(), INTERVAL -60 SECOND)';
183$result = mysql_query($query) or die('Query failed: ' . mysql_error());
184$cmd = null;
185while ($row = mysql_fetch_object($result)) {
186 $cmd .= 'fail2ban-client set blocklist banip ' . $row->ip . ' && ';
187}
188if ($cmd) {
189 $cmd .= "echo \"-\" > /etc/fail2ban/empty.log";
190 $cmd = $cmd . ' >/dev/null 2>/dev/null &';
191 exec($cmd, $output, $returnValue);
192}
193mysql_close($link);
194exit;
195```
196
197Now briefly test the script ....
198```
199root@devserv3:~# ./fail2ban.get.php
200```
201
202No error ? Great.
203Now we put the script into a cron job, so it is called every minute and read IP's to lock. The call cycle can also raise, if it is should not be any minute - but then adjust accordingly the 60 seconds in the script.
204We modify with nano this file: /etc/crontab and add the following at the end.
205
206```
207*/1 * * * * root nice -n 19 /usr/bin/php -c /etc/php5/apache2/php.ini -f /root/fail2ban.get.php > /dev/null 2>&1
208```
209
210Ready.