Smart Honeypot that Returns Attacks to the Attacker

The Attacker’s Infinite Loop

In this guide, I will teach you how to deploy a honeypot that not only simulates services running on certain ports but also applies dynamic rules so that any attacker who connects… ends up attacking themselves haha.

Ideal to entertain yourself while exhausting the patience and resources of the attacking bot.

What do we need?

Very little, just a Linux system—in our case, Debian 12—and install iptables so our honeypot works, plus tcpdump to actually see it in action.

sudo apt install -y iptables tcpdump

Once we have what we need, for the system to redirect incoming connections to another IP (in this case, back to the attacker themselves), we have to enable IP forwarding. The code provided later already does this when executed, but if you want to remove it from the script, you’ll have to enable it permanently like this:

echo “net.ipv4.ip_forward = 1” | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

How does it work?

It’s simple. We’ll launch fake services on all the ports we want and be even more annoying: on the first connection, we’ll show a banner very slowly. When the banner finishes displaying, it will create two iptables rules: one DNAT to redirect all future traffic from that attacker back to themselves, and one MASQUERADE so the attacker’s system doesn’t discard the traffic for not recognizing the source.

Now all that’s left is to create our honey. Create the file /opt/honeypot/honeypot.py with the following content:

				
					import socket
import threading
import time
import subprocess
import logging
import uuid
import sys
from logging.handlers import RotatingFileHandler
import gzip
import os

HONEYPOT_PORTS = [21, 23, 80, 443, 2222, 3306, 3389, 4000, 8080, 8443, 10000]
BANNER = "Welcome \nUnauthorized access is prohibited\n"
CHAR_DELAY = 0.3  # Seconds per character for banner delay

class CompressedRotatingFileHandler(RotatingFileHandler):
    def doRollover(self):
        super().doRollover()
        if self.backupCount > 0:
            old_log = f"{self.baseFilename}.1"
            if os.path.exists(old_log):
                with open(old_log, 'rb') as f_in, gzip.open(old_log + '.gz', 'wb') as f_out:
                    f_out.writelines(f_in)
                os.remove(old_log)

logger = logging.getLogger()
logger.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')

file_handler = CompressedRotatingFileHandler(
    '/var/log/honeypot.log', maxBytes=1_000_000_000, backupCount=5)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)


def create_firewall_rules(attacker_ip, local_port):
    dnat_cmd = [
        "iptables", "-t", "nat", "-A", "PREROUTING",
        "-s", attacker_ip, "-p", "tcp", "--dport", str(local_port),
        "-j", "DNAT", "--to-destination", f"{attacker_ip}:{local_port}"
    ]

    masq_cmd = [
        "iptables", "-t", "nat", "-A", "POSTROUTING",
        "-p", "tcp", "-d", attacker_ip, "--dport", str(local_port),
        "-j", "MASQUERADE"
    ]

    logger.info(f"Applying DNAT rule: {attacker_ip}:{local_port} -> {attacker_ip}:{local_port}")
    subprocess.call(dnat_cmd)

    logger.info(f"Applying MASQUERADE rule for {attacker_ip}:{local_port}")
    subprocess.call(masq_cmd)


def send_slow_banner(conn):
    try:
        for char in BANNER:
            conn.send(char.encode())
            time.sleep(CHAR_DELAY)
    except Exception as e:
        logger.error(f"Error sending banner: {e}")


def handle_connection(conn, addr, port):
    ip, src_port = addr
    session_id = uuid.uuid4()
    logger.info(f"Session {session_id} started from {ip}:{src_port} on port {port}")

    send_slow_banner(conn)
    create_firewall_rules(ip, port)

    try:
        while True:
            data = conn.recv(1024)
            if not data:
                break
            data_str = data.decode(errors='ignore').strip()
            logger.info(f"Session {session_id} received data: {data_str}")
            conn.send(b"Access denied\n")
    except Exception as e:
        logger.error(f"Session {session_id} error with {ip}:{src_port} - {e}")
    finally:
        conn.close()
        logger.info(f"Session {session_id} closed with {ip}:{src_port}")


def listener(port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('0.0.0.0', port))
    sock.listen(5)
    logger.info(f"Honeypot listening on port {port}")

    while True:
        conn, addr = sock.accept()
        thread = threading.Thread(target=handle_connection, args=(conn, addr, port))
        thread.daemon = True
        thread.start()


