SSH Architecure using IDS, IPS, Port Knocking and SIEM System

Hi guys thank you for deciding to take a look at this blog. Enjoy

Generally, the main objective of this project is to design an SSH architecture that is resilient to SSH Brute Force attacks and to discover any new methods used by attackers. So generally there are a few tools and softwares integrated with each other to reach this objective. The tools are :

  1. Cowrie (Honeypot)

  2. Knockd (Port Knocking)

  3. Suricata (IDS)

  4. Fail2ban (IPS)

  5. Wazuh (SIEM System)

Feel free to skip the paragraphs below if you already know the meaning of honeypot, IDS etc.

A honeypot is a security mechanism designed to mimic a vulnerable target, luring attackers to interact with it and revealing their tactics. It helps organizations detect, analyze, and understand threats by acting as a decoy without putting actual systems at risk. Port knocking is a security method that restricts access to network services by requiring a specific sequence of connection attempts to closed ports before access is granted. This technique enhances security by keeping services hidden from potential attackers until the correct "knock" sequence is received.

An Intrusion Detection System (IDS) monitors network traffic and system activities for suspicious behavior, generating alerts for potential threats or policy violations. It can be categorized as either network-based (NIDS) or host-based (HIDS), and it primarily detects known threats through signatures or identifies anomalies against established baselines. IDS monitors network traffic for suspicious activity and generates alerts, while Intrusion Prevention System (IPS) actively blocks detected threats and unauthorized access attempts. While both systems aim to enhance network security, IDS focuses on detection and alerting, whereas IPS focuses on prevention and response. A Security Information and Event Management (SIEM) system collects, analyzes, and correlates security data from across an organization's IT environment, including logs from servers, network devices, and applications. It provides real-time monitoring, threat detection, and incident response capabilities, allowing security teams to identify and respond to potential threats more effectively while also helping with compliance and reporting.

HOW DO THEY WORK TOGETHER ?

The Architecture

Basically the flow is like this : -

1

Hacker

The hacker stumbles upon a public-facing website set up by the admin. Starts port scanning to reveal available ports.

2

Knockd

Port 22 of the website would be displayed as closed because Knockd closes it by default. It is only opened once a port knocking sequence of 3 ports is supplied by the hacker.

3

Hacker

(for some reason the hacker manages to guess the port sequence)

The hacker is greeted by SSH login session where he starts brute forcing for the correct password.

4

Suricata

Detects the brute force attack and generates an alert in its log file.

5

Fail2ban

Fail2ban detects SSH brute force alert in the log file extracts and blocks the hacker's IP address to prevent further connection.

Generates an alert to notify sysadmin that a blocking has been implemented.

6

Wazuh

Aggregates all logs, generates alerts as well as visualizations and providing near real-time security monitoring dashboard.

SETUP & CONFIGURATIONS

🎯 Web Page

For this part, a cloud-based VM will host the web server. A simple page consisting of login page is constructed and hosted publicly. This is the page that the attacker will stumble upon. I just used html and css for this part.

Webpage

I signed up for the GCP free trial and got some free credits to purchase some VM's. The specification I used for both VM's can be found in the table below. For the tutorial on how to set up a webpage in Linux, you can look it up on the internet because it took only 15 minutes at most.

Operating System
Ubuntu 22.04 LTS

Processor

AMD EPYC 7B12

RAM

4 GB

Storage

100 GB

System Architecure

x86_64


🎯 GCP

I used GCP as my cloud provider where I will get my VM's from here. Some configurations need to be made as cloud-based vm utilizes cloud firewall. If you use Digital Ocean droplets, port 22 is open by default.

  • To access the machine via SSH from my local CLI, I need to create a firewall rule allowing incoming connections on port 8742, the new port for the real SSH server. The actual SSH server was moved to this port to let Cowrie use port 22. This will be explained in the next section.

  • Create a rule to allow inbound traffic to port 80 and 443 for Wazuh and for people to actually "stumble" upon the website.

  • Setting up a public-private key pair on the GCP machine for SSH access is optional and can be easily done using the many tutorials available online. Once configured, you can connect to the machine using a command like the one below, where the -i flag specifies the private key.

ssh -p 8742 -i ~/.ssh/ssh_pot owenira@34.125.184.125

🎯 Iptables

This part is a little bit tricky but it's actually easy to configure, it's just me that took a long time on this part. Okay so we all know iptables is a utility to create firewall rules. Let's talk about our first line of defense first which is Knockd (Port Knocking). Its job is to open port 22 once a correct port knocking sequence is made against it. So we need to block any connections to port 22 first. This is where iptables comes in.

The first command here is to allow incoming packets that are part of established or related connection. The second one is the rule that rejects any incoming connections to port 22. Note that -A is used to append the rule to the end of the rule list. Keep in mind that iptables processes rules sequentially from top to bottom, so the first rule must be placed above the rule blocking port 22. Essentially, iptables will let any established connection to go through instead of blocking them.

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j REJECT

Note that Knockd and Fail2ban also use iptables to apply firewall rules so iptables configuration doesn't end here, there will be chapters explaining the other configurations for Knockd and Fail2ban.


