Honeypot
Robots aren't our friends!
Sunday hackers either, and you know what? Let's give them a little lesson. You know, people who think stealing grannies will enrich themselves or advance the cause. Often they will either try by hand (if they are lame) to break into a server, or send their compromised pc armada try stuff. All day the internet traffic is saturated with these shitty bots, it's super boring. Here we will set them up and get as much information as possible about them. All of this will be used to feed DIY super blocklists (like the good granny soup) and available on the net for everyone.
Base configuration
Connect to the provider pannel and check the server IP. Let's use ssh to connect to root first. We will create a user with rights now.
adduser honeypot
passwd honeypot
usermod -aG sudo honeypot
- Here we have changed the default port on 5588 (22 is for the honeypot)
- We forbid root connection
- We limit sessions to one
- Also, we block attempts to up to three
- We remove X11 and all horrible stuff
Go to the directory /etc/ssh and open sshd_config and modify with :
Protocol 2
Port 5588
PermitRootLogin no
MaxAuthTries 3
MaxSessions 1
AllowUsers "srv-admin"
DenyUsers root
AuthorizedKeysFile .ssh/authorized_keys
KbdInteractiveAuthentication no
UsePAM yes
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
LoginGraceTime 300
X11Forwarding no
ClientAliveInterval 0
PermitTTY yes
PrintMotd no
Banner /etc/banner.exemple
Subsystem sftp /usr/lib/ssh/sftp-server
LogLevel VERBOSE
Firewalld
Download firewalld and activate the service
sudo apt install firewalld
sudo systemctl enable --now firewalld.service
sudo firewall-cmd --set-default-zone=block
Open ports related to your service list on the "block" profile :
sudo firewall-cmd --add-port=21/tcp --zone=block --permanent
sudo firewall-cmd --add-port=22/tcp --zone=block --permanent
sudo firewall-cmd --add-port=23/tcp --zone=block --permanent
sudo firewall-cmd --add-port=25/tcp --zone=block --permanent
sudo firewall-cmd --add-port=80/tcp --zone=block --permanent
sudo firewall-cmd --add-port=110/tcp --zone=block --permanent
sudo firewall-cmd --add-port=123/tcp --zone=block --permanent
sudo firewall-cmd --add-port=143/tcp --zone=block --permanent
sudo firewall-cmd --add-port=161/tcp --zone=block --permanent
sudo firewall-cmd --add-port=389/tcp --zone=block --permanent
sudo firewall-cmd --add-port=443/tcp --zone=block --permanent
sudo firewall-cmd --add-port=445/tcp --zone=block --permanent
sudo firewall-cmd --add-port=1080/tcp --zone=block --permanent
sudo firewall-cmd --add-port=1433/tcp --zone=block --permanent
sudo firewall-cmd --add-port=1521/tcp --zone=block --permanent
sudo firewall-cmd --add-port=3306/tcp --zone=block --permanent
sudo firewall-cmd --add-port=5060/tcp --zone=block --permanent
sudo firewall-cmd --add-port=5432/tcp --zone=block --permanent
sudo firewall-cmd --add-port=5900/tcp --zone=block --permanent
sudo firewall-cmd --add-port=6379/tcp --zone=block --permanent
sudo firewall-cmd --add-port=6667/tcp --zone=block --permanent
sudo firewall-cmd --add-port=8080/tcp --zone=block --permanent
sudo firewall-cmd --add-port=9200/tcp --zone=block --permanent
sudo firewall-cmd --add-port=11211/tcp --zone=block --permanent
Dont forget your custom ssh port (not the 22 !)
sudo firewall-cmd --add-port=5588/tcp --zone=block --permanent
sudo firewall-cmd --reload
sudo systemctl restart firewalld.service
Fail2ban
Install and enable fail2ban :
sudo apt install fail2ban
sudo systemctl enable --now fail2ban.service
Enable SSH jail :
sudo nano /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 5588
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 1w
Reload and restart fail2ban
sudo systemctl reload fail2ban.service && sudo systemctl restart fail2ban.service
Docker installation
sudo apt update
Install keys and trusted docker repository
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
Update, upgrade and install docker + docker-compose
sudo apt update
sudo apt upgrade
sudo apt install docker-ce docker-compose
Honeypot deployment
Create a base directory, here honeypot-config and add a docker-compose.yml
mkdir honeypot-config
cd honeypot-config
sudo nano docker-compose.yml
Paste this configuration :
version: '3.3'
services:
honeypots:
container_name: honeypots
image: justsky/honeypots:latest # latest, dev
restart: unless-stopped
command: --setup all
# Add your custom path to this folder
volumes:
- './honeypot_logs:/honeypots/logs'
# Dont change the internal ports, change only external
ports:
- 21:21 # FTP
- 22:22 # SSH
- 23:23 # TELNET
- 25:25 # SMTP
- 80:80 # HTTP
- 110:110 # POP3
- 123:123 # NTP
- 143:143 # IMAP
- 161:161 # SNMP
- 389:389 # LDAP
- 443:443 # HTTPS
- 445:445 # SMB
- 1080:1080 # SOCKS5
- 1433:1433 # MSSQL
- 1521:1521 # ORACLE
- 3306:3306 # MYSQL
- 5060:5060 # SIP
- 5432:5432 # POSTGRES
- 5900:5900 # VNC
- 6379:6379 # REDIS
- 6667:6667 # IRC
- 8080:8080 # HTTPPROXY
- 9200:9200 # ELASTIC
- 11211:11211 # MEMCACHE
Deploy the honeypot
sudo docker-compose up -d
Check ports with netstat :
sudo apt install net-tools
sudo netstat -tunlp
Exemple :
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5899 0.0.0.0:* LISTEN 87930/nginx: master
tcp 0 0 0.0.0.0:5900 0.0.0.0:* LISTEN 77829/docker-proxy
tcp 0 0 0.0.0.0:33030 0.0.0.0:* LISTEN 77917/docker-proxy
tcp 0 0 0.0.0.0:33031 0.0.0.0:* LISTEN 77928/docker-proxy
tcp 0 0 0.0.0.0:33028 0.0.0.0:* LISTEN 77896/docker-proxy
tcp 0 0 0.0.0.0:33029 0.0.0.0:* LISTEN 77906/docker-proxy
tcp 0 0 0.0.0.0:5432 0.0.0.0:* LISTEN 77818/docker-proxy
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 77885/docker-proxy
tcp 0 0 0.0.0.0:5060 0.0.0.0:* LISTEN 77804/docker-proxy
tcp 0 0 0.0.0.0:9200 0.0.0.0:* LISTEN 77874/docker-proxy
tcp 0 0 0.0.0.0:1521 0.0.0.0:* LISTEN 77781/docker-proxy
tcp 0 0 0.0.0.0:389 0.0.0.0:* LISTEN 77731/docker-proxy
tcp 0 0 0.0.0.0:1433 0.0.0.0:* LISTEN 77771/docker-proxy
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 77864/docker-proxy
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 77741/docker-proxy
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN 77750/docker-proxy
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 77675/docker-proxy
tcp 0 0 0.0.0.0:110 0.0.0.0:* LISTEN 77684/docker-proxy
tcp 0 0 0.0.0.0:123 0.0.0.0:* LISTEN 77696/docker-proxy
tcp 0 0 0.0.0.0:6667 0.0.0.0:* LISTEN 77850/docker-proxy
tcp 0 0 127.0.0.54:53 0.0.0.0:* LISTEN 8081/systemd-resolv
tcp 0 0 0.0.0.0:1080 0.0.0.0:* LISTEN 77760/docker-proxy
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 77792/docker-proxy
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 77838/docker-proxy
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 8081/systemd-resolv
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 77708/docker-proxy
tcp 0 0 0.0.0.0:161 0.0.0.0:* LISTEN 77718/docker-proxy
tcp6 0 0 :::5900 :::* LISTEN 77834/docker-proxy
tcp6 0 0 :::33030 :::* LISTEN 77923/docker-proxy
tcp6 0 0 :::33031 :::* LISTEN 77932/docker-proxy
tcp6 0 0 :::33028 :::* LISTEN 77902/docker-proxy
tcp6 0 0 :::33029 :::* LISTEN 77913/docker-proxy
tcp6 0 0 :::5432 :::* LISTEN 77822/docker-proxy
tcp6 0 0 :::11211 :::* LISTEN 77890/docker-proxy
tcp6 0 0 :::5060 :::* LISTEN 77813/docker-proxy
tcp6 0 0 :::5588 :::* LISTEN 1/systemd
tcp6 0 0 :::9200 :::* LISTEN 77879/docker-proxy
tcp6 0 0 :::1521 :::* LISTEN 77786/docker-proxy
tcp6 0 0 :::389 :::* LISTEN 77735/docker-proxy
tcp6 0 0 :::1433 :::* LISTEN 77776/docker-proxy
tcp6 0 0 :::8080 :::* LISTEN 77869/docker-proxy
tcp6 0 0 :::443 :::* LISTEN 77746/docker-proxy
tcp6 0 0 :::445 :::* LISTEN 77755/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 77679/docker-proxy
tcp6 0 0 :::110 :::* LISTEN 77691/docker-proxy
tcp6 0 0 :::123 :::* LISTEN 77701/docker-proxy
tcp6 0 0 :::6667 :::* LISTEN 77856/docker-proxy
tcp6 0 0 :::1080 :::* LISTEN 77765/docker-proxy
tcp6 0 0 :::3306 :::* LISTEN 77798/docker-proxy
tcp6 0 0 :::6379 :::* LISTEN 77844/docker-proxy
tcp6 0 0 :::143 :::* LISTEN 77712/docker-proxy
tcp6 0 0 :::161 :::* LISTEN 77724/docker-proxy
List generation
We will now look at the generation of lists so that we can then retrieve them on the platform we want If you look in the log folder, you can see that many files are present.
If you let the trap run a bit and look in the http.log file
Many queries are present and it shows that it works, it says the format is different depending on the services, we will have to clean it and send it to a new file.
cd /home/honeypot/honeypot-config
mkdir listes
touch daily.sh
chmod +x daily.sh
sudo nano daily.sh
We will make a script that will run commands to recover ip in all log files. Then we will put the file in the previously created list folder. Here is the content of the script
cat /home/honeypot/honeypot-config/honeypot_logs/* >> /home/honeypot/honeypot-config/listes/ip.txt.tmp
cat /home/honeypot/honeypot-config/listes/ip.txt.tmp | grep -oP '"src_ip": "\K[^"]+' $FILE | sed 's/"//g' | sort | uniq > /home/honeypot/honeypot-config/listes/ip.txt
rm -rf /home/honeypot/honeypot-config/honeypot_logs/*.logs
rm -rf /home/honeypot/honeypot-config/honeypot_logs/honey*
rm -rf /home/honeypot/honeypot-config/listes/ip.txt.tmp
If you display the generated ip.txt file, you will see that this is much better
Now it's time to make sure we can get it back. Here I would make it available with a web server on a non-standard port. A script in my rest will curl the file in order to recover its content every night.
cron task
Since I use ubuntu, cron is already installed and preconfigured. In a more modern approach we could have made a systemd service (which is much better). Here for simplicity reasons, we will just add the script in cron.
sudo crontab -e
add this
0 2 * * * /home/honeypot/honeypot-config/daily.sh
Lists will update every day at 2am
Serve file
Now let's make our blocklist available with a simple web server
sudo apt install nginx
Go to the site-available nginx directory
cd /etc/nginx/sites-availables
Create a configuration for the website with 5899 port :
server {
listen 5899;
# Define the root directory for your static files
root /home/honeypot/honeypot-config/listes;
# Configure access to static files
location /ip.txt {
}
# Additional configuration options can be added here
# Define access log and error log locations
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# Add any other server-specific configurations here
if ($block_ua) {
return 403;
}
}
Restart nginx and check the website "http://ServerIP:5899/ip.txt"
sudo systemctl reload nginx && sudo systemctl restart nginx
Nice, it's works !
Curl this page to get the list.
AbuseIP Reporting
Create an account on AbuseIP (best website for malicious ip reporting) In your profile, check your API key. Create a bash script :
sudo nano report-abuseip-v2.sh
#!/bin/bash
ABUSE_IP_DB_API_KEY="XXXXXXXXXXXXXXXXXXXX"
REPORTED_FILE="/home/honeypot/honeypot-config/listes/reported.txt" #Reported-ip-logs
report_ip() {
local ip=$1
# Trim leading and trailing whitespace and carriage returns
ip=$(echo "$ip" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/\r//')
# Validate the IP format (basic validation)
if [[ ! $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid IP address format: $ip"
return 1
fi
# Send the report to AbuseIPDB API
response=$(curl -s -w "%{http_code}" -o /tmp/response_body.txt "https://api.abuseipdb.com/api/v2/report" \
-H "Key: $ABUSE_IP_DB_API_KEY" \
-d "ip=$ip" \
-d "categories[]=10" \
-d "categories[]=18" \
-d "categories[]=21" \
-d "categories[]=15" \
-d "comment=Multiple attacks on Honeypot servers")
response_code=$(tail -n1 <<< "$response")
response_body=$(cat /tmp/response_body.txt)
if [[ "$response_code" == "200" ]]; then
echo "Successfully reported IP: $ip"
else
echo "Failed to report IP: $ip"
echo "HTTP Status Code: $response_code"
echo "Response Body: $response_body"
fi
}
read_report_file() {
local file=$1
# Make sure the file exists before attempting to read
if [ ! -f "$file" ]; then
echo "Error: File not found: $file"
exit 1
fi
while IFS= read -r line; do
# Skip empty lines and lines starting with a comment (if any)
[[ -z "$line" || "$line" =~ ^# ]] && continue
report_ip "$line"
done < "$file"
}
if [ $# -eq 0 ]; then
echo "Usage: $0 <ip_address> | <report_file>"
exit 1
fi
if [ $# -eq 2 ] && [ -f "$2" ]; then
read_report_file "$2"
elif [ $# -eq 1 ] && [ -f "$1" ]; then
read_report_file "$1"
else
report_ip "$1"
fi
This script can report a file and push on AbuseIP with categories "bruteforce", "web attack", "spam", "hacking" ...
I'm adding a message "Multiple attacks on Honeypot servers"
If we run the script :
Here exemple for bruteforce :
Edit cron tasks :
sudo nano crontab -e
Paste :
0 3 * * * /home/honeypot/honeypot-config/report-abuseip-v2.sh ./listes/ip.txt
At 3am, the server will send the entire ip found on the previous day.
Base Hardening
Hardening on this part consists of some key steps that reduce the attack surface. A honeypot is a server that is targeted by very large amounts of ip every day and we want it to be robust to trap as many bots as possible without maintenance. The classic protections are already there for the ssh and fail2ban, here we will concentrate on preventing a privilege escalation in case of compromise of one of the elements.
We're going to make it impossible to use the root account and access its shell in case of privilege elevation or bad exploit !
Modify the /etc/passwd file and change root line with :
root:x:0:0:root:/root:/sbin/nologin
Disable TTY access :
sudo rm -rf /etc/securetty
sudo touch /etc/securetty
sudo chmod 600 /etc/securetty
Enforce the PAM configuration :
sudo nano /etc/pam.d/login
auth required pam_listfile.so \
onerr=succeed item=user sense=deny file=/etc/ssh/deniedusers
Restric file modification :
chmod 600 /etc/ssh/deniedusers
Edit the file sudo nano /etc/ssh/deniedusers and add "root"
Disable root password and groups :
sudo passwd -l root
sudo usermod -L root
Okay root now is safe, we can move on!
Apparmor
First install apparmor (under ubuntu it is already present and preconfigured).
This is a MAC protection that reduces potential interrelation between processes. A docker profile is present (attention, only rootfull, otherwise you will have to point to podman and why not SElinux).
sudo apt install apparmor apparmor-utils
Modify the kernel parameters on the /boot and add this line :
lsm=landlock,lockdown,yama,integrity,apparmor,bpf
Enable the service, reboot and enforce profiles :
sudo systemctl enable apparmor.service
sudo aa-enforce /etc/apparmor.d/*
Nginx Hardening
Enforce the nginx configuration with these elements :
server {
listen 5899;
# Define the root directory for your static files
root /home/honeypot/honeypot-config/listes;
# Configure access to static files
location /ip.txt {
if ($server_protocol = HTTP/1.0) {
add_header Upgrade "HTTP/2.0";
add_header Connection "Upgrade";
return 426 "Upgrade Required: Upgrade your client to support more modern HTTP protocol";
break;
}
limit_except GET {
deny all;
}
add_header X-Frame-Options "DENY";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com;";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "no-referrer";
add_header Permissions-Policy "geolocation=(); midi=(); notifications=(); push=(); sync-xhr=(); accelerometer=(); gyroscope=(); magnetometer=(); payment=(); usb=(); vr=(); camera=(); microphone=(); speaker=(); vibrate=(); ambient-light-sensor=(); autoplay=(); encrypted-media=(); execute-clipboard=(); document-domain=(); fullscreen=(); imagecapture=(); lazyload=(); legacy-image-formats=(); oversized-images=(); unoptimized-lossy-images=(); unoptimized-lossless-images=(); unsized-media=(); vertical-scroll=(); web-share=(); xr-spatial-tracking=();";
server_tokens off;
}
location ~ \.(7z|asp|aspx|bak|bz|bz2|cer|cgi|conf|crt|gz|ini|jsp|key|log|pem|php|php7|rar|sh|sql|tar|zip)$ {
return 403;
break;
}
# Additional configuration options can be added here
# Define access log and error log locations
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# Add any other server-specific configurations here
if ($block_ua) {
return 403;
}
if ($is_blocked_common_exploits_path) {
return 403;
}
}
map $request_uri $is_blocked_common_exploits_path {
"~*//" 1;
"~*(boot.ini|etc/passwd|self/environ)" 1;
"~*(%2e%2e|%252e%252e|%u002e|%c0%2e)" 1;
"~*(\.\./\.\./|\.\.\.|%252e%252e%252e)" 1;
"~*(~|`|<|>|:|;|{|}|\[|\]|\(|\))" 1;
default 0;
}
We find essential limitations for our case, such as forcing HTTP2 or limiting only GET requests, which prevents someone from sending data to our machine (to retrieve the blocklist, this will be largely enough).
The headers required for protection against XSS injections are added.
I also took the initiative to prohibit any access to the types of interesting files, in case someone could make a directory listing or a missconfiguration arrives. At the end of the file, you can see some path traversal blockage that I could find on the net, which allows to reinforce all this.
A file blacklist-UA.conf is created in /nginx and present with an include in nginx.conf:
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
include blacklist-UA.conf;
Content :
map $http_user_agent $block_ua {
default 0;
~*profound 1;
~*scrapyproject 1;
~*netcrawler 1;
~*nmap 1;
~*sqlmap 1;
~*slowhttptest 1;
~*nikto 1;
~*jersey 1;
~*brandwatch 1;
~*magpie-crawler 1;
~*mechanize 1;
~*python-requests 1;
~*redback 1;
~*python 1;
~*wget 1;
~*Pcore-HTTP 1;
~*HTTrack 1;
}
This file protect with suspect user agent detection on the website (nmap, sqlmap, nikto scanner, python ...). Avoid scanner and enumeration on the honeypot.
This hardening part will be improved over time. I strongly recommend following OWASP for good base security.