Shell Script to Prevent SSH and vsftpd Brute-Force Attacks (v2)

             On a newly deployed FTP backup server, a routine check of the /var/log/secure log revealed numerous failed authentication attempts for both sshd and vsftpd. It was obvious someone was trying to brute-force passwords, so a security script needed to be written to prevent this.

The script requirements are as follows: This SHELL script is placed in a crontab scheduled task and runs every 6 hours (this interval can be defined based on actual circumstances) to read the /var/log/secure log. It extracts malicious IPs that are attempting to guess passwords. If the number of connections within a specific time unit (one week) exceeds a threshold, for example, 100 (this threshold can also be defined based on actual circumstances), the IP is added to the /etc/hosts.deny blacklist. If it falls below this threshold, the IP is ignored.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/var/log/secureThe failed authentication information inside is as follows:
Nov 28 10:18:08 centos2 sshd[7556]: Connection closed by 222.216.30.109
Nov 28 10:18:08 centos2 sshd[7557]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=222.216.30.109 user=root
Nov 28 10:18:09 centos2 sshd[7559]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=222.216.30.109 user=root
Nov 28 10:18:10 centos2 sshd[7551]: Failed password for root from 222.216.30.109 port 2391 ssh2
Nov 28 10:18:10 centos2 sshd[7552]: Connection closed by 222.216.30.109
Nov 28 10:18:10 centos2 sshd[7553]: Failed password for root from 222.216.30.109 port 2397 ssh2
Nov 28 10:18:10 centos2 sshd[7554]: Connection closed by 222.216.30.109
Nov 28 10:18:11 centos2 sshd[7557]: Failed password for root from 222.216.30.109 port 2401 ssh2
Nov 28 10:18:11 centos2 sshd[7558]: Connection closed by 222.216.30.109
Nov 28 10:18:11 centos2 sshd[7559]: Failed password for root from 222.216.30.109 port 2403 ssh2
Nov 28 10:18:11 centos2 sshd[7560]: Connection closed by 222.216.30.109
Nov 28 10:37:01 centos2 vsftpd: pam_unix(vsftpd:auth): check pass; user unknown
Nov 28 10:37:01 centos2 vsftpd: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=hello rhost=centos1.cn7788.com
Nov 28 10:37:01 centos2 vsftpd: pam_succeed_if(vsftpd:auth): error retrieving information about user hello
Nov 28 10:37:19 centos2 vsftpd: pam_unix(vsftpd:auth): check pass; user unknown
Nov 28 10:37:19 centos2 vsftpd: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=yhc rhost=centos1.cn7788.com
Nov 28 10:37:19 centos2 vsftpd: pam_succeed_if(vsftpd:auth): error retrieving information about user yhc
Nov 28 10:37:36 centos2 vsftpd: pam_unix(vsftpd:auth): check pass; user unknown
Nov 28 10:37:36 centos2 vsftpd: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=yuhongchun rhost=centos1.cn7788.com
Nov 28 10:37:36 centos2 vsftpd: pam_succeed_if(vsftpd:auth): error retrieving information about user yuhongchun
Nov 28 10:42:44 centos2 vsftpd: pam_unix(vsftpd:auth): check pass; user unknown
Nov 28 10:42:44 centos2 vsftpd: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=yuhongchun rhost=114.112.169.70
Nov 28 10:42:44 centos2 vsftpd: pam_succeed_if(vsftpd:auth): error retrieving information about user yuhongchun
Nov 28 10:42:56 centos2 vsftpd: pam_unix(vsftpd:auth): check pass; user unknown
Nov 28 10:42:56 centos2 vsftpd: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=andrewyu rhost=114.112.169.70
Nov 28 10:42:56 centos2 vsftpd: pam_succeed_if(vsftpd:auth): error retrieving information about user andrewyu

Let’s observe the log rotation pattern of /var/log/secure, as shown below:

