tcp-honeypot.py is a Python program that allows you to define listeners using dictionaries: they listen on a given TCP port and process connections according to their configuration.
It started as a simple TCP honeypot, but now I use it too if I need a small network server.
For my quickpost “Quickpost: Browsers & Content-Disposition“, I needed a simple web server that would serve a page that I could fully control (headers & body).
I did this with tcp-honeypot. Dictionary dListeners (used by tcp-honeypot) defines the listeners: the keys are the TCP port numbers to listen on, and the values are dictionaries with configuration entries.
As I wanted to serve 3 different pages, I resorted to listen on 3 different ports (8080, 8081, 8082), each would serve a different page. Each dictionary for these listeners contains one entry with key THP_REPLY. Because each listener is very simple it listens for a connection and reads incoming data, discards it, and then sends its reply (regardless of input).
Here is the code to do this (file content-disposition-test.py):
#!/usr/bin/env python __description__ = 'TCP honeypot configuration for Content-Disposition tests' __author__ = 'Didier Stevens' __version__ = '0.0.1' __date__ = '2019/04/03' """ Source code put in public domain by Didier Stevens, no Copyright https://DidierStevens.com Use at your own risk History: 2019/04/03: start Todo: """ dListeners = { 8080: {THP_REPLY: TW_CRLF(['HTTP/1.1 200 OK', 'Content-Disposition: inline', '', 'Line 1', 'Line 2', 'Line 3'])}, 8081: {THP_REPLY: TW_CRLF(['HTTP/1.1 200 OK', 'Content-Disposition: attachment', '', 'Line 1', 'Line 2', 'Line 3'])}, 8082: {THP_REPLY: TW_CRLF(['HTTP/1.1 200 OK', 'Content-Disposition: attachment; filename="test.js"', '', 'Line 1', 'Line 2', 'Line 3'])}, }
THP_REPLY configures a listener to read incoming data when a TCP connection is established, then send a reply (the value of dictionary entry THP_ENTRY) and then close the connection. This value is a string: the HTTP message (start-line, headers and body) to be send to the browser. In stead of defining one long string with start-line, headers and body, separated with carriage return & newline (CR NL), I use convenience function TW_CRNL. When you call convenience function TW_CRNL (Terminate With CR NL) with a list of strings, it terminates each string with CR NL (\r\n) and concatenates all strings into one string, that is returned by the function.
To start the server with this configuration, I just have to run tcp-honeypot.py with content-disposition-test.py as argument.
There are other methods to do this, for example using a single port. I’ll describe these methods in an upcoming blog post.