🎯 Cowrie Setup

If you look in the architecture image at the beginning of this blog, Cowrie (honeypot) will be installed in VM1, so follow the instructions in this LINK. Follow step 1,2,3,4 and 6 skipping step 5 because Telnet is not needed here. In step 1, I added virtualenv python3.10-venv at the end because it seems to work out instead of the original command.

sudo apt-get install git python3-venv libssl-dev libffi-dev build-essential libpython3-dev python3-minimal authbind virtualenv python3.10-venv
Dependencies

Just to make sure Cowrie is up and running, head over to /var/log/cowrie and open the cowrie.log file. Any command entered in the honeypot will be recorded in this log file. I like to use tail -f command to display the file content in real time. You also can try login to the honeypot using root@[ip address].

Use these command below to allow Cowrie to operate on port 22 because any ports under 1024 require root privilege. Authbind is used to grant the cowrie user permission to bind to port 22 safely, without running Cowrie as root.

sudo touch /etc/authbind/byport/22
sudo chown cowrie /etc/authbind/byport/22
sudo chmod 777 /etc/authbind/byport/22

Next, move the real SSH server to another port so that the default port for SSH will be used by Cowrie, to mimic a real SSH server. Open up SSH configuration file at /etc/ssh/sshd_config and look for "Port 22". Uncomment it and change the port number to your desired one. Don't forget to take note of this port number as you don't want to go back and forth to this config file. Save the changes made and restart SSH service using command below

sudo systemctl restart sshd
ssh config file

Next, set Cowrie to use port 22 after the actual SSH server is relocated. Use the commands below to make a copy of cowrie.cfg.dist and make changes in the copy file. Save the file.

sudo su - cowrie
cd cowrie
cd etc
cp cowrie.cfg.dist cowrie.cfg
nano cowrie.cfg

The next thing we wanna do is change Cowrie login credentials. One thing to note about Cowrie is it has a built-in credentials recording feature where it tracks what credentials people are using to log in to the honeypot. This means that Cowrie accepts all usernames and passwords, there is no right and wrong. So right now we have to set the only correct username and password so that attackers would have to brute force attack the SSH login daemon. Use commands below to do that.

cp userdb.example userdb.txt
Nano userdb.txt

Lastly use the command below

authbind --deep /home/cowrie/cowrie/bin/cowrie start

🎯 Knockd Setup

Before you continue, dont' be confused because the VM name in the below image and the above image is different. I had to delete the harun-virtual-machine instance because it ran into some problems. Even though their names are different, just consider them VM1 ahahah it's just I'm too lazy to setup Cowrie on the new machine (honeypot).

Okay so Knockd also should be installed on VM1. Run the command as seen in the image below. Run sudo systemctl status knockd to double check.

Edit /etc/knockd.conf to modify the port knocking sequence. At the openSSH section, the command's purpose is to allow access to port 22 if the port knocking sequence provided by the attacker is correct. Notice that I changed the -A to -I, this is because we need the command to be inserted at the top of any other rules in the list of iptables rules. In other words, this command (allow access) will be processed first before the port 22 blocking rule we set earlier. Remember that iptables processes rules from top to bottom :)

The closeSSH section's command is to delete rule if a command triggers it. (There is a knockd command to close the port 22 back if we open it by providing the correct port knocking sequence).

To start Knockd, change the number uncomment the START_KNOCKD and change the value from 0 to 1. Uncomment the KNOCKD_OPTS and replace the "eth1" with the name of VM1 network connection, in my case, it's ens4. Save the changes.


🎯 Suricata

Of course, Suricata is also installed on VM1 to monitor the honeypot. Confirm it using systemctl.

sudo apt install suricata

There are some modifications needed in the Suricata configuration file (Suricata.yaml). Open /etc/suricata/suricata.yaml file and make changes as the following :

  1. Change the HOME_NET value to the ip address of the machine Suricata is going to monitor which is VM1.

  1. Search "af-packet" and put the interface name of VM1

  1. Update the interface name of VM1

  1. Save the file and type suricata-update command to save the update made to the config file

Remarks (Suricata)

  • Default rule file : /var/lib/suricata/rules/suricata.rules

  • Default log path : /var/log/suricata/fast.log

  • To test Suricata config file : sudo suricata -T -c /etc/suricata/suricata.yaml -v


🎯 Fail2ban

There are two things you have to set up fail2ban other than installing it. First one is making a .conf file in each of jail.d and filter.d directories. The file in jail.d is called jail file and the file in filter.d is called filter file. Generally, jail.conf file is to specify the actions that Fail2ban will make once it detects SSH brute force alerts in the Suricata log file while filter.conf file is to detect specific alert pattern in Suricata log file (in this case, brute force alert pattern).

Jail File

  1. Go to the jail.d directory and make a file with the conf extension. It also specifies attributes like maxretry. Below is my conf file. You can use this link as a guide.

Jail File