1
2
3
4
5
ls -lsart secure.*
512 -rw------- 1 root root 516379 11-04 01:31 secure.4
660 -rw------- 1 root root 668192 11-11 00:05 secure.3
304 -rw------- 1 root root 306589 11-17 10:33 secure.2
484 -rw------- 1 root root 488620 11-25 02:33 secure.1

Basically, the /var/log/secure file rotates on a weekly basis. For those with strict security requirements, you can also follow a “leave no one behind” principle to capture malicious IPs from older secure logs and then dump them into the /etc/hosts.deny file. Next, we need to figure out how to efficiently capture these malicious IPs. If we refer to the original version of the SHELL script, to capture the IP addresses probing the vsftpd and sshd services from the secure log,

we can use the following command:

1
cat /var/log/secure | awk '/Failed/{print $(NF-3)}'| sort| uniq -c| awk '{print $2"="$1;}'

Obviously, this won’t capture the failed IP values for vsftpd. The failure information in the sshd log differs from that in the vsftpd log. I wrote several methods combining awk and sed, and after testing their efficiency, I felt that using an awk script is the fastest. You can also write a few variations and test them with the time command. Finally, I streamlined the code and completed the entire script. The script

content is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
awk '{for(i=1;i<=NF;i++){if($i ~ /rhost/)print substr($i,7)}}' /var/log/secure | sort | uniq    -c>/root/black.txt
DEFINE="100"
cat     /root/black.txt |    while read LINE
do
               NUM=`echo $LINE |awk '{print $1}'`
               host=`echo $LINE    |awk '{print $2}'`
               if [ $NUM -gt $DEFINE ];
               then
                grep $host    /etc/hosts.deny > /dev/null
                   if [ $? -gt 0 ];
                   then
                   echo "sshd:$host"     >> /etc/hosts.deny
                   echo "vsftpd:$host" >> /etc/hosts.deny
                   fi
               fi
done

 

After the script has been running for a while, we can inspect some of the files involved, such as /root/black.txt,the results will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat /root/black.txt
               2 113.17.144.156
               4 114.112.51.208
               4 114.112.69.170
           169 118-163-227-50.hinet-ip.hinet.net
               8 119.188.7.200
               8 122.70.130.11
            61 124.248.32.246
            12 183.203.14.121
               3 189.26.255.11
            56 199.204.237.60
               3 199.30.53.220
               5 201.236.80.4
               6 220.172.191.31
            30 222.216.30.109
            60 222.253.159.111
            58 223.4.180.23
           166 58.221.42.178
               1 61.132.4.85
           152 61.142.106.34
            22 61.167.33.222
               7 85.126.166.83
           166 www.b-nets.com

 

The /etc/hosts.deny script content is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sshd:124.248.32.246
vsftpd:124.248.32.246
sshd:199.204.237.60
vsftpd:199.204.237.60
sshd:222.253.159.111
vsftpd:222.253.159.111
sshd:223.4.180.23
vsftpd:223.4.180.23
sshd:58.221.42.178
vsftpd:58.221.42.178
sshd:61.142.106.34
vsftpd:61.142.106.34
sshd:118-163-227-50.hinet-ip.hinet.net
vsftpd:118-163-227-50.hinet-ip.hinet.net
sshd:www.b-nets.com
vsftpd:www.b-nets.com

 

Finally, we put this shell script into crontab to run every six hours, with the following command:

1
* */6 * * * root /bin/bash /root/hostsdeny.sh >> /dev/null 2>&1

Since the /var/log/secure log rotates on a weekly basis, the execution frequency of this script can be set as needed. If you feelthe server is being probed frequently, the execution interval can be set shorter; otherwise, it can be set longer.Note: If you only want to prevent SSH brute-force attacks, this script doesn’t need to be updated; you can adopt my originalSHELL script (i.e., the original version). This updated script is suitable for deployment on public-facing machines with FTP. It has been testedand is relatively stable, but I feel there is still room for improvement. You are welcome to email me for discussion, Yu Hongchun([email protected]).

This article is from the “抚琴煮酒” blog. Please be sure to retain this source: http://andrewyu.blog.51cto.com/1604432/1074650

Leave a Comment

Your email address will not be published.