A malicious network actor (e.g., malware or an intruder) on a local network will typically strive to find open ports. One of the ways to detect this activity is to create a honey pot. This is an open port disguised as a legitimate service for the purpose of catching and reporting malicious / unwanted activity.
In this article we use the Python socket interface to develop a honey pot. There are many different paths to take when developing a honey pot. One can go as far as fully emulating a particular service (i.e., ftp) and allowing the bad actor to download false or potentially dangerous files (e.g., launch malware on your neighbor's network in retribution for him or her jumping on yours!).
In this article, we're just going to meet the following goals:
- Create a listening port on an IPv4 network known port (telnet) and alert on a basic TCP SYN/ACK handshake.
- Show that nmap detects the port (our honey pot)
- Alert us if our honey pot port is probed / scanned (by nmap)
With just this basic, simple tool, we can become alerted to unwanted activity on our network.
We develop and test our honey pot using two Linux systems. The client system (Ubuntu 16.04) is used to run nmap and tcpdump. The server (embedded Linux 4.11) is used to run our python3 honeypot.py script as root.
The Python socket interface is modeled after the Unix socket API. In working with Python sockets, you will probably find yourself often referring to Linux man pages for various definitions.
And as pointed out in the Python socket documentation, the socket module / interface depends on calls to the underlying operating system, so your usage of the provided example may work differently ( or not at all) on a different system.
Let's start out by verifying that nmap and tcpdump
are working properly on our client system by confirming that an
$ nmap 192.168.3.200 -p 21 Starting Nmap 7.25SVN ( https://nmap.org ) at 2017-05-07 15:52 EDT Nmap scan report for Server (192.168.3.200) Host is up (0.00023s latency). PORT STATE SERVICE 21/tcp open ftp Nmap done: 1 IP address (1 host up) scanned in 0.03 seconds
$ sudo tcpdump -Xvn -i enp2s0 host 192.168.3.200 and port 21 ... <packet dump> ...
It's a good idea at this point to play around with different nmap
options (e.g., -sV: determine service) and also try this with the
Socket basics from the shell
The Python socket documentation is extensive and provides enough examples that will get you started. For our purposes, let's show the setup of a basic listening port using the Python 3 shell / interpreter on port 23 (telnet):
$ python3 Python 3.5.2 (default, Mar 29 2017, 18:58:38) ... >>> from socket import socket, AF_INET, SOCK_STREAM >>> sk=socket(AF_INET,SOCK_STREAM) >>> sk.bind(('192.168.3.200',23)) >>> sk.listen() >>> conn,addr = sk.accept()
This last line should now block, waiting for a client to connect. Go back to shell 1 on the client and run nmap with "-p 23".
$ nmap 192.168.3.200 -p 23 Starting Nmap 7.25SVN ( https://nmap.org ) at 2017-05-07 16:00 EDT Nmap scan report for Server (192.168.3.200) Host is up (0.00020s latency). PORT STATE SERVICE 23/tcp open telnet Nmap done: 1 IP address (1 host up) scanned in 0.02 seconds
Go back to your Python shell on the server, and the command line should have returned. Type the following into the shell:
>>> print('alert ' + addr + ' has connected with us')
Bringing it together
The source code for our honeypot.py script is provided below. Run the script on your server and provide the IP address that matches the interface you're listening on using the '-a' option.
# ./honeypot.py -a 192.168.3.100
Now run nmap to scan the system at port 23:
$ nmap 192.168.3.200 -p 23 Starting Nmap 7.25SVN ( https://nmap.org ) at 2017-05-07 21:06 EDT Nmap scan report for Server (192.168.3.200) Host is up (0.00021s latency). PORT STATE SERVICE 23/tcp open telnet Nmap done: 1 IP address (1 host up) scanned in 0.02 seconds
You should see the honey pot report the scan as shown below:
# ./honeypot.py -a 192.168.3.200 honeypot has been visited by 192.168.3.36
You can also try your honey pot using the telnet client. It should close the port after the user hits the enter key (return).
#!/usr/bin/env python3 """ Copyright 2017 Mind Chasers Inc, file: honeypot.py Demo code. No warranty of any kind. Use at your own risk """ import sys import argparse from socket import socket, AF_INET, SOCK_STREAM VERSION = '0.1' welcome = b"Ubuntu 16.04.2 LTS\nserver login: " def send_email(src_address): """ Todo: send an email if we're scanned / probed on this port """ pass def honeypot(address,port=23): """ create a single Threaded telnet listen port """ try: ski=socket(AF_INET,SOCK_STREAM) ski.bind((address, port)) ski.listen() conn,addr = ski.accept() print('honeypot has been visited by ' + addr) send_email(addr) conn.sendall(welcome) while True: data=conn.recv(1024) if data == b'\r\n': ski.close() sys.exit() except: ski.close() sys.exit() if __name__ == '__main__': parser = argparse.ArgumentParser(description='honeypot prototype', epilog='Version: ' + str(VERSION)) parser.add_argument('-a','--address',help='server ip address to use',action='store', required=True) args = parser.parse_args() honeypot(args.address)
You now have the basics of a useful honey pot, but there is still much that can be added and should be considered:
- Keep in mind that a honey pot is basically a fake network service, and they're easy to write. The other side of this story is to remind yourself to not blindly trust network services since providers and hackers can replace or modify them with a compromised implementation for the purpose of stealing data.
- We picked telnet because it's simple to emulate and test. However, you NEVER want to actually have a telnet server running on one of your hosts. Telnet exchanges data across the network in the clear, which means that any eavesdropper can sniff all data exchanged including user credentials.
- If your goal is to create an elaborate honey pot that very closely mimics the behavior of a service, then it may be better to just start with the existing source (e.g., vsftp) and patch in your alerts.
- Our example is single threaded, which may be preferred. Consider the dangers of a multi-threaded honey pot that sends email alerts on each access and the potential to create denial of service attacks by repeatedly stimulating the honey pot service. At the very least, you'll want some sort of rate limiting in a multi-threaded honey pot.
- Consider turning your honey pot script into a daemon and using a cron job to check its status & restart it if necessary. References are provided below for this.
- You may see something like the following between invocations: "honeypot exception : [Errno 98] Address already in use". This can be expected while waiting for the OS to close the port. Give it a little time and try again. If you're stuck, post a comment below