Monitor a Honeypot with Azure App Insights

Photo by Boba Jaglicic on Unsplash

Have you ever wanted to watch foreign malicious actors attack a virtual machine in real time? In this article, we will do just that with a python honeypot and Azure Monitor.

First, I need to give a shout-out to the Microsoft docs for setting up Application Insights. This explains in greater detail some things that I gloss over.

Also check out my GitHub repo with python honeypot.

Outline

This article has 3parts:

  1. Create a honeypot — set up a virtual machine that will run a python script to expose a port to public connections. The script will reject attempts to connect by foreign actors and close the connection.
  2. Send the hackers’ IP address information to Application Insights on Azure.
  3. Analyze log data using Kustos Query Language in the Application Insights Logs dashboard.

Part 1. Create a honeypot

Rather than setting up the honeypot on your personal machine, I recommend setting up an Linux Azure virtual machine and creating a Resource Group. The Resource Group can house both the virtual machine and the Application Insights resource.

When you set up your virtual machine, you can remote into it via either RDP or ssh. I recommend adding the VM ssh public key to your known hosts file and accessing the VM through VS Code. Also don’t forget to run apt-get update from a termin on the VM, and install python 3.

Virtual Machine networking

For your python application to listen on a port, you will need to open that port up on the virtual machine. If you are working on an Azure virtual machine, you can open the port up from Networking tab. Add Inbound port rule with a Destination Port Range of the port your app will listen on. I used port 1025.

Also, the python socket function requires an IP address to listen on. You must use the internal IP address given by the virtual machine, not the public IP address given by Azure. You can get your internal IP address by running ifconfig from the command line of the virtual machine. Your internal IP is under eth=0, inet.

Set up Application Insights

Before we set up the honeypot, we need to create a create an Application Insights Resource. Once this has been created, take note of the Instrumentation key. This key is used in the connection string of the Azure Monitor OpenCensus SDK. I saved the key to an an environment variable and loaded it using the os python library. The connection string is formatted like InstrumentationKey='<your-key-here>'.

We will modify a simple honeypot python script written by omnidan on GitHub to send a json document containing ip address information to Application Insights. The connection information includes data like time, ip address and country of origin.

The honeypot creates a socket object that listens on a specified port and logs attempts to connect to that exposed port. There are many examples of sockets in python, so I will go over the three main functions used to send the data to Application Insights.

Install packages

You will need to install two packages on the VM that your python app will use.

  1. The OpenCensus SDK for Azure Monitor. This is used to send data to Application Insights.
  2. ipinfo — you will need to sign up for a free account and copy your access token. This service returns information about the IP address of the hacker. We get the info from ipinfo and then send that data to Application Insights.
Photo by Brett Zeck on Unsplash

Part 2. Send the data to Application Insights

Initialize the the logger object that will send the data to Azure Application Insights.

Use the ipinfo pip package and service to pull information about the attacker based on their IP address

You will need to sign up on the ipinfo website and they will immediately email you an access key. The details object returned is a dictionary of information like city, country, hostname, region, organization. This function gets called and thedetails object is passed to our final function.

Write the data to Application Insights

This function parses out the details object and creates the dictionary that will be passed to our App Insights logger function. Recall we created the logger object using our instrumentation key in the first function.

Finally, we insert our three functions into the original script.

Recap: the functions create a logger object, request IP information, and write the data to Application Insights.

You can see the full python file at my GitHub repo. Run the script from the terminal: python3 <python-file-here>.py to start the honeypot. Be aware there can be issues running the python script to listen to Port 23 as that is a port that requires admin access. You can avoid this by using port 1025 or higher and running your python script without admin access, which is always preferable.

Test your app

From another linux machine, run telnet <vm-ip-address> <port> to scan your vm for open ports. You will see output printed to the VM console with the IP address, as well as a new entry in Application Insights.

Photo by Francesca Tirico on Unsplash

Part 3: Application Insights

On the Azure Portal, navigate to your Application Insights resource and click on Logs. This will pull up a query editor that uses Kustos Query Language. Don’t worry, Kustos is very similar to SQL, with some built in functions that come in handy. Here is a helpful SQL to Kustos cheat sheet.

The most basic element of a query for the logs we sent from our honeypot is traces. Type in traces and click the play button to run your query. You will see the records sent from our python app as they exist in the App Insights Database. The IP address information is located in the nested json document inside customDimensions, which contains the data we passed to 'logger.warning('action',extra=logData).

query traces

Let’s write a query to:

  1. Extract data from customDimensions
  2. Create new columns
  3. Subset certain records
  4. Select columns

You can create a new column by using extend. In the below example, I create a new column Time from customDimensions['Time'].

traces
| extend Time = tostring(customDimensions['Time'])

We can create calculated columns using extend that return a value based on a condition. Use the case function to evaluate the IP address of the record and return a zero if it is your IP address, and 1 if not.

traces
| extend Time = tostring(customDimensions['Time'])
| extend IP = tostring(customDimensions['IP'])
| extend IPme = case(IP == '<your-ip-address>', 0, 1)

Now, use the familiar where function to subset certain records. We will subset only records where IPme is equal to one.

traces
| extend Time = tostring(customDimensions['Time'])
| extend IP = tostring(customDimensions['IP'])
| extend IPme = case(IP == '<your-ip-address>', 0, 1)
| where IPme == 1

The above expression is identical to:

traces
| extend Time = tostring(customDimensions['Time'])
| extend IP = tostring(customDimensions['IP'])
| where IP != '<your-ip-address>'

Finally, select columns using the project function.

traces
| extend Time = tostring(customDimensions['Time'])
| extend IP = tostring(customDimensions['IP'])
| where IP != '<your-ip-address>'
| project Time, IP

The final query with formatted columns showing records that did NOT come from my IP address is:

traces
| extend Time = tostring(customDimensions['Time'])
| extend IP = tostring(customDimensions['IP'])
| extend City = tostring(customDimensions['City'])
| extend Country = tostring(customDimensions['Country'])
| extend CountryName = tostring(customDimensions['CountryName'])
| extend Location = tostring(customDimensions['Location'])
| extend Region = tostring(customDimensions['Region'])
| extend Timezone = tostring(customDimensions['Timezone'])
| where IP != '<your-ip-address>'
| where isnotempty(Country)
| project Time, IP, City, Country, CountryName, Location, Region, Timezone

Count and Group By

You can perform a count of records per country with the summarize function.

traces
| extend CountryName = tostring(customDimensions['Country'])
| summarize Count = count() by CountryName
| project CountryName, Count

That’s it! Now that you can send data from your application to Application Insights, you can write Kustos queries to analyze your IP address data. You can also send your python errors to App Insights using the same method of passing to customDimensions.

Stay tuned for more articles about analyzing the IP address data and building dashboards using Application Insights.

Northwestern University Master’s in Public Policy Student

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store