I've been playing around with networking in recent months, including setting up my own OPNsense box and deploying Proxmox on a few machines. I've been loving it, and from a security enthusiast's point of view, some of the data that I could see in OPNsense was very interesting. Through tools like CrowdSec, I could see automated port scanners getting blocked, and it made me take a closer look at home networking and security in general. That's why I set up an SSH honeypot, to try and catch a glimpse of what these people do when they gain access to a system, and the results were pretty scary.

Unless you know what you're doing, I don't suggest setting up your own honeypot, and definitely not on your home network. I deployed a barebones Ubuntu virtual machine running on its own host, without any other data, and set up a tool called Cowrie. Cowrie is an SSH honeypot that will simulate a real SSH connection, complete with responses to commands that look legitimate. It can accept file transfers, too, so that scripts and other malicious files can be intercepted and analyzed by a security researcher. We'll be taking a look at some of that too.

I used this GitHub repository to configure Cowrie with an ElasticSearch database (though I needed to modify the setup script), and altered the Kibana dashboard to display the information that I specifically wanted to see. The data shown here is especially important not just because it captures the real-time attempts from those looking to automate intrusions into self-hosted services that are exposed to the internet, but it also shows what can happen when you don't use a secure password. Nearly all of these attempts were using passwords that find themselves on lists of the most common passwords, but someone specifically targeting you may also try to tailor their attempts specifically to you.

Cowrie is a honeypot that you control every aspect of

It looks like a normal SSH connection

Cowrie is an SSH and Telnet honeypot, designed to log interactions. It's written in Python and emulates a Unix system, though it can also act as a proxy to a real machine if you'd prefer. It's completely customizable, so you can change the login banner, the accepted logins, the filesystem, and so much more. Plus, not only are interactions logged, but file transfers are also saved locally to the machine so that they can be analyzed later.

Cowrie can be run in a containerized environment (such as with Podman or Docker), or it can be run as a regular application using Python. The point of it is that the person connecting to the honeypot doesn't know that it's a honeypot. It responds to commands with plausible responses, including commands that are designed to print system information. As we'll get to, there were a lot of those, and some of the actions undertaken by those who connected to my honeypot were very interesting.

I deployed my Cowrie instance on the 23rd of April, 2025, and all data discussed in this article has been collected since then. There were 29,282 unique interactions, with the most active day being the 1st of May, 2025, logging a total of 7,438 unique interactions. An "interaction" is defined as any individual action, such as an attempted login, an executed command, or the client disconnecting. There were 447 unique IP addresses identified in the dataset after filtering out my own IP address when I was testing it.

Usernames and passwords most commonly used

The usual suspects

First and foremost, we'll have a look at the usernames and passwords that were used the most. Unsurprisingly, "root" was the most-attempted user, representing just over a sixth of all attempts. This makes sense, as the root user is the most privileged user on a Linux-based system. With root access, the attacker controls your entire system and can access every single file present. It's essentially the holy grail, which is why it's recommended to use SSH keys for remote access in general. On top of that, if you don't need the root user enabled, it's better to disable the root user entirely and instead rely on sudo commands to gain those elevated privileges when you need them from your own account.

Looking at the other commonly used usernames, most of them are unsurprising. "admin" and "user" make a lot of sense, as does "support". Interestingly, "ubnt" is the default username on most Ubiquiti products, and that username is one of the more commonly-tried usernames in my dataset. "usario" is Spanish for "user", and "oracle", "ubuntu", and "pi" are all fairly self-explanatory. Most of the other usernames attempted here appear to mainly attack specific services, such as "hadoop", "ec2-user", and "nginx", to name a few. Finally, there were also references to cryptocurrency names, suggesting that some attackers may have been looking to find cryptocurrency wallets relating to mining operations.

Next up are the passwords, and none of these are all too surprising. These are passwords you'll find on common password lists, aside from some specific ones like "raspberryraspberry993311". This password appears to be used by a worm, according to one researcher, that will report to an IRC server, change the password to that password, and then scan for other potential victim devices. Some attackers may use this password in their attempts in order to seize control of a device from another attacker, while the ones who deployed it may use this password as a way to tell if they have already gained access to this system in the past.

There's not a whole lot to say here; these passwords are terrible and represent the first attempts by hackers when trying to gain access to a system. If you're using one of these passwords (or any other commonly used password), you should change it. For SSH access to your server, especially, you should use SSH keys or, at the very least, ensure that you use a strong password. Like in the case of the "raspberryraspberry993311" password attempt, we can get information from other passwords that were attempted, too. One password, "0l0ctyQh243O63uD", was attempted multiple times and appears to be used by the Mirai-based NoaBot, according to Akamai security.

Commands most frequently executed

Some surprises

Unsurprisingly, the most commonly-used command was "uname -s -v -n -r -m". This prints the kernel name, the kernel version (build date and other information), the network node hostname, the kernel release version, and the machine hardware name. This can be used to identify a honeypot, but it's also used to determine the kind of hardware the attacker has connected to in general. Many disconnected immediately after running this command, suggesting that it wasn't what they were looking for.

