Blog - 0x00


Unwanted (ssh) connections

2021/10/09

A few days ago I rented a server on a VPS provider with a public IPv4 as a playground, to test some tools, learn new ones and maybe have personal services running. So I installed Rocky Linux 8.4 to test it out and one of the first things I wanted to check was the ssh attempts to my server as it was the only service open to the internet, but I noticed there was no file logging this, so I had to edit the file /etc/rsyslog.conf and made sure this line was uncommented:

# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
Once I had done that I restarted rsyslog service:

[root@rockylinux ~]# systemctl restart rsyslog
and the ssh attempts started appearing in /var/log/secure.

It was really interesting to see the attempts, the users they were attempting to login and the IPs. I’ll start a bit with the numbers, all of this is in 24 hours:

Certainly it would be more interesting on a longer period of time but 24 hours of ssh attempts can still show a few things.

Within the logs I saw what I’d guess is someone running a broken script, it was attempting to use IPs as the username to login (wasn’t even my machines IP). I also saw two HTTP GET requests, yes, they tried to do a GET to port 22 in my server. (The IPs have been changed)

error: kex_exchange_identification: client sent invalid protocol identifier "GET / HTTP/1.1"
...
Invalid user admin from 192.168.32.3 # Normal attempt to user 'admin'
Invalid user 10.23.2.1 from 172.16.2.1 # Attempt with username IP
Invalid user 10.23.3.25 from 172.16.2.1 # Another one

After checking the logs I thought, how could I stop attempts? They were bruteforcing their way in, filling the logs and it didn’t make much sense to even allow connections from somewhere outside the country I live in. So I used nftables, the new tool that is replacing iptables.

I searched on the internet for Chile IP Blocks/CIDR and downloaded them as a text file so I could create a list of the IPs that were allowed to connect to my server, allowing only IPs from Chile. Then I had to configure nftables, which was a bit difficult because I had only used iptables before and the commands to create rules, chains, etc was different, but thankfully Red Hat provides good documentation about nftables called “Getting started with nftables”.

So with nft one of the first things I did was create a table called “filter”. It’s important in this case before the name of the table to set it to ip because the rules in that table will match IPv4 packets and there are other options for packet filtering: ip6, inet, arp, bridge, netdev

[root@rockylinux ~]# nft add table ip filter
[root@rockylinux ~]# nft add chain ip filter input { type filter hook input priority filter\; policy accept\; }

The second command will add a chain called “input” and its important that the policy is “accept” as I tried to first set it to “drop” and lost connection to the server and couldn’t connect through ssh as it will drop any incoming connection.

# We aren't a router so we can safely drop "forward" packets
[root@rockylinux ~]# nft add chain ip filter forward { type filter hook forward priority filter\; policy drop\; }
[root@rockylinux ~]# nft add chain ip filter output { type filter hook output priority filter\; policy accept\; }
# Allow "related" and "established" connections
[root@rockylinux ~]# nft add rule ip filter input ct state related,established  counter accept
# Allow loopback interface input packets
[root@rockylinux ~]# nft add rule ip filter input iifname "lo" counter accept

Now that I have established the basic rules for the incoming packets I can start adding the IPs that I want to allow incoming packets BUT I don’t want to just “accept” the connection to any port so I’ll create a new chain where I can control which ports are open and which are not and then any incoming connection from an IP in Chile will jump to my “personal” chain where I’ll add rules to ports, in this case port 22 so I can ssh into the server.

[root@rockylinux ~]# nft add chain ip filter personal
# ip-chile.txt contains cidr ips which will be the IPs that are allowed to connect
[root@rockylinux ~]# while read line; do nft add rule ip filter input ip saddr "${line}" counter jump personal; done < ip-chile.txt
[root@rockylinux ~]# nft add rule ip filter personal tcp dport 22 counter accept
# Once we are done we can by default drop packets in input
[root@rockylinux ~]# nft add chain ip filter input { type filter hook input priority filter\; policy drop\; }

And done. Only the IPs that were in the file ip-chile.txt will be allowed AND only through port 22 using TCP, any other IP that doesn’t match any of the rules in the chain input will be dropped.

If you try to ping the machine from anywhere it won’t respond, I did intentionally left it like this because usually if you want to know whether a machine is alive or not you use ping and I prefer my server to stay “hidden” or look dead rather than someone knowing there is a server at my IP and probably trying to bruteforce or an exploit.

Now in the last 24 hours the only thing that has been written in /var/log/secure have been my logins, so nftables have completely “dropped” packets coming from everywhere except the IPs I allowed, even if they somehow got ahold of my private key to ssh they wouldn’t be able to connect to the server because of the rules in nftables (unless they knew and also had an IP from Chile).

I learned how to enable the logs for ssh authentication, also was able to see interesting bruteforcing attempts into my machine, managed to learn more about nftables as I only knew iptables. I hope it was an interesting read and also learned a little bit from what I wrote.