snh_nl
snh_nl

Reputation: 2955

Using Nginx honeypot and using blacklist, firewall block ip or fail2ban

Using Nginx honeypot and using blacklist, firewall block ip or fail2ban

So we have this server and we see 1000's of probes everyday. Funny thing is they all 'try' at least the same basic uri's like \admin and \wp-admin and \control and \mysqladmin .... our own people and users would never type these commands.

In the past we have sent deny all to these uri location matches and our block looks like this

location ~* ^/(admin|wp-admin|control)/?$
    deny all;
}

But for some uri requests we are 100% certain this is a website probe/hacker/crawler crawling non existant over-logical insecure uri's ... and instead of using deny all; I would like to have the IP blocked ... permanently or for at least 24 hours

question: How can I uri match requests like a honeypot and then block this IP using our firewall via nginx conf?

The result would be something like

location ~* ^/(admin|wp-admin|control)/?$
    ban the ip permanently;
    or
    ban the ip 24hours;
}

thanks!

Upvotes: 3

Views: 2718

Answers (1)

sebres
sebres

Reputation: 820

If deny all produces an error entry in your error.log, you can use a fail2ban jail called nginx-http-auth, so add this in your /etc/fail2ban/jail.local:

[nginx-http-auth]
enabled = true

make fail2ban restart (or fail2ban-client reload for fail2ban v.0.10 or newer) and they will be banned.


If you have only entries in access.log, or you want try better scenario, your can try this:

create new access log format (nginx default is a bit worse) in http section of nginx config:

log_format badlogfmt '$time_local : $remote_addr : $status : $body_bytes_sent : $request_method : $remote_user : '
                     '"$request" "$http_referer" "$http_user_agent"';

then write a new entry that would log all "bad" requests in separate log-file:

map $status $loggable {
    404     0; # ignore page not found (404).
    499     0; # ignore canceled/closed requests.
    ~^[45]  1; # all other requests with status starting with 4 or 5.
    default 0;
}

# log the bad requests: 
access_log /var/log/nginx/access_bad.log badlogfmt if=$loggable;
# all other requests:
access_log /var/log/nginx/access.log combined;

this will cause that all "bad" requests going to different log, which looks like this:

11/Jan/2020:06:27:59 +0100 : 192.0.2.1 : 403 : 154 : GET : - : "GET /admin/ HTTP/1.1" ...
11/Jan/2020:06:28:00 +0100 : 192.0.2.2 : 400 : 166 : - : - : "145.ll|'|'|SGFjS2...

your jail can be similar this one:

[nginx-ban-bots]
port    = http,https
logpath = /var/log/nginx/access_bad.log
backend = auto
filter =
# ban all but ignore 401 Unauthorized for empty user (: - :) and 404 (and 499 cancel request)...
failregex = ^\s*: <HOST> :(?: (?!40[14]|499)[45]\d{2} :| 401 : \d+ : \S* (?!: - :))
enabled = true

reload fail2ban and all the bots will disappear.

More info about in fail2ban/wiki/Best-practice#reduce-parasitic-log-traffic.

If your page is safe enough, so you could say "there are no broken links on our page", so you have almost no 404 errors, a smart trick could be also to ban large-scale attempts from an intruder to every not existing page.

So you could comment or remove 404 in map $status ... directive, as well as remove 4 from [14] from failregex, and possibly increase maxretry (and findtime) in order to avoid some false positives.

With this strategy you would not need to create all the nginx locations for any artificial URLs to match every bot attempts (and it'd work also tomorrow if the list of lucrative URLs would change)...


You could also try our newest fail2ban version (0.11) with incremental banning, then you could enable bantime.increment and set initial bantime to some lower value like 30s (for possible false positives), but all bans of known as "bad" intruders will be longer with each next ban (after repeated attempts).

Upvotes: 5

Related Questions