fingerprinting

Fingerprint shell for telnet client identification.

This module runs server-side: it is the shell callback for a telnetlib3 server that probes connecting clients for protocol capabilities, collects session data, and saves fingerprint files. Despite the generic name, it fingerprints the remote client, not the server.

Display, REPL, and post-script code live in telnetlib3.fingerprinting_display.

ENVIRON_EXTENDED: list[str] = ['HOME', 'SHELL', 'IPADDRESS', 'SSH_CLIENT', 'SSH_TTY', 'SSH_AUTH_SOCK', 'SSH_REMOTE_HOST', 'HOSTNAME', 'HOSTTYPE', 'OSTYPE', 'PWD', 'PS1', 'VISUAL', 'TMUX', 'STY', 'SHELLOPTS', 'TERM_PROGRAM_VERSION', 'XDG_SESSION_PATH', 'XDG_CURRENT_DESKTOP', 'XCURSOR_THEME', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES', 'LC_COLLATE', 'LC_TIME', 'LC_ADDRESS', 'LC_IDENTIFICATION', 'LC_MEASUREMENT', 'LC_MONETARY', 'LC_NAME', 'LC_NUMERIC', 'LC_PAPER', 'LC_TELEPHONE', 'DOCKER_HOST', 'HISTFILE', 'HISTFILESIZE', 'HISTSIZE', 'EPOCHREALTIME', 'LSCOLORS', 'LS_COLORS', 'DIRCOLORS', 'GCC_COLORS', 'AWS_PROFILE', 'AWS_REGION', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_SESSION_TOKEN', 'AWS_DEFAULT_REGION', 'SSH_REMOTE_IP', 'GITHUB_TOKEN', 'GH_TOKEN', 'GITLAB_TOKEN', 'GL_TOKEN', 'ANTHROPIC_API_KEY', 'OPENAI_API_KEY', 'STRIPE_SECRET_KEY', 'SENDGRID_API_KEY', 'HEROKU_API_KEY', 'NPM_TOKEN', 'SLACK_TOKEN', 'TWILIO_AUTH_TOKEN', 'DATABASE_URL', 'PGPASSWORD', 'MYSQL_PWD', 'REDIS_URL', 'AZURE_CLIENT_SECRET', 'GOOGLE_APPLICATION_CREDENTIALS', 'SECRET_KEY', 'API_KEY', 'PRIVATE_KEY', 'JWT_SECRET', 'DOCKER_PASSWORD']

Extended NEW_ENVIRON variable list used during client fingerprinting. The base TelnetServer requests only common variables (USER, LOGNAME, LANG, TERM, etc.). This extended set collects additional information useful for identifying and classifying clients – and for demonstrating the oversharing risk of RFC 1572 NEW_ENVIRON.

class FingerprintingServer(term='unknown', cols=80, rows=25, timeout=300, shell=None, _waiter_connected=None, encoding='utf8', encoding_errors='strict', force_binary=False, never_send_ga=False, line_mode=False, connect_maxwait=4.0, compression=None, limit=None, reader_factory=<class 'telnetlib3.stream_reader.TelnetReader'>, reader_factory_encoding=<class 'telnetlib3.stream_reader.TelnetReaderUnicode'>, writer_factory=<class 'telnetlib3.stream_writer.TelnetWriter'>, writer_factory_encoding=<class 'telnetlib3.stream_writer.TelnetWriterUnicode'>)[source]

TelnetServer with extended NEW_ENVIRON.

Combines FingerprintingTelnetServer with TelnetServer so that fingerprinting_server_shell() receives the full set of environment variables needed for stable fingerprint hashes.

Used as the default protocol_factory by fingerprint_server_main() / telnetlib3-fingerprint-server CLI.

Initialize TelnetServer with terminal parameters.

connection_lost(exc)[source]

Log connection close/loss.

Return type:

None

class FingerprintingTelnetServer[source]

Mixin that extends on_request_environ with ENVIRON_EXTENDED.

Usage with create_server():

from telnetlib3.server import TelnetServer
from telnetlib3.fingerprinting import FingerprintingTelnetServer

class MyServer(FingerprintingTelnetServer, TelnetServer):
    pass

server = await create_server(protocol_factory=MyServer, ...)
on_request_environ()[source]

Return base environ keys plus ENVIRON_EXTENDED.

Return type:

list[Union[str, bytes]]

class ProbeResult[source]

Result of probing a single telnet option.

fingerprint_server_main()[source]

Entry point for telnetlib3-fingerprint-server CLI.

Reuses parse_server_args() and run_server() with FingerprintingServer as the default protocol factory and fingerprinting_server_shell() as the default shell.

Accepts --data-dir to set the fingerprint data directory. Falls back to the TELNETLIB3_DATA_DIR environment variable, then to data/ in the current directory.

Return type:

None

async fingerprinting_server_shell(reader, writer)[source]

Shell that probes client telnet capabilities and runs post-script.

Immediately probes all telnet options on connect. If DATA_DIR is configured, saves fingerprint data and runs the post-script through a PTY so it can probe the client’s terminal with ucs- detect.

Parameters:
Return type:

None

fingerprinting_post_script(filepath)[source]

Post-fingerprint script that optionally runs ucs-detect for terminal probing.

If ucs-detect is available in PATH, runs it to collect terminal capabilities and merges the results into the fingerprint data.

Can be used as the TELNETLIB3_FINGERPRINT_POST_SCRIPT target:

TELNETLIB3_FINGERPRINT_POST_SCRIPT=telnetlib3.fingerprinting
TELNETLIB3_DATA_DIR=./data
telnetlib3-server --shell fingerprinting_server_shell
Parameters:

filepath (str) – Path to the saved fingerprint JSON file.

Return type:

None

get_client_fingerprint(writer)[source]

Collect all available client information from writer.

Parameters:

writer (Union[TelnetWriter, TelnetWriterUnicode]) – TelnetWriter instance.

Return type:

dict[str, Any]

Returns:

Dictionary of all negotiated client attributes.

async probe_client_capabilities(writer, options=None, timeout=0.5)[source]

Actively probe client for telnet capability support.

Sends IAC DO for ALL options at once, waits for responses, then collects results.

Parameters:
Return type:

dict[str, ProbeResult]

Returns:

Dict mapping option name to ProbeResult.

async probe_client_loop_detection(writer, probe_results, timeout=0.3)[source]

Detect clients that would re-negotiate already-agreed options (telnet loop).

Saves the negotiation state for options the client already agreed to, clears the cache, re-sends IAC DO / IAC WILL for those options, and checks whether the client replies again. A well-behaved client ignores redundant requests in the YES state; a loop-prone client replies again.

Checks both directions: re-DO’ing options the client already WILL’d, and re-WILL’ing options the client already DO’d.

Return type:

list[str]

Returns:

Sorted list of option names that would loop.