Sunday, September 30, 2018

Rate limit SSH access using IPTables/Firewalld to counter Brute Force attacks.

Hello Guys,

The Public IP ranges of Cloud Platforms like Amazon AWS, Oracle OCI, Microsoft Azure are published in Public. If you have an instance with open SSH rules lets say, Security Group on AWS, Security List on Oracle OCI, I am very sure that you have seen SSH break in attempts like below.


Sep 30 12:29:47 host sshd[9731]: Invalid user admin from 222.173.30.222 port 3644
Sep 30 12:29:47 host sshd[9731]: input_userauth_request: invalid user admin [preauth]
Sep 30 12:29:48 host sshd[9731]: Connection closed by 222.173.30.222 port 3644 [preauth]
Sep 30 12:36:22 host sshd[9779]: Invalid user ftpuser from 202.28.33.166 port 58268
Sep 30 12:36:22 host sshd[9779]: input_userauth_request: invalid user ftpuser [preauth]
Sep 30 12:36:22 host sshd[9779]: Received disconnect from 202.28.33.166 port 58268:11: Normal Shutdown, Thank you for playing [preauth]

NB: I am leaving those IPs from my logs here as they were causing troubles!

this clearly tells us that you need to reconsider the security settings on your cloud network. Ideally, sensitive ports like SSH (TCP/22) should be opened up only to trusted IPs or IP Networks. However, this might not be possible if the customer has users accessing the instance from various location. 

At times these attacks can become so severe, it slows down your instance and could end up crashed due to kernel Out of Memory Killer (OOM Killer) or because of CPU starving.


Setting up rate limiting rules using IPTables/Firewall on TCP/22 can help in reducing the effect of brute force attacks. But I should remind you that rate limiting is not the solution, you should consider accessing the instance via a bastion host for safe guarding the data and ensuring security best practices. 

Let’s check out how to make use of IPTables, Firewalld to set rate-limit rules to reduce brute force attacks.

Modern operating systems flavours like OEL7, RHEL7, CentOS7 uses Firewalld. Older OS flavours use IPTables. Let’s check out how to set rate-limit rules using both.

 

Using Firewalld:


The below sets rate limiting rules temporarily:

# firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp -m tcp --dport 22 -m recent --update --seconds 180 --hitcount 3 --rttl --name SSH --rsource -m comment --comment "SSH Brute-force" -j LOG --log-prefix "SSH_brute_force"

# firewall-cmd --direct --add-rule ipv4 filter INPUT 1 -p tcp -m tcp --dport 22 -m recent --update --seconds 180 --hitcount 3 --rttl --name SSH --rsource -m comment --comment "SSH Brute-force" -j DROP

# firewall-cmd --direct --add-rule ipv4 filter INPUT 2 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH --rsource -m comment --comment "SSH Brute-force" -j ACCEPT

# firewall-cmd --zone=public --remove-service=ssh

Once the above rules are set, do test the rules yourself. Try logging in to the instance from a new session and make sure you are able to SSH in. Please do not close the existing session to revert the changes in case you get locked out. If the above rules are set properly, with in 3 minutes you will be able to SSH in to the instance 3 times and the 4th attempt will be blocked.


Logging:
The rules logs the blocked SSH attempt in "/var/log/messages" as follows:

# grep SSH_brute_force /var/log/messages  | tail -5
Aug 27 13:30:10 test kernel: SSH_brute_forceIN=ens3 OUT= MAC=02:00:17:00::00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=20404 DF PROTO=TCP SPT=37076 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0
Aug 27 13:30:11 test kernel: SSH_brute_forceIN=ens3 OUT= MAC=02:00:17:00::00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=20405 DF PROTO=TCP SPT=37076 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0
Aug 27 13:30:13 test kernel: SSH_brute_forceIN=ens3 OUT= MAC=02:00:17:00::00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=20406 DF PROTO=TCP SPT=37076 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0
Aug 27 13:30:17 test kernel: SSH_brute_forceIN=ens3 OUT= MAC=02:00:17:00::00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=20407 DF PROTO=TCP SPT=37076 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0
Aug 27 13:30:25 test kernel: SSH_brute_forceIN=ens3 OUT= MAC=02:00:17:00::00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=20408 DF PROTO=TCP SPT=37076 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0



