SSH Brute-Force Attacks Are Annoying, So...

7 min

language: ja bn en es hi pt ru zh-cn zh-tw

Hello, it's me, the incompetent one.
While watching /var/log/auth.log on the server hosting Gitea with tail -f, I noticed some suspicious attempts.
Here's an example:

2024-12-07T16:57:39.486624+00:00 hostname sshd[392231]: Received disconnect from WireGuardSrvIP port 42552:11: Bye Bye [preauth]

There are SSH login attempts from the VPN server side. The reason this is happening is because I'm using Nginx to Stream proxy to this Gitea server.

stream {
    server {
        listen 2222; 
        proxy_pass GiteaSrvIP:2222; 
        proxy_timeout 1m;
        proxy_connect_timeout 1s;
    }
}

When configured like this, IPs received on Port 2222 are forwarded to GiteaSrvIP. Honestly, I still don't understand why a different port, 42552, is shown in the logs, but it feels unsettling to see so many login attempts from this IP, which I'm using as an internal IP.
In terms of mechanism, I want to push to Gitea via SSH protocol, but when proxying with Stream, it's necessary to proxy to IP:port, so I think this is happening because all SSH attempts on port 2222 are being forwarded to GiteaSrvIP.

Even as I explain it myself, it's getting confusing, so...


Attacker: I'll SSH to git.domain.tld on port 2222!
WireGuardSrv: Oh, you're trying to log in on port 2222, are you?
WireGuardSrv: Alright, I'll forward all requests to port 2222 to GiteaSrv!
GiteaSrv: Well, I can only see WireGuardSrv's IP, and there are a lot of SSH login attempts coming in...


This is the only flow that makes sense for SSH attempts coming from WireGuardSrvIP...
However, the mystery is how it becomes port 42552 when I've only configured it to receive on port 2222 and forward to port 2222. If it were an attempt to SSH to this port from a global IP address, using an IP that only exists on the VPN, I might understand, but...
Of course, root login is prohibited for SSH itself, and I only allow public key authentication, so if it were to be breached, I'd be curious how it was done.

As a Countermeasure

If a messy auth.log remains, it's hard to read as a log file, and more importantly, the log file is likely to grow excessively, so I want to block it at an earlier stage.
The thing is, while fail2ban blocks multiple SSH login attempts, with the current setup, SSH attempts to GiteaSrvIP via Wireguard also get blocked, mixed in with other logs.
Therefore, I want to prevent it before it's written to auth.log.

On the FreeBSD (WireGuard Server) Side

I'll set the default block policy for pf to drop.
PF: Runtime Options
So, I'll set the default policy to Drop.

set block-policy drop

With this, if a packet hits the FreeBSD block policy, it will be dropped immediately.

On the Debian (WireGuard Client and Gitea Server) Side

First of all, it's strange that there are access attempts from other port numbers, clearly originating from WireGuardSrvIP, to Gitea's HTTP server and SSH ports 22 and 2222.
Especially ports above 2222, such as 3000, function as default local HTTP ports, so these shouldn't ideally be open. However, since I don't want Gitea to listen on port 80, I've temporarily opened port 3000 for a testing period.
Since I've rambled on, I've restricted ports using ufw as follows.

ufw deny proto tcp from WireGuardSrvIP to any port 2223:65535
ufw reload

Since I want to use it as a play-around VPS server, I've temporarily denied the range 2223:65535, but explicitly opened 3000/tcp separately.

Successfully Stopped Meaningless SSH Attempt Logs

Thanks to this, whether it was due to the block policy on the FreeBSD side or the explicit deny with ufw, I don't know which effect it was since I did both simultaneously, but the login attempts that were flooding auth.log like crazy have successfully stopped.
Most likely, since I had already configured some firewall rules on the FreeBSD side, blocked packets are being dropped instead of REJECTed, meaning all packets are discarded at the FreeBSD stage. I hope so.

Revisiting fail2ban Settings

So, I edited /etc/fail2ban/jail.conf and set the excluded IPs in the default monitoring settings.

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 WireGuardSrvIP

After that, I changed the settings for sshd.

[sshd]
enabled = true
port    = all
logpath = /var/log/auth.log
bantime = 10w  
findtime = 1d  
maxretry = 2

I tried a stricter setting than WireGuardSrv.
The reasons for the changes are as follows.

port    =  all
maxretry = 2

For WireGuardSrv, the port is explicitly set to only ssh, so it only monitors ports used for SSH, but this monitors SSH attempts on all ports.
Regarding retries, it's a strict limit of 2.
The reason for the change is that I'm curious how many hits it will get, and if it gets a lot, I plan to apply similar settings to WireGuardSrv as well.
That's all for now.
I'm looking forward to the results.

Related Posts