Cowrie Honeypot on Ubuntu

What is Cowrie

Cowrie is the new fork of the Kippo Honeypot. It has been updated with new features and provides emulation that records the session of an attacker. With this session recording, you get a better understanding of the attackers tools, tactics, and procedures - TTPs. TTPs being a term that is increasingly being used in Cyber Defence and Incident Response.


Our setup will be very close to a default installation of Cowrie. The hosts SSH daemon will run on a high port (22222), Cowrie will run on 2222, and port 22 (default SSH) will be redirected to 2222 using iptables.

So, the SSH bot, or attacker, will connect to port 22, and will be redirected to our honeypot on 2222. Confused? Take a look at the diagram.

A warning before we proceed. Honeypots are designed to allow access to a system by an attacker. This could result in compromise of the host if the honeypot has vulnerabilities or is mis-configured. Understand what you are doing and be very careful if running a honeypot anywhere near production kit.

Change Default SSH Port

Before installing cowrie and our dependencies, lets move SSH to port 22222.

 root@cowrie:~# vi /etc/ssh/sshd_config
# What ports, IPs and protocols we listen for
Port 22222

root@cowrie1:~# systemctl restart ssh
root@cowrie1:~# systemctl status ssh
? ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2018-03-19 23:21:05 UTC; 5s ago
 Main PID: 9242 (sshd)
    Tasks: 1
   Memory: 1.3M
      CPU: 5ms
   CGroup: /system.slice/ssh.service
           ??9242 /usr/sbin/sshd -D

Mar 19 23:21:05 cowrie1 systemd[1]: Stopped OpenBSD Secure Shell server.
Mar 19 23:21:05 cowrie1 systemd[1]: Starting OpenBSD Secure Shell server...
Mar 19 23:21:05 cowrie1 sshd[9242]: Server listening on port 22222.
Mar 19 23:21:05 cowrie1 sshd[9242]: Server listening on :: port 22222.
Mar 19 23:21:05 cowrie1 systemd[1]: Started OpenBSD Secure Shell server.

root@cowrie1:~# netstat -nap | grep 2222
tcp        0      0  *               LISTEN      9242/sshd
tcp6       0      0 :::22222                 :::*                    LISTEN      9242/sshd

We can see SSH is now listening on port 22222 from both the systemctl status as well as the netstat output.

Installation of Cowrie Honeypot on Ubuntu

First, we run apt udpate as we are on a brand new Digital Ocean VPS. Then we install dependencies and create a Cowrie user. Running a Honeypot as root would be a bad idea.

 root@cowrie:~# apt update
root@cowrie:~# apt-get install git python-virtualenv libssl-dev libffi-dev build-essential libpython-dev python2.7-minimal authbind
root@cowrie:~# adduser --disabled-password cowrie
Adding user `cowrie' ...
Adding new group `cowrie' (1000) ...
Adding new user `cowrie' (1000) with group `cowrie' ...
Creating home directory `/home/cowrie' ...
Copying files from `/etc/skel' ...
Changing the user information for cowrie
Enter the new value, or press ENTER for the default
        Full Name []:
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] Y
root@cowrie1:~# su - cowrie

Ok, grab the code for Cowrie using git.

cowrie@cowrie1:~$ git clone
Cloning into 'cowrie'...
remote: Counting objects: 9340, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 9340 (delta 3), reused 2 (delta 0), pack-reused 9330
Receiving objects: 100% (9340/9340), 7.43 MiB | 2.32 MiB/s, done.
Resolving deltas: 100% (6415/6415), done.
Checking connectivity... done.

Now we create a virtual environment for Python and Cowrie to run from:

cowrie@cowrie1:~$ cd cowrie
cowrie@cowrie:~/cowrie$ virtualenv cowrie-env
Running virtualenv with interpreter /usr/bin/python2
New python executable in /home/cowrie/cowrie/cowrie-env/bin/python2
Also creating executable in /home/cowrie/cowrie/cowrie-env/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.

Next step: Activate the Python virtual environment, and install python packages Cowrie needs to run.

cowrie@cowrie1:~/cowrie$ source cowrie-env/bin/activate                                                                   
(cowrie-env)  cowrie@cowrie1:~/cowrie$ pip install --upgrade pip 
Requirement already up-to-date: pip in ./cowrie-env/lib/python2.7/site-packages                                                     
(cowrie-env) cowrie@cowrie1:~/cowrie$ pip install --upgrade -r requirements.txt                                                    
Collecting twisted>=17.1.0 (from -r requirements.txt (line 1))                                                                      
  Downloading Twisted-17.9.0.tar.bz2 (3.0MB)                                                                                        
    100% |????????????????????????????????| 3.0MB 403kB/s                                                                           
