HTB – Sense– without Metasploit

As usual we’ll make a nmap scan session for the target machine open ports.

discovered only 80 and 443 ports. Visiting the address on the browser give us the access page of the pfsense firewall.

let’s run a web bruteforce discovery with gobuster. In this case we used the php and txt extensions.

gobuster dir -u -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -k -x php,txt

the scan reported two interesting pages.
/changelog.txt (Status: 200)
/system-users.txt (Status: 200)

system-users.txt give us the right credentials to access the firewall admin panel.

user: rohit
pass: pfsense

after this we tried to discover the actual version of the firewall. It’s the 2.1.3

on there’s an exploit suitable for our target version:

so we gave the correct parameters for access the remote machine vulnerability. Be careful…the python version to use is python3 or you obtain an error lauching the command.

it’s root!

HTB – Blocky – without Metasploit

here’s a new episode related to the hackthebox machine Blocky.
As always I’m figuring to avoid the use of metasploit in order to better understand the hacking process.

some open ports. I make a full scan with max retries = 1 in order to make a quick scan of the whole machine.
On port 80 there’s a website made by wordpress.
so I always start Nikto for the port 80 and in this case I add a scan with WPscan.

let’s keep them but we’ll try to exploit other vector before.

the ftp version is vulnerable but the exploit doesn’t work.

so we decided to move to a web application brute forcing with dirbuster

the plugins directory contains two files. Download them!

