This will be a multi part series on building a cloud-hosted honeypot, integrating it with Splunk, and automating actions based on the intel gathered through Ansible, all orchestrated by Splunk. This blog post will mainly go over the groundwork of getting the honeypot set up, and connected to Splunk and Ansible, as well as some scheduled searches set up to gather activity information from the honeypot, and lastly a small dashboard to help visualize activity.

Cowrie Honeypot Setup

My honeypot is hosted on Microsoft Azure’s free tier of compute VMs. I went with Azure because I don’t currently have the ability to create VLANs or a DMZ in my home network, so cloud hosting was the safest option for me. At some point I’m going to get a Layer 3 switch and get VLANs set up, at which point I’d likely look to pull the VM inside of my network.

There are many of guides out there on getting the Cowrie Honeypot set up, so I won’t be including much information here about the set up and configuration of the VM. The guide that I followed the most was this one. Splunk also has a very good blog post up on configuring Cowrie, which includes a link to their github for some scripts you can run to auto-configure the machine and set up logging to Splunk through the HTTP Event Collector.

Instead of using Splunk HEC to collect logs, I set up ssh keys on the VM, and then used my Splunk Universal Forwarder Ansible Playbook to push and install the UF on the box. After installing and configuring cowrie, I started picking up the cowrie activity log and sending it into Splunk.

Splunk Configuration

In order to work with the logs from the honeypot, the first item of business was to develop a few field extractions and calculated fields:

EXTRACT-HoneyPotSSHTransport__src_ip = HoneyPotSSHTransport,\d+,(?<src_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})
EXTRACT-login_attempt__cowrie_action = login attempt \[(?<user>.+?)\/(?<password>.+?)\] (?<cowrie_action>\w+)
EVAL-action = case(cowrie_action=="succeeded", "success", cowrie_action=="failed", "failure", isnotnull(cowrie_action), "error")
EXTRACT-command = Command found: (?<command>.+)

With those created, I set up a lookup list in order to track the IP addresses attacking the honeypot. The lookup contains only four columns that give me enough information to track attacker activity, even when the logs age out:

  1. src_ip – IP address of attacker
  2. count – Total number of records from attacker
  3. first_seen – Epoch timestamp of first time the IP was seen
  4. last_seen – Epoch timestamp of the lat time the IP was seen

I’ve set up a scheduled search that runs every 15 minutes to look for new attack activity, values for existing IP addresses are updated with each run, and new attackers are tacked onto the end:

host=azure003 sourcetype=cowrie 
| stats earliest(_time) AS first_seen, latest(_time) AS last_seen, count by src_ip
| inputlookup append=t cowrie_ip_intel.csv
| stats min(first_seen) AS first_seen, max(last_seen) AS last_seen, sum(count) AS count by src_ip
| outputlookup cowrie_ip_intel.csv

Lastly, I set up a dashboard in order to get a holistic image of the activity from the honeypot. The different elements on the dashboard are:

  1. IP addresses – Includes count of events over the time frame
  2. Credentials attempted – Includes counts and whether the credentials were successful
  3. Home firewall traffic matching intel list – This was one of my primary reasons for running the honeypot. I wanted to see what traffic was hitting my home firewall that was also hitting the honeypot. Eventually I’ll be automating responses based on these matches, but that’ll be for a future blog post
  4. Activity over Time – Graphics are pretty
  5. Geographical mapping of activity – Graphics are pretty


The dashboard came out how I wanted it to, and I’ve got everything in place now to work on the automated responses I have planned. Stay tuned for additional (and more exciting than set up) blog posts on the Cowrie honeypot and how I’m utilizing it.

Leave a Reply

Your email address will not be published. Required fields are marked *