Interestingly, Telegram was also specifically targeted. Both the "locate D877F783D5D3EF8Cs" and the Telegram commands are related, with "D877F783D5D3EF8Cs" containing the user ID and encryption key for communication between the Telegram client and servers. Other commands were run to gain information about what the system was capable of, while others were used to execute scripts and applications that were downloaded. Of course, these couldn't actually be executed, as the files were intercepted by Cowrie and placed outside of the container for later review.

Most other commands that frequently appeared relate to the attempted execution of those files, including attempting to grant execution rights to them, and "scp -t" commands to receive a file and place it in the /tmp folder.

Looking at one of the files received

Ghidra is my tool of choice

There were a total of 18 items transferred to my honeypot throughout the data collection period, with files ranging from a measly 1 KB to nearly 30 MB. I took a look at one of them just to see how it began execution, as reverse engineering software can take a long time. It's typically best to analyze malware in a virtual machine, and I'm using Ghidra for this process. In the above screenshot, we can see one of the files obtained from the honeypot, opened in Ghidra. Ghidra is a free and open-source tool, released by the National Security Agency in the United States, and is used for reverse engineering software. This, paired with another tool like radare2, can give a fascinating insight into how a piece of software works.

In the above screenshot, I followed the function map from the application's entry point (where it starts executing) to understand how data flows through it. This is one of the earlier functions that actually does something, and seemed like a good candidate to analyze as a result. In the highlighted portion, we can see that this is likely a check for something separated by dots.

cVar1 = *pcVar7;
while ((byte)(cVar1 - 0x30U) unaff_EBX = pcVar7 + 1;
uVar4 = (int)cVar1 - 0x30;
cVar1 = pcVar7[1];
while ((byte)(cVar1 - 0x30U) unaff_EBX = unaff_EBX + 1;
uVar4 = cVar1 + -0x30 + uVar4 * 10;
cVar1 = *unaff_EBX;
}
iVar3 = iVar3 + 1;
uVar8 = uVar8 if (cVar1 != '.') break;
pcVar7 = unaff_EBX + 1;
cVar1 = *pcVar7;
}

This code reads the first character in cVar1, which is taken from a pointer reference to pcVar1. pcVar1 likely contains the kernel version, and we'll get to why later. It then checks if it’s a digit (since '0' = 0x30), so this loop only continues if the character is '0'-'9'. It then initializes uVar4 to the value of the current digit. and moves to the next character. The second, nested while loop parses a multi-digit number as it repeatedly multiplies the previous value by 10 and adds the next digit, handling multi-digit octets. It then shifts the existing uVar8 value left by 8 bits and adds the newly parsed octet, putting it into a single unit. Finally, when it reaches a '.', it moves to the next octet, breaking the loop when nothing is left.

This next block is pretty interesting, but is where I'll be stopping on this analysis, as this is a quick overview of what you can do with a honeypot and the data you collect. This code starts by inverting all the bits in uVar8, the parsed value we talked about earlier, and then right-shifting it by 31 bits. This effectively checks if the original value is not all 1s (0xFFFFFFFF) or 0, treating those values as special cases. If the result of the shift is 0, the code skips the upcoming logic entirely and instead attempts to read the kernel version by accessing /proc/sys/kernel/osrelease. If it’s non-zero, meaning it's a "normal" value, it enters a loop that uses uVar8 along with a global value called DAT_080d7e64. It then creates a 64-bit value from those two 32-bit values (uVar9), possibly for use as a compound state or unique identifier. If the global DAT_080d7e64 is not zero, the code compares the two parts of the 64-bit value. Based on that, it decides whether to update the global with the newly parsed value or keep the previous value.

Once all of that is done, it checks whether the value (or a derived value from it) is less than a specific threshold: 0x20609. If it is, the code prints the message "FATAL: kernel too old" and jumps to a function that presumably halts execution. This entire function serves to analyze the system's kernel version and throws an error if it is. That threshold would correspond to Linux kernel version 2.6.9, which was released in 2004.

There are a lot of dangers on the internet

Be safe out there

As you can see throughout this article, the internet is a pretty scary place. There are lots of automated scanners trying to find victims, and many of them are successful in finding them. In this case, there was no damage, but on a real server, the consequences could be catastrophic. It's clear that these bad actors can do anything once they gain access, from stealing credentials and cryptocurrency wallets to deploying malware that attempts to spread to other devices.

As always, be vigilant when it comes to security. Use proper passwords, don't expose devices to the internet that don't need to be exposed, and adhere to common sense principles when browsing the web. This was one server that I ran for just over a week, and the results are scary if unsurprising. Imagine the countless devices out there that have already been compromised without the owner's awareness? These scripts are designed to hide themselves, so in my case, if my server had been compromised, I'd have needed to actively look for it to find it.