Collecting cryptography>=0.9.1 (from -r requirements.txt (line 2))                                                                  
  Downloading cryptography-2.2-cp27-cp27mu-manylinux1_x86_64.whl (2.2MB)                                                            
    100% |????????????????????????????????| 2.2MB 544kB/s                                                                           
Collecting configparser (from -r requirements.txt (line 3))                                                                         
  Downloading configparser-3.5.0.tar.gz                                                                                             
Collecting pyopenssl (from -r requirements.txt (line 4))                                                                            
  Downloading pyOpenSSL-17.5.0-py2.py3-none-any.whl (53kB)                                                                          
    100% |????????????????????????????????| 61kB 9.8MB/s                                                                            
Collecting pyparsing (from -r requirements.txt (line 5))                                                                            
  Downloading pyparsing-2.2.0-py2.py3-none-any.whl (56kB)                                                                           
    100% |????????????????????????????????| 61kB 9.7MB/s                                                                            
Collecting packaging (from -r requirements.txt (line 6))                                                                            
  Downloading packaging-17.1-py2.py3-none-any.whl                                                                                   
Collecting appdirs>=1.4.0 (from -r requirements.txt (line 7))                                                                       
  Downloading appdirs-1.4.3-py2.py3-none-any.whl                                                                                    
Collecting pyasn1_modules (from -r requirements.txt (line 8))                                                                       
  Downloading pyasn1_modules-0.2.1-py2.py3-none-any.whl (60kB)                                                                      
    100% |????????????????????????????????| 61kB 9.7MB/s                                                                            
Collecting attrs (from -r requirements.txt (line 9))
  Downloading attrs-17.4.0-py2.py3-none-any.whl
Collecting service_identity (from -r requirements.txt (line 10))
  Downloading service_identity-17.0.0-py2.py3-none-any.whl
Collecting python-dateutil (from -r requirements.txt (line 11))
  Downloading python_dateutil-2.7.0-py2.py3-none-any.whl (207kB)
    100% |????????????????????????????????| 215kB 5.4MB/s
Collecting tftpy (from -r requirements.txt (line 12))
  Downloading tftpy-0.6.2.tar.gz
Collecting zope.interface>=3.6.0 (from twisted>=17.1.0->-r requirements.txt (line 1))
  Downloading zope.interface-4.4.3-cp27-cp27mu-manylinux1_x86_64.whl (170kB)
    100% |????????????????????????????????| 174kB 4.1MB/s
Collecting constantly>=15.1 (from twisted>=17.1.0->-r requirements.txt (line 1))
  Downloading constantly-15.1.0-py2.py3-none-any.whl
Collecting incremental>=16.10.1 (from twisted>=17.1.0->-r requirements.txt (line 1))
  Downloading incremental-17.5.0-py2.py3-none-any.whl
Collecting Automat>=0.3.0 (from twisted>=17.1.0->-r requirements.txt (line 1))
  Downloading Automat-0.6.0-py2.py3-none-any.whl
Collecting hyperlink>=17.1.1 (from twisted>=17.1.0->-r requirements.txt (line 1))
  Downloading hyperlink-18.0.0-py2.py3-none-any.whl
