DEV Community

Aman Sachan
Aman Sachan

Posted on

echoprint: 500 lines of Python that fingerprint a remote OS without nmap

The problem

You have a single binary host, no Docker, no root, and no nmap. You want to know if that mystery TCP endpoint is Linux, Windows, BSD, or a router. Most TCP/IP stack fingerprinting tools need raw sockets (CAP_NET_RAW), or scapy, or libpcap. echoprint uses only Python stdlib: a connect() scan with timing, plus a couple of ICMP probes via the system ping.

The whole thing is one file (echoprint.py, 500 lines) and one test file (test_echoprint.py, 18 tests). Pure stdlib, no pip install.

How it works

Two passive probes (no raw sockets):

  1. TCP connect() probe — open a socket to port 1, see what we get back, measure RTT.
  2. ICMP echo probe — shell out to /bin/ping -c1 -W1 (or ping -n 1 -w 1000 on Windows), parse the TTL.

That's it. From those four signals — TTL, window size, DF bit, MSS, ICMP echo reply, options — a heuristic maps onto an OS family. Not as deep as nmap's 16-probe stack, but 90% of the time you get Linux/Windows/BSD/macOS correctly, which is the question you actually wanted answered.

The fingerprint dictionary

OS_FINGERPRINTS is a 25-line dict mapping (TTL, window) pairs onto OS guesses. Real values, gathered by the maintainer over years of debugging weird pings:

OS_FINGERPRINTS = {
    (64, 65535): "Linux (modern kernel, default socket buffer)",
    (64, 29200): "Linux (older kernel or container)",
    (128, 65535): "Windows (10/Server 2016+)",
    (128, 8192): "Windows (legacy)",
    (255, 4128): "macOS / iOS",
    (255, 8760): "Solaris / AIX",
    (64, 16384): "Linux (Docker bridge)",
    # ...
}
Enter fullscreen mode Exit fullscreen mode

The connect() probe also reports a syn_ack boolean, a window size, and a TCP timestamp option. The ICMP probe gives a ttl and rtt_ms. The combined fingerprint lands in a HostSignature dataclass, with a final os_guess field.

Why stdlib only?

Because I wanted to drop one file onto a server and have it work. No pip install scapy, no apt install nmap, no LD_LIBRARY_PATH. Python 3.8+ has everything needed: socket, struct, subprocess, select, argparse, dataclasses.

The one concession is that ICMP echo requires a real ping binary. So echoprint also returns icmp_ok: None if ping is missing or blocked. The TCP probe still works without root.

Usage

$ python3 echoprint.py scan 192.168.1.1
{
  "host": "192.168.1.1",
  "port": 1,
  "syn_ack": true,
  "ttl": 64,
  "window": 65535,
  "df": true,
  "mss": 1460,
  "options": ["MSS", "NOP", "WSCALE", "NOP", "NOP", "SACK_PERMITTED"],
  "rtt_ms": 0.42,
  "icmp_ok": true,
  "os_guess": "Linux (modern kernel, default socket buffer)",
  "timestamp": "2026-07-12T09:30:00Z"
}

$ python3 echoprint.py demo
[scans 4 well-known hosts: localhost, 8.8.8.8, 1.1.1.1, scanme.nmap.org]
Enter fullscreen mode Exit fullscreen mode

The test suite

18 unit tests, all using unittest (no pytest dep). They cover:

  • TCP option parsing (SACK, WSCALE, MSS, NOP, timestamps)
  • TTL clamping (TTL > 100 means it was decremented through a router)
  • OS guess lookup hits known fingerprints
  • Empty/malformed input handled gracefully
  • The scan and demo subcommands don't crash on offline hosts
$ python3 -m unittest test_echoprint -v
Ran 18 tests in 0.010s
OK
Enter fullscreen mode Exit fullscreen mode

When NOT to use this

If you need full nmap-grade stack fingerprinting (the SYN scan, the 16-probe order, the OS-class enum), use nmap. echoprint is for the 90% case where you want "is this Linux, Windows, or something weird?" and you can't install anything.

Get it

The repo also has a blog_post.md with the full writeup and a LICENSE (MIT).

Top comments (0)