jar files can be extracted (

this is the content of Blockycore.class
there’s a root and something that seems to be a password… try it on ssh

the password doesn’t work with root user. But on wpscan we discovered the user notch. and it works!

we have the password so we try to check if the user is in the sudoers group

so with a simple “sudo su”

HTB – Nibbles – without Metasploit

let’s start nmapping the machine. There are 2 ports opened: 22 and 80.
On the port 80 there’s a simple “hello word” page but checking the page source there’s something interesting:

port 80 – view-source

Adding the nibbleblog directory to our url let us reach a nibbles blog homepage.

Nibble homepage

The hyperlinks don’t open other pages so what we can do is try to enumerate more web pages with gobuster.

As soon as we started the enumeration we discovered many interesting links.
The admin page have a login so we look for some sql injection using sqlmap.
While configuring burpsuite to grab the sql request we tried to use some basic password against the login (admin / password, admin / pass, nibbles / nibbles) and we discovered that the login was admin / nibbles.
We launched sqlmap the same in order to analize the sql injection.

The nibbleblog dashboard. Is possible to see some login failed attempt

This is the request we’ll use with sqlmap

save this to be used with Sqlmap. Click the right mouse button and select “copy to file”
# sqlmap -r sql.req --batch --risk 3 --level 5

the problem is that we have some kind of protection (WAF) that blocks our requests.

something blocks our requests

After few minutes we are again able to access the website but we can’t use automatic tools that can block us.
Entering the blog we discovered the software version

googling this version we discovered a vulnerability with the “my image” plugin. From

The first upload, from the “my image” plugin was a simple image. After the upload the image appears on the home page and by inspecting it we discovered where the uploaded images are located. so I try to upload a php shell.
We found a directory listing where there’s a image.php file… on it..
here’s the shell!!!

type some command to obtain a better shell (thank you Ippsec….subscribe his channel for very cool HTB and others high quality writeups!!)

in the home directory is possible to found the user hash

unzip the archive and you’ll find the code that works as a protection from bruteforce auth. Nothing particularly interesting for now.
Get LinEnum from attacking machine and launch it.


modify the with this command

echo "su" >

and launch the following command:

sudo /home/nibbler/personal/stuff/

even if the program returns an error, we are root!


Kubernetes – nginx with virtualhosts on 3 nodes bare metal configuration

Hello everybody!

This is a simple but cool exercise you can do in order to better understand Kubernetes and it’s configuration.

Scenario: we want a persistent Volume on an external nfs storage (we call it storage1 inside the configurations. Remember to set your etc/hosts file in order to be resolve the address or just use the ip).

This is our first file, nfs_pv.yaml. It creates a new persistent volume on the nfs storage, on the path “/mnt/share” as you can see in the following code:

apiVersion: v1
kind: PersistentVolume
  name: nfs
    storage: 50Gi
    - ReadWriteMany
  storageClassName: my-local-storage
    server: storage1
    path: "/mnt/share/"

It’s very simple!!. Storage1 is the name resolution of my external nfs (set it on /etc/hosts file!).

Now we need a claim on this persistent volume. Just edit pvc.yaml file and insert the following code:

kind: PersistentVolumeClaim
apiVersion: v1
  name: my-claim
  - ReadWriteMany
  storageClassName: my-local-storage
      storage: 50Gi

Now you should have two files inside you directory. Launch the command:

kubectl get pv
kubectl get pvc

You can control that the status of the volume and its claim are bound

Create a service that is responsible to give us network access to the pods that we are going to create. Let’s call this file as svc.yaml.

apiVersion: v1
kind: Service
   name: www-np
   type: NodePort
   - port: 80
     targetPort: 80
     app: www2

We are now able to use port 80 to match the port 80 on the pod with nginx.

Create now the nginx deployment (deployment.yaml):

apiVersion: extensions/v1beta1
kind: Deployment
  name: www2
  replicas: 2
        app: www2
        - name: www2
          image: nginx:alpine
            - containerPort: 80
            - name: www-persistent-storage
              mountPath: /usr/share/nginx/html
            - name: directory-data
              mountPath: /etc/nginx/sites-enabled/            
            - name: nginx-config
              mountPath: /etc/nginx/ 

        - name: www-persistent-storage
            claimName: my-claim
        - name: nginx-config
            name: confnginx

        - name: directory-data
            name: directory-data

– /usr/share/nginx/html will be mapped on the nfs storage (/mnt/share/). the “www-persistent-storage” is related to the claimName “my-claim” that is linked to the nfs folder.
– The folder /etc/nginx/sites-enabled/ will be created by the deployment and it’ll contain directory-data (configMap that we’ll explain in a while).
– “replicas: 2” is the number of pod we want to create. They will balance requests on the web server.

We need to change two configurations for the virtualhost to work. The first one is Site-enabled folder which contains all the nginx.conf files of our virtualhosts. The other configuration is the nginx.conf to be saved in /etc/nginx on the pod. We used the configMaps in order to achive this.
We put inside a folder (“data” in this case) all the configuration we want to enable in our nginx installation.

kubectl create configmap directory-data --from-file=data/

This command will take all the files in the directory and save them in the configmap directory-data. In the deployment file we configured this part:

            - name: directory-data
              mountPath: /etc/nginx/sites-enabled/   

this allow us to save all the files of our virtualhosts in the directory “/etc/nginx/sites-enabled/

we are doing the same with confnginx

kubectl create configmap confnginx --from-file=nginx.conf

check the configmaps with this command:

# kubectl get configmaps
NAME             DATA   AGE
confnginx        1      122m
directory-data   2      146m

It’s possible to recover the content of the configmaps files. Here’s the command that allow you to read the configuration files (we’re offer to you the whole code):

# kubectl get configmap directory-data
NAME             DATA   AGE
directory-data   2      154m
[root@k8s-master boh_nginx]# k get configmap directory-data -o yaml
apiVersion: v1
data: |
    server {
        listen       80;

        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;

        location / {
            root /usr/share/nginx/html/;
            index  index.html index.htm;
            try_files $uri $uri/ =404;

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;

        # proxy the PHP scripts to Apache listening on
        #location ~ \.php$ {
        #    proxy_pass;

        # pass the PHP scripts to FastCGI server listening on
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #location ~ /\.ht {
        #    deny  all;
    } |
    server {
        listen       80;

        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;

        location / {
            root /usr/share/nginx/html/;
            index  index.html index.htm;
            try_files $uri $uri/ =404;

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;

        # proxy the PHP scripts to Apache listening on
        #location ~ \.php$ {
        #    proxy_pass;

        # pass the PHP scripts to FastCGI server listening on
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #location ~ /\.ht {
        #    deny  all;
kind: ConfigMap
  creationTimestamp: "2019-08-13T10:14:33Z"
  name: directory-data
  namespace: default
  resourceVersion: "478167"
  selfLink: /api/v1/namespaces/default/configmaps/directory-data
  uid: 35f084a6-03ce-4a86-903e-2479a1d0bcce

As you can see we have and files!
The following is the nginx.conf taken from the configmap:

# kubectl get configmap confnginx -o yaml
apiVersion: v1
  nginx.conf: |
    user  nginx;
    worker_processes  1;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/;

    events {
        worker_connections  1024;

    http {

        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;
        #tcp_nopush     on;

        keepalive_timeout  65;

        #gzip  on;

        include /etc/nginx/sites-enabled/*.conf;
        server_names_hash_bucket_size 64;

kind: ConfigMap
  creationTimestamp: "2019-08-13T10:38:09Z"
  name: confnginx
  namespace: default
  resourceVersion: "480437"
  selfLink: /api/v1/namespaces/default/configmaps/confnginx
  uid: dc4278c3-6d62-4b6e-8bae-cde3d39b6748

From the folder that contains all these file we wrote during the tutorial lauch:

# kubectl apply -f ./

this will deploy all the configuration we made!

Don’t forget to set the hosts file to match the ip address of your k8s installation.
You need to launch this command if you’re using a baremetal setup in order to see which port is mapped on the nginx installation:

open your browser on:


HTB – Devel – no metasploit

this is the first nmap.

after this I open Sparta for automatic recconaissance. In this case the machine have an open 80 port. so Nikto will be lauched by Sparta.

on the port 80 there’s the default IIS 7 page

the server version is IIS-7.5
Nmap discovered the port 21 open.

Sparta discovered an ftp server with anonymous access:

so I tried to log on with ftp client and test a directory listing

let’s try to upload something with the ftp server
Create a new payload with msfvenom

upload is allowed

create an handler on msfconsole (allowed on OSCP!)

and we have a successful exploit

meterpreter is running as

find an exploit suitable with this environment

I’ve found an exploit suitable for this machine

I downloaded and compiled it from my kali. this is the command:

i686-w64-mingw32-gcc exploit.c –o exploit.exe] –lws2_32

after this upload the exploit.exe file to the machine. Use the FTP server in binary mode for the transfer.
after this, simply run the command from the meterpreter shell and…

HTB – Legacy writeup (without Metasploit)

LEVEL: Beginner

In this writeup we’ll start with Sparta, a tool for automatic enumeration.
I usually run Sparta after the first nmap scan, in order to get more information in a very fast manner. Sparta launchs nmap and other tools like Nikto after discovering a port compatible with that particular tool (port 80 or 443 in Nikto case).

as we can see not so much options except smb protocol.
The other important thing is that we discovered the target os (Windows XP).

No shares seems to be available on the machine. No anonymous login allowed.

It’s time to get more into enumeration. Nmap has many vuln NSE script that can make easier our enumeration phase.
locate the scripts with:

let’s lanch vuln script against our target on port 445.

there are two BIG vulns, the first one related to ms08-67 an old vuln discovered in 2008. Is possible to solve this with metasploit (I don’t want to do this). For those who are studying for the OSCP it nice to avoid the use of metasploit and is not always easy to discover how to solve machines without this tool.
The other discovered vulnerability is on SMBv1 server (ms17-010) that is the vuln that allowed the spred of the wannacry ransomware in 2017.
let’s try to exploit this

This page collects a lot of different exploits related to the EternalBlue vulns.

This particular exploit was tested on XP

the python script asks for IP and the executable file. So, if we generate the malicious file we cand send it to the victim and we have RCE.

create the payload with msfvenom

were X.X.X.X is the attacking machine address in order to receive the reverse shell. Open a listener on port 443 and launch the command:

with systeminfo we can discover information of our target

we are able to reach the administrator\Desktop folder so we are root on the machine.


How to install ELK stack – Centos 7 – part 1

ELK stack – easy install Centos 7

ELK stack is the acronimous of Elasticsearch, Logstash and Kibana and it’s a powerful tool that allow you to collect, analyze and visualize your logs.

let’s start!!!!
first install java:

sudo yum install -y  java-1.8.0-openjdk-devel

after this check the installed version with java -version.

go to the main elasticsearch website in order to collect the correct and updated repository. Download and install the public key:

rpm --import

create a file in the /etc/yum.repos.d/ and paste this data:

name=Elasticsearch repository for 7.x packages

start the installation with

yum install -y elasticsearch

start, enable and verify the elasticsearch service

systemctl start elasticsearch
systemctl enable elasticsearch
systemctl status elasticsearch

check the cluster status

# curl -X GET "localhost:9200/_cat/health?v"

epoch      timestamp cluster       status shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1557000685 20:11:25  elasticsearch green           1         1      0   0    0    0        0             0                  -                100.0%

check the node status

# curl -X GET "localhost:9200/_cat/nodes?v"

ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name           30          33   2    0.10    0.13     0.13 mdi       *      elk

Install Kibana

# yum install -y kibana

edit the configuration file

vim /etc/kibana/kibana.yml

uncomment the following line

server.port: 5601

start and enable kibana

systemctl start kibana
systemctl enable kibana

Install Nginx

you need nginx to be used as a reverse proxy. Install epel release and nginx

yum install epel-release
yum install httpd-tools
yum install nginx 

edit the nginx configuration

vim /etc/nginx/conf.d/elkstack.conf

paste the following code in this file

server {
    listen 80;

    server_name elkstack;

    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/htpasswd.kibana;

    location / {
        proxy_pass http://localhost:5601;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;

before start the service we need to remove the default nginx configuration file. Edit the /etc/nginx/nginx.conf. Locate and delete the whole server section.
This is the portion of the file that we have to delete

server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {

        error_page 404 /404.html;
            location = /40x.html {

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {

Now it’s time to set the username and password to access our ELK stack server.

sudo htpasswd -c /etc/nginx/htpasswd.kibana admin

insert the password that you’ll use to access to the system.

if you have selinux configured in enforce mode you need to allow httpd

sudo setsebool httpd_can_network_connect 1 -P

you should do the same with your firewall (firewalld in centos) if you have problems.

# firewall-cmd --zone=public --add-port=80/tcp --permanent
# firewall-cmd --reload

visit you ip address with the browser and……IT WORKS!

You’ll see anything right now because we don’t have any data and we have to complete the ELK with Logstash.
Logstash is a data collector that is able to parse incoming data and insert them in elasticsearch to be visualized in kibana

yum install -y logstash
systemctl start logstash
systemctl enable logstash

start and enable logstash

that’s all for this “episode”. In the next step we’ll configure logstash to collect and parse our data.

How to connect remotely to my rasp behind NAT

remotely connect to a raspberry pi behind NAT

disclaimer: I’m not related to; they just offer a nice service that can be useful to some people…so I decided to speak about it!

Hello! do you have a raspberry pi? do you want to reach it remotely in a secure manner and easily? your ISP doesn’t allow you to forward port on your network and you are behind a NAT configuration? ok….I have a simple solution that can help you! offers a cool and free for personal use service that allow you to add a secure port device forwarding to any device.

you can choose between two connection types:

the first way is very simple to set up and all you need is the connectd installed on the target device. Two limitations here: URL and port changes every time you connect and there’s a 8 hour time limit before the connection will be closed.

with the second option you don’t have this problems, the throughput is faster and no limitation on time connections.

Installation and configuration on raspberry

just update your raspberry and install connectd with this commands. After this execute the interactive installer :

sudo apt update
sudo apt full−upgrade

sudo apt install connectd
sudo connectd_installer

follow the interactive installation (very simple) and you’ll arrive at the main menu were you are able to choose witch protocol you’d like to use with this device. You can even create a custom TCP configuration!

*********** Protocol Selection Menu ***********
     1) SSH on port 22                       
     2) Web (HTTP) on port 80                
     3) Secure Web (HTTPS) on port 443       
     4) VNC on port 5900                     
     5) nxWitness on port 7001               
     6) Samba (SMB) on port 445              
     7) Remote Desktop (RDP) on port 3389    
     8) NextCloud on port 443                
     9) OpenVPN on port 1194                 
     10) Custom (TCP)                        
     11) Return to previous menu             

 You can change the port value during install  


Choose a menu selection (1 - 11):

The default port for SSH is 22.

After this I downloaded the app on my Iphone and I was able to see the raspberry in the Devices panel. Just click on the remote device (raspberry) and you’ll be prompt (just for the very first time) to insert the app you want to use to connect to remote endpoint. I use Termius on my Iphone and that’s it!

my remote raspberry shell from my Iphone!


with you’ll be able to connect and control your devices remotely anywhere in the world as though it is on your local network in a very secure manner.

with no port forwarding you have “Zero Attack Surface” and this is important expecially for unsecure protocols like RDP.
Give it a try!

Tcpdump – analyze your packets

packet sniffing and analysis with tcpdump

tcpdump is a powerful tool that can help detect and analyze network traffic. The command line usage is very simple and allow to use grep and other terminal utilities for match and discover ethernet packets and flows.
In this tutorial we’ll show some basic examples that allow you to discover the various options the tool offers


install is very simple. Just use yum (or your distro packet manager)

# yum install tcpdump

first….we have to discover the various interfaces we can sniff just type the command tcpdump with -D options

root@raspberrypi:~# tcpdump -D

1.eth0 [Up, Running]
2.any (Pseudo-device that captures on all interfaces) [Up, Running]
3.lo [Up, Running, Loopback]
4.nflog (Linux netfilter log (NFLOG) interface)
5.nfqueue (Linux netfilter queue (NFQUEUE) interface)
6.usbmon1 (USB bus number 1) 

let’s sniff the first 10 packets from our eth0 interface:

# tcpdump -i eth0 -c 10

write our sniff to a pcap file (readable from wireshark too)

# tcpdump -i eth0 -w /home/pi/sniffing.pcap

we can read data from the captured file and look for arp traffic only with

# tcpdump -nn -r sniffing.pcap arp

extract from the capture traffic from and directed to one specific host (-nn means “don’t resolve hostname and port numbers”)

# tcpdump -n -r sniffing.pcap host 

extract traffic from a specific network, a specific source ip and a unique destination

# tcpdump -n net 
# tcpdump src
# tcpdump dst

is possible to filter src and destination port (port range too)

# tcpdump src port 4444
# tcpdump dst port 80
# tcpdump port 53
# tcpdump portrange 1000-1100

boolean operators

with the use of boolean operators is possible to obtain interesting combination of search options

# tcpdump host and port not 22
# tcpdump src and dst
# tcpdump not tcp

is possible to make even more complex searches by combining various options

# tcpdump 'src and (dst port 21 or 25)'

TCP Flags filtering

is possible to make some decision on which flags consider in our sniff. In order to apply correctly this it’s important to have a basic knowledge of the ethernet packet header. Here’s the header format taken from RFC 793

TCP Header Format

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   |          Source Port          |       Destination Port        |
   |                        Sequence Number                        |
   |                    Acknowledgment Number                      |
   |  Data |       |C|E|U|A|P|R|S|F|                               |
   | Offset| Res.  |W|C|R|C|S|S|Y|I|            Window             |
   |       |       |R|E|G|K|H|T|N|N|                               |
   |           Checksum            |         Urgent Pointer        |
   |                    Options                    |    Padding    |
   |                             data                              |

tcp flags starts from byte 13 (as the image shows), from the CWR (Congestion Window Reduced) and ECE [ECN (Explicit Congestion Notification) flags.

if we want to filter only SYN-ACK packet we have to do this simple operation. Put an ‘1’ in correspondence of every flag we want to consider and convert the value to decimal:

00010010 = 18 (decimal)

so to accomplish this filter request we have to use this option:

# tcpdump 'tcp[13]=18'

if we want to check RST packet? both requests are equivalent

# tcpdump 'tcp[13] & 4!=0'
# tcpdump 'tcp[tcpflags] == tcp-rst'

4 is the value of the ‘r’ flag inside CEUAPRSF so in the previous research we asked for packets at least with r flag active

is possible to use linux terminal tools like grep, cut, awk etc to make more specific researches.

# tcpdump -vvtt | grep 'raspberry' 

the last option is related to packet size. here’s an example:

# tcpdump -i eth0 <= 64 and dst
# tcpdump dst or less 32
# tcpdump greater 128 and port not 22 


tcpdump can provide information for IT troubleshooting. The syntax is quite human and after some tests you will easily remember the right option that will support you in your daily activities

Port Protection with fail2ban

A public server is scanned and brute forced a lot of times every hour of the day. These are the statistic related to my public and unknown developer test server in the last 24 hours:

Elk stack report of the last 24 hours ssh bruteforce attacks

This could be both a security problem and a system performance issue due to the resources spent in order to manage every connection. Fail2ban is easy to be installed and configured. After different trials of guessing user password the attacker client is automatically inserted in the iptables drop chain for a certain amount of time.

Let’s install epel ( Extra Packages for Enterprise Linux ) and fail2ban service :

yum install epel-release
yum install -y fail2ban fail2ban-systemd

‘Enable’ to make it persistent and start the service

systemctl enable fail2ban
systemctl start fail2ban

if selinux is installed you need to update the policies with:

yum update -y selinux-policy*

The default configuration file is located in /etc/fail2ban directory and it’s called jail.conf.
This file can be modified or restored by package distribution updates so it’s better to create a new file called jail.local and make there our configurations

vim /etc/fail2ban/jail.local

here we can specify some settings like global bantime and other customization. These reported here are the default ones that can fits your installation:

# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space (and/or comma) separator.
ignoreip =

# "bantime" is the number of seconds that a host is banned.
bantime  = 600

# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 600

# "maxretry" is the number of failures before a host get banned.
maxretry = 5

# Default banning action (e.g. iptables, iptables-new,
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overridden globally or per
# section within jail.local file
banaction = iptables-multiport
banaction_allports = iptables-allports

can be more complex parameters to be enabled that, for example, can alert you by mail with whois query included. Just explore the configuration file!

# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
            %(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]

protect sshd

What I prefer is to create a personal and specific fail2ban configuration for every service we expose. Let’s protect our ssh deamon
Copy the jail.conf to /etc/fail2ban/jail.d/sshd.local and edit it:

cp jail.conf /etc/fail2ban/jail.d/sshd.local
vim /etc/fail2ban/jail.d/sshd.local

This configuration and the changes we’ll make here will override the default configuration of jail.local.
This could be a simple configuration


enabled = true
port = ssh

# this will force the system to use IPTABLES for ban the attacker ip
action = iptables-multiport

maxretry = 5
bantime = 600

# specify a path for the log related to fail2ban events
logpath = %(sshd_log)s

that’s it! restart the service every time you make configuration changes

systemctl restart fail2ban

this is the running configuration for iptables just before activating fail2ban

iptables -L -n                                                                                                                                         
Chain INPUT (policy ACCEPT)                                                                                                                                                     
target     prot opt source               destination                                                                                                                            

Chain FORWARD (policy ACCEPT)                                                                                                                                                    target     prot opt source               destination                                                                                                                             

Chain OUTPUT (policy ACCEPT)                                                                                                                                                     target     prot opt source               destination  

after some minutes this is the situation! we already banned an IP!

# iptables -L -n

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
f2b-default  tcp  --              multiport dports 22

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain f2b-default (1 references)
target     prot opt source               destination         
REJECT     all  --            reject-with icmp-port-unreachable
RETURN     all  --             

how to check how many client were banned

# fail2ban-client status sshd                                                                                                                  

Status for the jail: sshd                                                                                                                                                       |- Filter                                                                                                                                                                       |  |- Currently failed: 1                                                                                                                                                       |  |- Total failed:     54
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions                                                                                                                                                                           
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list:                                                                                                    

great! so now what if we need to unban a client that was wrongly inserted into iptables drop list? it’s simple:

fail2ban-client -h

give us a good help in which we can find a lot of information and configuration regarding fail2ban use. To unban an ip just type

set <JAIL> unbanip <IP>                  manually Unban <IP> in <JAIL>

so in our case it became:

fail2ban-client set sshd unbanip


fail2ban is very easy to configure and deploy. Despite this simple installation it can provide a big help to keep your server authentications secure.