Collecting cffi>=1.7; platform_python_implementation != "PyPy" (from cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading cffi-1.11.5-cp27-cp27mu-manylinux1_x86_64.whl (407kB)
    100% |????????????????????????????????| 409kB 3.0MB/s
Collecting enum34; python_version < "3" (from cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading enum34-1.1.6-py2-none-any.whl
Collecting asn1crypto>=0.21.0 (from cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading asn1crypto-0.24.0-py2.py3-none-any.whl (101kB)
    100% |????????????????????????????????| 102kB 9.7MB/s
Collecting idna>=2.1 (from cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading idna-2.6-py2.py3-none-any.whl (56kB)
    100% |????????????????????????????????| 61kB 9.5MB/s
Collecting six>=1.4.1 (from cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading six-1.11.0-py2.py3-none-any.whl
Collecting ipaddress; python_version < "3" (from cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading ipaddress-1.0.19.tar.gz
Collecting pyasn1<0.5.0,>=0.4.1 (from pyasn1_modules->-r requirements.txt (line 8))
  Downloading pyasn1-0.4.2-py2.py3-none-any.whl (71kB)
    100% |????????????????????????????????| 71kB 9.4MB/s
Requirement already up-to-date: setuptools in ./cowrie-env/lib/python2.7/site-packages (from zope.interface>=3.6.0->twisted>=17.1.0->-r requirements.txt (line 1))
Collecting pycparser (from cffi>=1.7; platform_python_implementation != "PyPy"->cryptography>=0.9.1->-r requirements.txt (line 2))
  Downloading pycparser-2.18.tar.gz (245kB)
    100% |????????????????????????????????| 256kB 4.5MB/s
Building wheels for collected packages: twisted, configparser, tftpy, ipaddress, pycparser
  Running bdist_wheel for twisted ... done
  Stored in directory: /home/cowrie/.cache/pip/wheels/91/c7/95/0bb4d45bc4ed91375013e9b5f211ac3ebf4138d8858f84abbc
  Running bdist_wheel for configparser ... done
  Stored in directory: /home/cowrie/.cache/pip/wheels/1c/bd/b4/277af3f6c40645661b4cd1c21df26aca0f2e1e9714a1d4cda8
  Running bdist_wheel for tftpy ... done
  Stored in directory: /home/cowrie/.cache/pip/wheels/b6/6b/9a/4536837177d943f2aede676c74488f1dd6f2c3c7ef80f8c094
  Running bdist_wheel for ipaddress ... done
  Stored in directory: /home/cowrie/.cache/pip/wheels/d7/6b/69/666188e8101897abb2e115d408d139a372bdf6bfa7abb5aef5
  Running bdist_wheel for pycparser ... done
  Stored in directory: /home/cowrie/.cache/pip/wheels/95/14/9a/5e7b9024459d2a6600aaa64e0ba485325aff7a9ac7489db1b6
Successfully built twisted configparser tftpy ipaddress pycparser
Installing collected packages: zope.interface, constantly, incremental, attrs, six, Automat, idna, hyperlink, twisted, pycparser, cffi, enum34, asn1crypto, ipaddress, cryptography, configparser, pyopenssl, pyparsing, packaging, appdirs, pyasn1, pyasn1-modules, service-identity, python-dateutil, tftpy
Successfully installed Automat-0.6.0 appdirs-1.4.3 asn1crypto-0.24.0 attrs-17.4.0 cffi-1.11.5 configparser-3.5.0 constantly-15.1.0 cryptography-2.2 enum34-1.1.6 hyperlink-18.0.0 idna-2.6 incremental-17.5.0 ipaddress-1.0.19 packaging-17.1 pyasn1-0.4.2 pyasn1-modules-0.2.1 pycparser-2.18 pyopenssl-17.5.0 pyparsing-2.2.0 python-dateutil-2.7.0 service-identity-17.0.0 six-1.11.0 tftpy-0.6.2 twisted-17.9.0 zope.interface-4.4.3

Configure the Cowrie Daemon

That's the initial setup out of the way.

Now to configure the Cowrie daemon, and get started.

cp cowrie.cfg.dist cowrie.cfg

This creates a config file that we can edit and it won't be overwritten by updates.

When editing the configuration file, we make a few changes from the defaults.

First: I change the hostname seen by a successful login by an attacker. Keep it generic and non obvious. Use vim or your favorite text editor to make these changes.

# Hostname for the honeypot. Displayed by the shell prompt of the virtual
# environment
# (default: svr04)
hostname = testserver5

Second: enable telnet. SSH is enabled by default.

# Enable Telnet support, disabled by default
enabled = true

As you can see in the configuration, there are many options and things to play with, from logging and alerting, to fake addresses and file downloads.

Start the Daemon

Finally we are ready to start the daemon.

cowrie@cowrie:~/cowrie$ bin/cowrie start                                             
Using default Python virtual environment "/home/cowrie/cowrie/cowrie-env"             
Starting cowrie: [twistd   --umask 0022 --pidfile var/run/ --logger cowrie.python.logfile.logger cowrie ]...

cowrie@cowrie:~/cowrie$ netstat -an                  
Active Internet connections (servers and established)                                 
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0  *               LISTEN
tcp        0      0  *               LISTEN

From the netstat we can see the SSH and Telnet daemons of our honeypot listening on 2222 and 2223 respectively.

Redirect traffic

Last step is to redirect traffic to 22 and 23 to the high ports 2222 and 2223 using iptables.

root@cowrie:~# iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222                                          
root@cowrie:~# iptables -t nat -A PREROUTING -p tcp --dport 23 -j REDIRECT --to-port 2223   

Now it is just a waiting game. Due to the amount of SSH scanning that takes place on the Internet you will not have to wait long.

cowrie@cowrie:~/cowrie$ tail -f log/cowrie.log


Within 5 minutes I could see SSH connections logging in and running commands within my Honeypot.

Next Level Your Technical Network Intelligence

Domain Profiler

  • One Click Passive Reconnaissance

  • Know your attack Surface

  • Find gaps in the assets