fail2ban custom filter for custom node.js application - fail2ban

Need some help related to create a custom filter for custom app which is websocket server written in node.js . As per my understanding from other articles the custom node.js app needs to write a log which enters any authentication failed attempts which will further be read by Fail2ban to block IP in question . Now I need help with example for log which my app should create which can be read or scanned by fail2ban and also need example to add custom filter for fail2ban to read that log to block ip for brute force .

Its really old question but I found it in google so I will write answer.
The most important thing is that line you logging needs to have right timestamp because fail2ban uses it to ban and unban. If time in log file is different than system time, fail2ban will not find it so set right timezone and time in host system. In given example I used UTC time and time zone offset and everything is working. Fail2Ban recognizes different types of timestamps but I didn't found description. But in fail2ban manual you can find two examples. There also exist command to check if your line is recognized by written regular expression. I really recommend to use it. I recommend also to use "regular expression tester". For example this one.
Rest of the log line is not really important. You just need to pass user ip.
This are most important informations but I will write also example. Im just learning so I did it for educational purposes and Im not sure if given example will have sense but it works. I used nginx, fail2ban, pm2, and node.js with express working on Debian 10 to ban empty/bad post requests based on google recaptcha. So set right time in Your system:
For debian 10 worked:
timedatectl list-timezones
sudo timedatectl set-timezone your_time_zone
timedatectl <-to check time
First of all You need to pass real user ip in nginx. This helped me so You need to add line in You server block.
sudo nano /etc/nginx/sites-available/example.com.
Find location and add this line:
location / {
...
proxy_set_header X-Forwarded-For $remote_addr;
...
}
More about reverse proxy.
Now in node.js app just add
app.set('trust proxy', true)
and you can get user ip now using:
req.ip
Making it work with recaptcha:
All about recaptcha is here: Google Developers
When You get user response token then you need to send post request to google to verify it. I did it using axios. This is how to send post request. Secret is your secret, response is user response.
const axios = require('axios');
axios
.post(`https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${response}`, {}, {
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
},
})
.then(async function (tokenres) {
const {
success, //gives true or false value
challenge_ts,
hostname
} = tokenres.data;
if (success) {
//Do something
} else {
//For fail2ban. You need to make correct timestamp.
//Maybe its easier way to get this but on my level of experience
//I did it like this:
const now = new Date();
const tZOffset = now.getTimezoneOffset()/60;
const month = now.toLocaleString('en-US', { month: 'short' });
const day = now.getUTCDate();
const hours = now.getUTCHours()-tZOffset;
const minutes = now.getUTCMinutes();
const seconds = now.getUTCSeconds();
console.log(`${month} ${day} ${hours}:${minutes}:${seconds} Captcha verification failed [${req.ip}]`);
res.send(//something)
}
Time zone offset to set right time. Now pm2 save console.log instructions in log file in /home/youruserdir/.pm2/logs/yourappname-out.log
Make empty post request now. Example line of bad request will look like this:
Oct 14 19:5:3 Captcha verification failed [IP ADRESS]
Now I noticed that minutes and seconds have no 0 but fail2ban still recognizes them so its no problem. BUT CHECK IF DATE AND TIME PASSES WITH YOUR SYSTEM TIME.
Now make filter file for fail2ban:
sudo nano /etc/fail2ban/filter.d/your-filter.conf
paste:
[Definition]
failregex = Captcha verification failed \[<HOST>\]
ignoreregex =
Now ctrl+o, ctrl+x and you can check if fail2ban will recognize error lines using fail2ban-regex command:
fail2ban-regex /home/youruserdir/.pm2/logs/yourappname-out.log /etc/fail2ban/filter.d/your-filter.conf
Result will be:
Failregex: 38 total
|- #) [# of hits] regular expression
| 1) [38] Captcha verification failed \[<HOST>\]
`-
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [38] {^LN-BEG}(?:DAY )?MON Day %k:Minute:Second(?:\.Microseconds)?(?: ExYear)?
`-
Lines: 42 lines, 0 ignored, 38 matched, 4 missed
[processed in 0.04 sec]
As You can see 38 matched. You will have one. If You have no matches, check pm2 log file. When I was testing on localhost my app gave IP address with ::127.0.0.1. It can be ipv6 related. It can maybe make make a problem.
Next:
sudo nano /etc/fail2ban/jail.local
Add following block:
[Your-Jail-Name]
enabled = true
filter = your-filter
logpath = /home/YOURUSERDIR/.pm2/logs/YOUR-APP-NAME-out.log
maxretry = 5
findtime = 10m
bantime = 10m
So now. Be sure that you wrote filter name without .conf extension.
In logpath be sure to write right user dir and log name. If You will get 5(maxrety) wrong post requests in 10minutes(finditme) then user will be banned for 10 minutes. You can change this values.
Now just restart nginx and fail2ban:
sudo systemctl restart nginx
sudo systemctl restart fail2ban
After You can check if Your jail is working using commands:
sudo fail2ban-client status YOUR-JAIL-NAME
There will be written how much matches was found and how much ips are banned. More information You can find in fail2ban log file.
cat /var/log/fail2ban.log
Found IPADDR - 2021-10-13 13:12:57
NOTICE [YOUR-JAIL-NAME] Ban IPADDRES
I wrote this step-by-step because probably only people with little experience will look for this. If You see mistakes or you can suggest me something then just comment.

Related

Fail2Ban how to match any string

I have a very simple situation but I can't figure out how regex works...
I have an application generating a log only when a login problem occurs. So there is no line in log except in case of wrong login or in case of attempt to reset a password too many times. So potentially, I don't even need to search a particular string in log, any entry matches. Here is a log example :
2019-10-20 18:44:35 127.0.0.1 login.php : Authentication error - account not initialized : client XXXX, login YYYY
2019-10-20 21:31:17 127.0.0.1 login.php : Authentication error - password error : client XXXX, login XXXX
2019-10-20 21:29:39 127.0.0.1 login.php : Authentication error - client contains wrong chars : client XXXX, login YYYY
2019-10-21 06:25:25 127.0.0.1 login.php : Authentication error - account locked : client XXXX, login YYYY
2019-10-21 06:48:11 127.0.0.1 user.php : Authentication - Unlocking : client XXXX, login YYYYY
I have a problem with regular expression cause I can't understand how it works (for years). All I tried give me errors when I start fail2ban : Unable to compile regular expression, No failure-id group in 'Authentication error', ... Damned, it looks so easy !
Finally...
[INCLUDES]
before = common.conf
[Definition]
failregex = <HOST> .* Authentication
Please note this works but I found without understand anything. If someone has a link where how fail2ban works is explained. I found many but none of them have clear explanations.
The main trick is the fact that error.log files look different from tutorials and you need to rewrite failregex manually. Another trick is that <HOST> is a predefined regexp that tries to match an ip but it could match something like datetime instead
In such case like
[Tue Nov 08 03:03:03.349852] bla-bla [client 1.2.3.4:5] bla-bla xxx bla-bla
In case you're banning when xxx appear
[Definition]
failregex = client <HOST>(.*)xxx
Sadly quick google search upon fail2ban and tutorials indeed explain little. I also wanted to ban by simple string match.

Pjsip/pjsua timeout errors and resolve errors calling phone numbers after registering with voip.ms from Raspberry Pi

The Goal
I'm trying to make a call to a telephone number. I'd like to be able to make a call from the raspberry pi, and also make a call to my voip.ms phone number and be able to answer or auto-answer and play some generic .wav file.
My current understanding of things
This maybe should be titled "My current misunderstanding of things". I'm new to sip and pjsip, and I think I must be missing some part of the process I don't understand. I was under the impression that, if I register with voip.ms, when I make a call it would route to voip.ms and they would do a lookup on the number/address, and then respond with an address that I would then begin to communicate with.
What I've done so far
Compiled
I've compiled Pjsip on a Raspberry Pi 3B+ properly, for what I can tell. I can include pjsua2.hpp in my c++ applications. I've roughly followed this tutorial
Tested compilation with pjsua binary && demo.cpp
I'm running into identical problems running a modified pjsua2_demo.cpp and the binary included in the pjsip build. For the sake of simplicity, I'll ask about the binary located (for me) at <project-path>/pjproject-2.8/pjsip-apps/bin/pjsua-armv7l-unknown-linux-gnueabihf.
Successfully registered with voip.ms
I have an account and phone number with Voip.ms and can become registered with voip.ms by executing the following script:
call_and_auto_answer.sh
./pjsua2-cpp/pjproject-2.8/pjsip-apps/bin/pjsua-armv7l-unknown-linux-gnueabihf \
--play-file ~/CantinaBand60.wav \
--local-port=5060 \
--auto-answer 200 \
--auto-play \
--auto-loop \
--max-calls 5 \
--config-file ./sip.cfg
Where the config looks like:
sip.cfg
#
# Logging options:
#
--log-level 5
--app-log-level 4
#
# Account 0:
#
--id sip:<my-subaccount-username>#sip.voip.ms
--registrar sip:<server-location>.voip.ms
--reg-timeout 300
--realm *
--username <my-subaccount-username>
--password <my-subaccount-password>
--use-timer 1
#
# Network settings:
#
--local-port 5060
#
# Media settings:
#
--srtp-keying 0
--auto-play
--auto-loop
--play-file /home/pi/CantinaBand60.wav
--snd-auto-close 1
#using default --clock-rate 16000
#using default --quality 8
#using default --ec-tail 200
#using default --ilbc-mode 30
--rtp-port 4000
#
# User agent:
#
--auto-answer 200
--max-calls 5
#
# SIP extensions:
#
--use-timer 1
When I enter the cli, I see for my account list:
Account list:
[ 0] <sip:192.168.1.49:5060>: does not register
Online status: Online
[ 1] <sip:192.168.1.49:5060;transport=TCP>: does not register
Online status: Online
*[ 2] sip:<my-subaccount-username>#sip.voip.ms: 200/OK (expires=285)
Online status: Online
Buddy list:
-none-
Voip.ms shows I've registered on their website.
The problem
I'm trying to call my personal cell phone from my pi (I assume using the registered voip.ms phone number), and call my pi from my personal cell phone. While calling out I'm typically getting either 408 Request Timeout errors or 502 gethostbyname errors.
Different destinations, different errors
Depending on the destination for my call from the pi, I get one of two different errors most of the time
Timeout Error
I get an error that says,
18:19:19.757 pjsua_app.c ....Call 4 is DISCONNECTED [reason=408 (Request Timeout)]
18:19:19.757 pjsua_app_comm ....
[DISCONNCTD] To: <destination-sip-address>
where is any of the following:
sip:
sip:
sip:thetestcall#sip2sip.info
sip:thetestcall#iptel.org
sip:201#ideasip.com
and the phone numbers are formatted like: 3035551234, though I've tried prepending a 1 and a +1 just to check.
Lookup Error
I get an error that says,
19:09:45.435 sip_resolve.c ....Failed to resolve '<destination-sip-address>'. Err=70018 (gethostbyname() has returned error (PJ_ERESOLVE))
19:09:45.435 tsx0x18520dc ....Failed to send Request msg INVITE/cseq=10722 (tdta0x185012c)! err=70018 (gethostbyname() has returned error (PJ_ERESOLVE))
19:09:45.435 pjsua_app.c .......Call 4 is DISCONNECTED [reason=502 (gethostbyname() has returned error (PJ_ERESOLVE))]
19:09:45.435 pjsua_app_comm .......
[DISCONNCTD] To: sip:<destination-sip-address>
where is any of the following:
sip:
sip:
sip:abcd1234
Possible Successes
I'm getting what looks like a success while calling:
sip:**12340#ideasip.com
It confirms the call and has a bunch of messages, notable including:
19:16:17.550 pjsua_core.c ....TX 1300 bytes Request msg INVITE/cseq=13899 (tdta0x15c263c) to UDP 208.97.25.11:5060:
...
19:16:17.551 pjsua_app.c .......Call 4 state changed to CALLING
...
>>> 19:16:17.606 pjsua_core.c .RX 575 bytes Response msg 100/INVITE/cseq=13899 (rdata0x6d7008a4) from UDP 208.97.25.11:5060:
...
19:16:17.609 pjsua_core.c .RX 946 bytes Response msg 200/INVITE/cseq=13899 (rdata0x6d7008a4) from UDP 208.97.25.11:5060:
...
19:16:17.609 pjsua_app.c .....Call 4 state changed to CONNECTING
...
19:16:17.610 pjsua_app.c .....Call 4 state changed to CONFIRMED
...
19:16:17.676 pjsua_core.c .RX 594 bytes Response msg 100/INVITE/cseq=13900 (rdata0x6d7008a4) from UDP 208.97.25.11:5060:
...
19:16:17.678 conference.c ......Port 5 (sip:**12340#ideasip.com) transmitting to port 5 (sip:**12340#ideasip.com)
...
19:16:17.678 conference.c ......Port 1 (/home/pi/CantinaBand60.wav) transmitting to port 5 (sip:**12340#ideasip.com)
...
19:16:36.931 pjsua_app.c ......Call 4 is DISCONNECTED [reason=200 (Normal call clearing)]
Same Network
Additionally, if I set up a second pjsip client on the same network, I can call it from pi1 and answer the call on pi2.
Incoming calls
When I register with voip.ms, then try to call my voip.ms phone number from my personal cell phone, the call fails with a message on my iPhone that says, User Busy. This makes me think I'm messing something up with the registration, or that I'm missing some component, like a subscribe or link with that voip.ms account.
Final thoughts
I'm not sure what I'm missing here. I've read through a ton of the pjsip and pjsua docs, and I can't find anything I'm missing. Does anybody have insight into how to make a call to a phone number and allow for incoming calls? This has been quite a few days of solid work.
So I figured out the answer to my question. Here's the skinny:
Voip.ms registration
My registration with voip.ms wasn't configured properly. I was given credentials by a coworker, but upon further inspection of the sip endpoint, I found that the DiD number purchased for the account wasn't associated with the subaccount my coworker created for me. So, depending on the recipient's phone carrier, I was given different errors. Additionally, when I was testing inbound calls and receiving the error, User Busy, this was because the account I registered wasn't associated with the phone number.
To fix this, on voip.ms I associated the DiD number to my subaccount, and then went to my subaccount information and set the callerId number to be my DiD number, though I think you can override this value via pjsip.
Outbound sip calls
Secondly, to call a phone number, outbound calls should follow the following format:
sip:<phoneNumber>#<endpoint>
So for me, this looked very much like:
sip:5551234567#newyork.voip.ms

How to upload the siacs HttpUploadComponent for file sharing in openfire localhost

I am implementing the chat appliation using https://github.com/siacs/Conversations in android. There are no image sharing for group chat thats why It required the HTTP Upload component on openfire server (https://github.com/siacs/HttpUploadComponent). I made the changes in config.yml as per required. I am able to connected but in android eu:siacs:conversations:http:upload" not coming in feature list.
config.yml looks like below:-
component_jid: upload.andreis-mac-mini-2.local
component_secret: test
component_port: 5275
storage_path : /Users/enovate/Documents/Jagdish/Test
whitelist:
# andreis-mac-mini-2.local
# - someotherdomain.tld
# - dude#domain.tld
max_file_size: 20971520 #20MiB
http_address: 127.0.0.1 #use 0.0.0.0 if you don't want to use a proxy
http_port: 8080
# http_keyfile: /etc/ssl/private/your.key
# http_certfile: /etc/ssl/certs/your.crt
get_url: http://andreis-mac-mini-2.local
put_url: http://andreis-mac-mini-2.local
expire_interval: 82800 #time in secs between expiry runs (82800 secs = 23 hours). set to '0' to disable
expire_maxage: 2592000 #files older than this (in secs) get deleted by expiry runs (2592000 = 30 days)
user_quota_hard: 104857600 #100MiB. set to '0' to disable rejection on uploads over hard quota
user_quota_soft: 78643200 #75MiB. set to '0' to disable deletion of old uploads over soft quota an expiry runs
If anyone have idea. Please help me. Thanks in advance...

fail2ban regex for smtp_auth

I am NO GOOD at regex - and as such i can not seem to match the plesk mail log string that indicates a brute force smtp attack -
my log looks like this:
May 19 03:24:58 gohhllc smtp_auth[22702]: SMTP connect from mail.globaltrbilisim.com [213.144.99.201]
May 19 03:24:58 gohhllc smtp_auth[22702]: No such user 'chuong#drophit.net' in mail authorization database
May 19 03:24:58 gohhllc smtp_auth[22702]: FAILED: chuong#drophit.net - password incorrect from mail.globaltrbilisim.com [213.144.99.201]
In some cases it also looks like this
May 19 03:25:22 gohhllc smtp_auth[23056]: SMTP connect from 89-97-124-22.fweds-spc.it [89.97.124.22]
May 19 03:25:22 gohhllc smtp_auth[23056]: FAILED: element - password incorrect from 89-97-124-22.fweds-spc.it [89.97.124.22]
My regex attempts to match both username failures and password look like this
failregex = No such user '.*' in mail authorization database
FAILED: .* - password incorrect from [<HOST>]
Along with 20+ other combos with no avail - most of the time teh result is an error like this
Unable to compile regular expression 'FAILED:
Thanks
I worked through this and using http://www.regexr.com/ i was able to write a fairly easy regex (i guess im getting better at it) to make this work.
The resulting statement for smtp-auth when using Pleask and Qmail (atleast on my server) is
failregex = FAILED: [-/\w]+ - password incorrect from <HOST>
AS for "no such user" entries i was unable to make this work as there is no hostname in the log file for this entry and fail2ban requires the hostname :(

Fail2ban not sending email notifications

My CentOS server has postfix as MTA and it’s working.
When I type the command mail -s "testing" <my gmail address>, I receive the email.
However, Fail2ban is unable to send emails to my gmail address when an IP gets banned. I’m probably missing some configuration in jail.conf.
Here is part of my jail.conf file:
destemail = myaddress#gmail.com
sendername = fail2ban
mta = sendmail
protocol = tcp
action = %(action_mwl)s
I already tried mta = postfix and it didn’t work.
Thanks in advance for your help.
EDIT: I was able to make it work. None of the configuration above is correct for my fail2ban v0.8.10 and my linux CentOS 6. In fact, I removed all the lines above (garbage).
I found a pre-defined action in /etc/fail2ban/action.d/mail.conf file.
I noticed this action uses "mail -s" command which works on my server.
So, I decided to use this action in my jail.conf file as such:
[ssh-iptables]
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
mail[name=ssh, dest=my-address#gmail.com]
logpath = /var/log/secure
maxretry = 5
The only thing that needs to be change to get an email from fail2ban is to add that line below “action” that starts with “mail.” Very simple and easy.
You should change mta = sendmail to:
mta = mail
if you want email notifications with whois i found this solution
[sshd]
enabled = true
logpath = %(sshd_log)s
action = iptables-ipset-proto6[name=ssh, port=ssh, protocol=tcp, bantime=0]
mail-whois[name=sshd, dest=my-email#something.com]
findtime = 3600
bantime = -1
maxretry = 3
All of the above did not work for me.
What worked for me was adding second line under action =....
to be:
sendmail[mailcmd='/usr/sbin/sendmail -f "<sender>" "<dest>"', dest="email#recipient.com", sender="fail2ban", sendername="Fail2Ban", name="jail_name"]
Note: You may do so for various jails.
Also note, that if you would like to get an email notification for ModSecurity, you can do so, by setting a Fail2Ban jail for ModSecurity, and then get the email notifications.