The internet is a dangerous place. There are malicious bots online, going through all IP Addresses (bruteforcing by pruning known IP Ranges) to find any vulnerable servers to attack. In this post we are creating a HoneyPot in Python with asyncio in order to bait them into attacking us to analyse their attacks.

The bots do this by sending specific payloads (requests with specific data) and checking if the expected response was received. In this post we will attempt to create a simple honeypot which listens to all ports from 2 to 65535 (which is the maximum port number). Port 0 and Port 1 will not be used by the HoneyPot.

Server – DigitalOcean

The HoneyPot will run on a DigitalOcean VM because some of their IP Ranges are known by attackers ref: https://ipinfo.io/AS14061. Port 1 will actually be used for SSH by us because we want to check attacks on port 22 (default SSH port). Attack against weak passwords should be common (note this is an assumption).

Quick Python 3.8 Setup

As mentioned by the title you will need to install Python3.8. If you are running Ubuntu 16.04 you can do the following:

sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt install python3.8
sudo apt-get install python3.8-venv
python3.8 -m ensurepip
sudo python3.8 -m easy_install pip
python3.8 -m pip install fire
ulimit -n 100000

Note that we have increased the limit on open files to 100,000. This is because every socket opened on Linux is an open file. You should only need 65535 but 100,000 just to be safe (for example logging is going to use one at least).

You should then also modify /etc/ssh/sshd_config and modify the port to 1. When you ssh on the client side then you can do for example:

ssh root@server_address -p 1

asyncio

Asyncio is used to execute multiple tasks at a time on a single thread. We are going to make use of coroutines (async def) which listen (asyncio.start_server) a specific port and log any requests received (file logger to honeypot.log). We then launch all the tasks at runtime(asyncio.gather). There are 3 parameters that can be passed through the command line (done with Fire): address, port_start and port_end.

For more information please read: https://docs.python.org/3/library/asyncio.html

The full source code for the basic honeypot: https://github.com/Lougarou/honeypot

import utils.formatters as formatters
import utils.handlers as handlers
from datetime import datetime

import asyncio
import logging
import fire

logger = logging.getLogger(__name__)

async def smiley_protocol(reader, writer):
  try:
    data = await reader.read(1024)
    message = ""
    try:
      message = data.decode()
    except UnicodeDecodeError:
      message = data
    addr = writer.get_extra_info('peername')
    print([str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S")),message, str(addr[0])+":"+str(addr[1])])
    logger.info([str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S")),(f"{message!r}"), f"{addr[0]!r}", f"{addr[1]!r}"])
    writer.write(b":D")
    await writer.drain()
    writer.close()
  except ConnectionResetError:
    pass #do nothing, not useful for data collection

async def launch_pot(address='127.0.0.1',port=8888):
  server = await asyncio.start_server(
    smiley_protocol, address, port)
  try:
    async with server:
      await server.serve_forever()
  except:
    logger.error("failed to start "+str(port))

async def main(address="127.0.0.1", port_start=1, port_end=2**16-1, log='honeypot.csv'):

  logger.setLevel(logging.DEBUG)
  loggingStreamHandler = handlers.CSVTimedRotatingFileHandler(filename=log,
															  header=["time", "payload", "from", "port"])  # to save to file
  loggingStreamHandler.setFormatter(formatters.CSVFormatter())
  logger.addHandler(loggingStreamHandler)
  tasks = []
  for i in range(port_start,port_end + 1):
    tasks.append(asyncio.create_task(launch_pot(address, i)))
  await asyncio.gather(*tasks)

if __name__ == '__main__':
  fire.Fire(main)

You can then run the honeypot with the following command:

python3.8 honeypot.py --port_start=2 --address=<insert-ip>

Please feel free to comment if you are having any trouble running it.

Next Step: Honeypot.log Payload Analysis

I have planned to collect sample attacks in the honeypot.log and to do another blog post to analyse each of them. Initially I had planned to run it for a whole week but to my surprise the server is receiving hundreds of attacks per minute already.

For example one common attack that I can notice right away is the following:

Received b'\x03\x00\x00+&\xe0\x00\x00\x00\x00\x00Cookie: mstshash=hello\r\n\x01\x00\x08\x00\x03\x00\x00\x00' from ('13.65.92.2', 59134)

Cookie: mstshash=hello is payload to access compromised Microsoft Remote Desktop servers.

Subscribe to the blog if you don’t want to miss Part 2 where we will analyse the attacks received! Update: part 2 is out! https://everythingtech.dev/2021/03/basic-honeypot-analysing-payload-and-attacks/