Filter File

  1. Create a file with conf extension in the filter.d directory

  2. Declare two variables in the file which are failregex (regex pattern) to detect specific pattern in Suricata log file. ignoreregexvar is to ignore alert that contains the ip address specified, in this case that's my local machine IP because I just don't want my ip to be blocked. Keep in mind that you have to set the regex based on Suricata's SSH brute force attack alert. Below you can see the alert I use as reference to craft the regex.

SSH brute force alert
Filter File

Telegram Notification

As for Fail2ban to send a notification to telegram, a telegram bot needs to be made. Get your Chat ID and API token from Check Telegram ID bot and BotFather bot respectively.

  1. Create a directory called scripts

  2. Program a bash script and put it into the scripts dir. I used a script from AmirHosseinKarimi github repo

  3. Put the Chat ID and API token in the code at their right place as shown below

  1. Save the file

    1. Make a telegram.conf file in /etc/fail2ban/action.d. This file will execute the fail2ban-telegram.sh file with the given arguments. Notice that in the jail file we created earlier, there is the word “telegram” specified in the action variable. It is there to execute the telegram.conf in the action.d directory.

Conclusion (fail2ban)

For more clarification : - filter file is to detect for specific pattern in Suricata log file. Jail file is to specify the action taken, in this case, jail file will ban the ip address because in the jail file, the iptables-multiport is actually a file called iptables-multiport.conf in action.d directory. In the action variable, it is specified to use the iptables-multiport and telegram configuration file.

As for the telegram part, the flow is like this : - filter file will detect a pattern in Suricata log file and jail file will specify the actions taken as a response to the Suricata alert found thanks to filter file. One of the actions taken in the jail file is actually using telegram.conf file which will execute the telegram.sh script. The script will send a notification to telegram bot.


🎯 Wazuh

  1. Install Wazuh using this one liner from this Wazuh documentation. You will get a username and password from the installation. Use them to log into the Wazuh web interface by going to https://[VM2 ip address]:443 as stated in the installation. Remember that Wazuh is installed on a seperate VM as Cowrie, Suricata, Knockd and Fail2ban. Keep in mind, the command below might have been updated in the documentation.

curl -sO https://packages.wazuh.com/4.9/wazuh-install.sh && sudo bash ./wazuh-install.sh -a
  1. Register an agent. Agent is a machine that Wazuh will monitor and get the logs from.

  2. Enter the information needed like server address (VM2) and agent name. The last step from Wazuh is entering the commands given on the machine you're going to monitor, in this case VM1.

  3. There should be an agent added to the Wazuh dashboard as per below

Wazuh Manager
  1. Access VM1 and open the file /var/ossec/etc//ossec.conf and add these lines at then end. This allows the agent (VM1) to send Suricata log file to Wazuh (VM2). Add these lines also at the end of the Manager Configuration in the Wazuh dashboard. Click save and restart Manager.

Wazuh Agent
Wazuh Manager

ATTACK SIMULATION & ADMIN'S POV

For this part, brute force attack simulations will be carried out to test the architecture's effectiveness and ability to perform the actions intended as a response to the attacks.

Recon

Let's say I am the hacker, I have stumbled upon the webpage and already got the IP address of the webpage via nslookup. At this early stage, I want to gain as much information as I want, so I will actively engage with the webpage.

  1. Ping the machine to see if it is up and running. As you can see, result shows 0% packet loss which means the machine is running.

Ping
  1. Perform port scanning to discover available ports on the machine. Port 22 is closed because Knockd closes it by default.

Nmap scan

Login Tries

At this stage, I would try my luck if the web admin is using any weak credentials like "admin" and "root" as the password but clearly the connection is refused due to Knockd getting on my way. Next, I try to do port knocking and for the sake of testing the Fail2ban Suricata and Wazuh at later stages, I used the correct port knocking sequence. As you can see, the connection is not refused after i knock those ports.

Below image is the admin's POV as he looks into the Knockd log file. It detects the correct port knocking sequence and applies iptables rule to open port 22 for the corresponding IP address.

Knockd log file

As for admin's POV again, if we look into the below image, the iptables rule applied by Knockd successfully got into the KNOCKD chain in iptables

Iptables

Brute Force Attack

The only obstacle that is on my way now is I don't know the password to login. Thus I will leverage Hydra to perform SSH brute force attack. Some information needed to be supplied to Hydra like the wordlist, username, IP address and the protocol that is going to be attacked.

Hydra

Below image is the attack displays "Connection refused" because Suricata and Fail2ban already detected and blocked my hacker IP address from connecting to the machine. To double confirm, I can ping the machine once again and the result would be "Port Unreachable".

As from admin's POV, below image shows an alert gets generated in Suricata log file recording the brute force attack.

Suricata log file

Fail2ban log file below shows my IP address getting found in Suricata log file and banned immediately. In this case, me as the admin configured Fail2ban to block the IP address for 5 minutes, note that you can customise how long does Fail2ban takes to unban the IP address.

Fail2ban log file

As soon as Fail2ban banned the IP address, the admin will be notified via Telegram chatbot. Same case as when Fail2ban unbans the IP.

The Suricata alert also being forwarded to Wazuh Manager (Wazuh dashboard) for further investigation.

Wazuh Manager

Last updated

Was this helpful?