def enable_ip_forwarding():
    try:
        subprocess.call(["sysctl", "-w", "net.ipv4.ip_forward=1"])

        with open("/etc/sysctl.conf", "r") as sysctl_file:
            lines = sysctl_file.readlines()

        forwarding_line = "net.ipv4.ip_forward = 1\n"
        if forwarding_line not in lines:
            with open("/etc/sysctl.conf", "a") as sysctl_file:
                sysctl_file.write("\n" + forwarding_line)

        subprocess.call(["sysctl", "-p"])
        logger.info("IP forwarding enabled")
    except Exception as e:
        logger.error(f"Error enabling IP forwarding: {e}")


def main():
    logger.info("Infinite honeypot starting...")
    enable_ip_forwarding()

    for port in HONEYPOT_PORTS:
        thread = threading.Thread(target=listener, args=(port,))
        thread.daemon = True
        thread.start()

    try:
        while True:
            time.sleep(10)
    except KeyboardInterrupt:
        logger.info("Honeypot terminated")


if __name__ == '__main__':
    main()
				
			

As you can easily see in the code, we simply put the fake ports we want in HONEY_PORTS, customize the banner as you like, and set CHAR_DELAY — the higher it is, the slower the characters display on the first connection.

Now we run it. There are two options: run it manually, which is ideal the first time to see how it works, with:

sudo python3 /opt/honeypot/honeypot.py

And then we can create it as a service:

sudo nano /etc/systemd/system/honeypot-loop.service

And paste:

				
					[Unit]
Description=Infinite Attacker Loop Honeypot
After=network.target

[Service]
ExecStart=/usr/bin/python3 /opt/honeypot/honeypot.py
Restart=always
User=root

[Install]
WantedBy=multi-user.target

				
			

We enable and start it with:

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable honeypot-loop.service
sudo systemctl start honeypot-loop.service

With this, our honey loop would be ready.

How can I test it?

The easiest way is with a telnet to a port we set in the script and that our attacking machine also listens on, so we can see how after the first connection and the banner finishes displaying, it connects us back to our own machine. We will do the test in the lab with port 4000.

start honeypot

From our attacking machine we launch the first telnet to port 4000:

telnet 192.168.1.148 4000

telnet puerto 4000

Now if we launch a second telnet it will not show us the banner, because it will actually connect to the attacker’s machine which also has port 4000 open:

telnet redirigido

In our honeypot we can also see using tcpdump, with this command:

sudo tcpdump -n host 192.168.1.139 and port 4000

How to redirect the connection to the attacker’s IP:

comprobar redireccion tcpdump

You can find the logs in /var/log/honeypot.log

If you want to delete the iptables rules to run tests from scratch, just run:

sudo iptables -t nat -F

Keep in mind that this is done on a LAN and can be very entertaining to confuse the cybersecurity auditor who comes to your company, even by placing a banner for each port like the real service. If you expose it to the internet and the machine has a direct public IP, you won’t have to do anything except expose only the fake ports you want and, if you want, set default iptables policies for INPUT and FORWARD in DROP and a basic anti-Dos:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

iptables -A INPUT -p tcp –dport Number_Port -m connlimit –connlimit-above 5 -j REJECT

But that’s a matter of taste. If you put it behind a firewall, as usual, you’ll have to redirect ports and, in some cases, configure iptables to preserve headers.

That’s all, have a nice weekend.

TL.

Thanks for reading our posts.

FAQs

A honeypot is like a bait you set up to entice hackers to break into your system instead of your real system. This way, you can see what they’re trying to do, how they attack, and learn how to better protect yourself.

Yes, as long as you only expose the honeypot ports and keep everything else closed. The honeypot doesn’t provide real access to the system and simply simulates services, but it’s recommended to use it in controlled environments and monitor traffic to avoid risks.

Don’t worry, it’s designed to catch and study attackers without them being able to harm what you truly care about. It’s like a safe trap you can use to spy on the “bad guys” and learn how to protect yourself.

Deja tu comentario

Your email address will not be published. Required fields are marked *

Últimos artículos

robot web browser

Har2locust

Creating a Locust file with Har2Locust As promised, if you have followed the locust.io post:

Más visitados