Portspoof
Portspoof emulates open ports and service signatures across all 65535 TCP ports, turning the reconnaissance phase from a quick scan into a long, resource-intensive process. Scanners see thousands of convincing but fake services, making it impractical to identify the real attack surface.
The primary goal of Portspoof is to make reconnaissance slow, costly, and unreliable for attackers. Instead of a standard 5-second Nmap scan that maps every real service on a system, an attacker facing Portspoof sees 65535 open ports, each running what looks like a different legitimate service. There is no quick way to tell which ones are real.
SYN+ACK for every connection attempt.nmap -sV -p-) goes well beyond practical limits.Example Nmap Scan:
$ nmap -p 1-20 target
Starting Nmap 7.80 ( https://nmap.org )
Nmap scan report for target
Host is up (0.00016s latency).
PORT STATE SERVICE
1/tcp open tcpmux
2/tcp open compressnet
3/tcp open compressnet
4/tcp open unknown
5/tcp open rje
6/tcp open unknown
7/tcp open echo
8/tcp open unknown
9/tcp open discard
10/tcp open unknown
11/tcp open systat
12/tcp open unknown
13/tcp open daytime
14/tcp open unknown
15/tcp open netstat
16/tcp open unknown
17/tcp open qotd
18/tcp open unknown
19/tcp open chargen
20/tcp open ftp-data
Portspoof responds to service probes with valid, dynamically generated signatures based on a massive regular expression database. As a result, an attacker will not be able to determine which port numbers your system is truly using.
Example Version Scan (ports 1–100):
…
Combined, these techniques mean:
nmap -sV -p-) with default tarpit settings takes 10+ hours and generates hundreds of megabytes of bogus data.Real services (SSH, SMTP, FTP, HTTP) send a banner and keep the connection open, waiting for client input. Convincing emulation means doing the same: accept, send, hold. But a thread-per-client model burns memory and CPU on context switching, and at scale the defender runs out of resources before the attacker runs out of patience. The deception tool becomes a self-DOS vector.
The approach: a single-threaded epoll event loop. Each port is assigned a delivery mode at startup: some push a banner immediately, some wait for the client to send data before responding, and some stay silent. Hold times are spread across orders of magnitude (tens of milliseconds to minutes) with per-connection jitter, so repeated probes to the same port don't return identical timing.
This matters because without it, an attacker can send garbage to every port and measure response timing: real services close fast (wrong protocol), while a naive tarpit holds for seconds. With mixed modes and a wide timing spread, thousands of fake ports also close in the same range as real services. There's no clean threshold to filter on.
The economics work because of asymmetry:
Per-port delivery modes are fixed for the lifetime of the process but unpredictable across restarts. Hold times have a per-connection random component so repeated probes show natural variance, similar to real services under load.
v2.0 replaces the original banner-and-close behavior that was vulnerable to a connection-closure bypass (see Vicarius/Hored1971 blog post). The tarpit engine holds all connections open with mixed timing, defeating connection-closure filtering, timing fingerprinting, banner analysis, and statistical pattern modeling.
Ensure you have a C++ compiler and CMake (3.10+) installed.
mkdir build && cd build
cmake -DCMAKE_INSTALL_SYSCONFDIR=/etc ..
make
sudo make install
Portspoof runs in userland but relies on system firewall rules to intercept traffic destined for other ports.
Redirect all incoming TCP traffic (ports 1-65535) to the Portspoof port (default 4444).
Linux (iptables):
# Exclude real services first, then redirect the rest to Portspoof
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22 -j RETURN
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --to-ports 4444
Note: Replace eth0 with your network interface. Add a RETURN rule for each port running a real service.
To make this persistent, you can save your iptables rules or use the iptables-config provided in the system_files directory.
You can add Portspoof to your startup scripts using the examples in system_files/init.d/.
This mode generates and feeds port scanners with bogus service signatures.
portspoof -c /etc/portspoof.conf -s /etc/portspoof_signatures -D
With custom tarpit timings (hold each connection between 10 and 60 seconds):
portspoof -s /etc/portspoof_signatures -t 10 -T 60 -D
This mode simply returns an OPEN state for every connection attempt without sending service banners. Connections are still tarpitted.
portspoof -D
Portspoof can be used to fuzz scanning tools by sending random or wordlist-based payloads.
Fuzz with internal generator:
# Generates random payloads of random size
portspoof -1 -v
Fuzz with a wordlist:
portspoof -f payloads.txt -v
The basic REDIRECT rule above works, but an aggressive scanner can still try to overwhelm Portspoof with connections. The following ruleset adds rate limiting and automatic banning for hosts that exceed the connection threshold. Ports hosting real services (SSH in this example) are excluded from the redirect but still protected by the global ban rule.
…
For high-traffic deployments, increase the xt_recent list size:
echo "options xt_recent ip_list_tot=10000" > /etc/modprobe.d/xt_recent.conf
And tune kernel connection tracking:
sysctl -w net.netfilter.nf_conntrack_max=131072
sysctl -w net.core.somaxconn=4096
For stability under heavy scanning, also raise Portspoof's process file-descriptor limit in the launcher (it runs unprivileged and cannot raise it itself): LimitNOFILE=1048576 in a systemd unit, or --ulimit nofile=1048576:1048576 for Docker.
Portspoof Pro scales the same deception from a single host to entire networks. One out-of-band sensor covers your unused address space with no agents and no production impact, and policy-based routing puts it wherever you need it. Every port answers with its own TCP/UDP signature, and every interaction is captured in full, classified, and profiled at a low false-positive rate, then streamed to your SIEM/SOAR. It catches lateral movement and automated scanning, runs fully sandboxed and isolated, and maps to the frameworks you report against: NIS2, DORA, ISO 27001, NIST CSF, and CIS.
Author: Piotr Duszyński (@drk1wi)
License: GNU General Public License v3.0 (GPLv3). See the LICENSE file for details.
For commercial, legitimate applications, please contact the author for the appropriate licensing arrangements.
If you encounter any bugs or have feature requests, please report them on the GitHub Issue Tracker or contact the author via email at piotr [at] duszynski.eu.
No open issues yet, or sync has not completed.