You may make the rules permanent once you have completed testing:

# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp -m tcp --dport 22 -m recent --update --seconds 180 --hitcount 3 --rttl --name SSH --rsource -m comment --comment "SSH Brute-force" -j LOG --log-prefix "SSH_brute_force: "

# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 1 -p tcp -m tcp --dport 22 -m recent --update --seconds 180 --hitcount 3 --rttl --name SSH --rsource -m comment --comment "SSH Brute-force" -j DROP

# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 2 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH --rsource -m comment --comment "SSH Brute-force" -j ACCEPT


You may also remove the SSH service from the public zone.
# firewall-cmd --permanent --zone=public --remove-service=ssh


Using IPTables:

Older OEL/RHEL/CentOS uses IPTables instead on Firewalld. Here is the iptables rules for SSH rate limiting.

# iptables -N LOGDROP
# iptables -A LOGDROP -j LOG
# iptables -A LOGDROP -j DROP
# iptables -I INPUT 4 -p tcp --dport 22 -i ens3 -m state --state NEW -m recent --set
# iptables -I INPUT 5 -p tcp --dport 22 -i ens3 -m state --state NEW -m recent  --update --seconds 180 --hitcount 3 -j LOGDROP --log-prefix="SSH Brute-force: "


Logging:
The rules log the blocked SSH attempt in "/var/log/messages" as follows:

# grep "DPT=22" /var/log/messages | tail -5
Aug 27 13:54:14 test kernel: IN=ens3 OUT= MAC=02:00:17:00:74:b2:00:00:17:85:9a:40:08:00 SRC=160.XX.XX.133 DST=10.0.0.35 LEN=48 TOS=0x00 PREC=0x00 TTL=58 ID=0 DF PROTO=TCP SPT=53224 DPT=22 WINDOW=65535 RES=0x00 SYN URGP=0
Aug 27 13:54:16 test kernel: IN=ens3 OUT= MAC=02:00:17:00:74:b2:00:00:17:85:9a:40:08:00 SRC=160.XX.XX.133 DST=10.0.0.35 LEN=48 TOS=0x00 PREC=0x00 TTL=58 ID=0 DF PROTO=TCP SPT=53224 DPT=22 WINDOW=65535 RES=0x00 SYN URGP=0
Aug 27 14:28:49 test kernel: IN=ens3 OUT= MAC=02:00:17:00:74:b2:00:00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=62756 DF PROTO=TCP SPT=37091 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0
Aug 27 14:28:50 test kernel: IN=ens3 OUT= MAC=02:00:17:00:74:b2:00:00:17:85:9a:40:08:00 SRC=130.XX.XX.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=62757 DF PROTO=TCP SPT=37091 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0
Aug 27 14:28:52 test kernel: IN=ens3 OUT= MAC=02:00:17:00:74:b2:00:00:17:85:9a:40:08:00 SRC=130.XX.X.8 DST=10.0.0.35 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=62758 DF PROTO=TCP SPT=37091 DPT=22 WINDOW=26880 RES=0x00 SYN URGP=0


Test the rules: Try logging in to the instance from a new session and make sure you are able to SSH in. Please do not close the existing session to revert the changes in case you get locked out. If the above rules are set properly, with in 3 minutes you will be able to SSH in to the instance 3 times and the 4th attempt will be blocked.


Once you have tested the rules properly, you may delete the previous SSH allowed rule.

You may also save the IPTables rules to make it permanent.
# iptables-save > /etc/sysconfig/iptables

Automating the rate-limits using 3rd party tools:

  You may also use tools like Fail2Ban or SSHGuard to automatically block offenders.

Hope this helps! Let me know if you have any questions.

1 comment:

  1. why not try something like pam.d to lock those frequently login failed hosts.

    ReplyDelete