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 :
Cowrie (Honeypot)
Knockd (Port Knocking)
Suricata (IDS)
Fail2ban (IPS)
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 ?

Basically the flow is like this : -
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.

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.
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.
🎯 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.
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.

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.
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

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.
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.
Lastly use the command below
🎯 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.
There are some modifications needed in the Suricata configuration file (Suricata.yaml). Open /etc/suricata/suricata.yaml file and make changes as the following :
Change the HOME_NET value to the ip address of the machine Suricata is going to monitor which is VM1.

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

Update the interface name of VM1

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
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.

Filter File
Create a file with conf extension in the filter.d directory
Declare two variables in the file which are
failregex
(regex pattern) to detect specific pattern in Suricata log file.ignoreregex
var 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.


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.
Create a directory called scripts
Program a bash script and put it into the scripts dir. I used a script from AmirHosseinKarimi github repo
Put the Chat ID and API token in the code at their right place as shown below

Save the file
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
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.
Register an agent. Agent is a machine that Wazuh will monitor and get the logs from.
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.
There should be an agent added to the Wazuh dashboard as per below

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.


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.
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.

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

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.

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

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.

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.

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.

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.

Last updated
Was this helpful?