Recently I noticed the news about AI-generated malware which was hidden in images with pandas. While the main purpose of the malware is “only” cryptomining, it uses several interesting techniques which are not so common for coinminers. It uses nicely formatted and commented setup script (generated by AI). It supports wide variety of coinminers for various cryptocurrencies and for GPU and different CPU architectures. Its another component, hideproc, tries to hide the Koske miner from file listings and processes.

Fig. 1: Panda image with hidden Koske malware

Note: another name for koske miner is k0ske. Also attackers used both variants in their code.

I wanted to analyze this malware, too. The first task was to obtain the malware samples. Aqua Security mentioned some indicators in their article. However, it lacks the hashes of images and the most of the URLs with them were already blocked. Fortunately, thanks to the public sources such as UrlScan and Any.Run I found at least the images with malware samples. On the other hand, I was not able to find the initial tools for downloading those images and deploy the Koske malware. So regarding the Initial access, I can only summarize the findings from Aqua Security’s article.

It seems that attackers exploited misconfigured JupyterLab instance to achieve remote code execution. Then, they uses bash scripts utilizing curl and wget to download images with rootkit component hideproc and Koske miner from URL shorteners. They downloaded only the malicious content from images utilizing the Range HTTP headers. The attackers also established various methods for persistence, such as cron jobs, systemd services and autostart on boot via /etc/rc.local.

I was lucky to obtained two panda images from still alive URLs used by the attacker. One image contains Koske miner and second contains ‘hideproc’ rootkit. Let’s start with the miner itself.

Koske miner

The downloaded image contains two kind of data - the picture of panda (very probably generated by AI) and the the shell script for Koske malware setup. The malware portion of the image is not obfuscated, just concatenated after the image data. It started at offset 58100, see Fig. 2. The Koske shell script has approximately 2000 lines in total (including comments and empty lines).

Fig. 2: Bash shell script after JPEG data in image (some data omitted for clarity)

System information discovery

The shell script determines the platform (Fig. 3). While it is primary for Linux, it also contains very basic support for macOS, see Fig. 4. It tries to install Homebrew and XMRig miner. However, the lot of other code does not check for platform even if it is platform-specific. Even more, when installing packages on Linux, it also supposed that it is Debian-based distribution. It seems that right now Koske miner is only for Debian Linux (and Ubuntu and its derivatives) with with some attempts to be multiplatform.

Fig. 3: Koske checks for the host platform
Fig. 4: Homebrew and XMRig installation on macOS

This shell script contains lot of checks and error handling with comments typical for code generated by AI. Comments are in Serbian language, which may be caused that the attacker prompted his LLM in Serbian language instead of english. The pretty-formatted comments are clearly visible in the next part (Fig. 5), where the Koske checks network availability and if GitHub is accessible from the infected machine. If not, then it tries to “resolve” this problem in several steps:

  • unset system proxy
  • clear firewall rules and allow all traffic
  • clear proxies for APT package manager and git
  • modify DNS servers (it uses Cloudflare and Google DNS) and prevent its modification by setting immutable attribute

If GitHub is still not available, the malware tries to setup proxies from the public proxy lists mostly obtained from GitHub - logical error, which is more common in code generated by AI than human. As last resort, it contains the hardcoded list of proxy servers.

Fig. 5: Attempts to establish network access to GitHub

Next, it checks the CPU architecture and if GPU is available (see Fig. 6). In our case, when behavioral analysis was performed in Any.Run sandbox, there was detected CPU with 4 cores and without GPU suitable for coinmining.

Fig. 6: CPU and GPU checks

Coinminer installation

Based on these checks, Koske setup script choose the preferred cryptocoin and then coinminers (see Fig. 7). In analyzed sample, it supports approximately 20 different cryptocoins and several miners for each coin (see Fig. 8).

Fig. 7: Preferred cryptocoin for detected hardware. CPU3 is CPU with 3 and less cores
Fig. 8: Miners for cryptocoins. For CPU with 4+ cores, it is mbc coin and cpuMinerTermux from GitHub

In abovementioned Any.Run analysis, for CPU with 4+ cores and without GPU, ‘mbc’ coin is selected with cpuMinerTermux from GitHub (Fig. 9). More specifically, it is downloaded from GitHub repository “cpuMiner” belonging to the owner “vozstanica”. But it is only for x86-based CPUs with 4+ cores, on other harwdare, there is another coinminer used.

Fig. 9: Downloading of cpuMinerTermux during behavioral analysis on x86 CPU with 4 cores without GPU

On aarch64 without GPU, coinminer ccMinerARM from the GitHub repository of the same user will be downloaded. This coinminer is also mentioned in the article by Aqua Security. They (incorrectly) stated that “vozstanica” translates to “train station” in Slovak language. But this is not true, in Slovak language, train station is either “vlaková stanica” or “železničná stanica”. It seems that “vozstation” is incorrectly detected as Slovak word by Google Translate. Then, this observation was mentioned by BleepingComputer, and it sounds like Koske could be Serbian-Slovak malware (without confident attribution). But there are lot of other 3rd party coinminers that Koske can download depending on the hardware, and “vozstation”’s miners are only two of many, as we can see on Fig. 8. There are several clues about Serbian orogin, such as comments in AI-generated code and Serbian IP address used for initial exploitation mentioned by Aqua Security, however, it is still not enough to do some conclusions (and also no direct attribution was mentioned by Aqua Security). As they stated, usage of AI can hide some national-specific fingerprints, too.

Fig. 10: Health checks and stats during installation of coinminer

Later, the analyzed Koske setup script performs some health checks such as if the coinminer is active and mining pool is available. It also tries to mask the process executable with bind mount to the empty directory in ramdisk (/dev/shm/.k0ske), as we can see in the last line of output on Figure 10. The source code of that “masking” is on Figure 11.

Fig. 11: Attempt to use bind mount for process masking

Koske malware also save the process ID (PID) of running coinminer into the file /dev/shm/.hiddenpid. More on this later in the next part.

Fig. 12: Process ID of coinminer is saved in file /dev/shm/.hiddenpid

Persistence

After coinminer deployment, the Koske script continues with setup of persistence. It modifies the user’s .bashrc script to include .bashrc.koske. It also creates .bash.logout. They both clean the proxy settings, set the Cloudflare and Google nameservers, perform some validations and again download and run the Koske setup script from the image with panda. They use two URLs with shorteners, primary and backup. See Figure 13 and Indicators of Compromise at the end of this post.

Fig. 13: Persistence in bash logon and logout scripts

Indicator removal

Finally, Koske setup script deletes some traces of its execution. It removes bash history, wget history and vim info (despite the fact that it did not use vim).

Fig. 14: Clean the history

Hideproc rootkit

Same as with the previous malware - there is an image with JPEG data followed by malicious content (offset 56228). This time, it is C source code of rootkit, originally called hideproc.c. This source code is short, especially when compare with the Koske shell script installer. The hideproc.c has only 74 lines in total.

Fig. 15: C source code after JPEG data in image (some data omitted for clarity)

The main purpose of hideproc rootkit is to hide some Koske files and directories from directory listings (e.g. obtained by command ls). Another purpose is to hide coinminer process with the PID stored in the file /dev/shm/.hiddenpid (e.g. obtained by command ps which reads directory “/proc”). To achieve all of this, hideproc rootkit hooks the readdir() function and hides entries which contain the hardcoded strings “hideproc.so” for filename, “koske” for keyword and “hideproc” for module name (however, all checks for “hideproc.so” are redundant in this case), see Fig. 16 and 17.

Fig. 16: Hidden patterns in rootkit and loading of the hidden PID
Fig. 17: Hooking of readdir() function and filter hiddenpid entry in /proc directory

The rootkit source code is compiled to the shared object hideproc.so and loaded into processes with LD_PRELOAD mechanism either via LD_PRELOAD environment variable or via file /etc/ld.so.preload. In Figure 18 it is demonstrated how it affects the output of command ls.

Fig. 18: Rootkit affects the output of command ls when loaded via LD_PRELOAD

When rootkit is loaded, it hides some part of Koske malware. However, there are still parts of the malware which remains visible, such as .bash_logout persistence or downloaded coinminer from GitHub or elsewhere.

VirusTotal Detections

In the time of writing this post, the Koske samples were almost undetected on VirusTotal. The panda images had one or zero detections. The extracted source code of hideproc rootkit had one detection and the extracted Koske shell script installer had only 4 detections.

Fig. 19: VirusTotal detections of the Koske samples

Video from analysis on Any.Run

Indicators of Compromise

SHA256 hashes

  • image with Koske miner shell script
    • f8c6c873e8289ebbd52d3fc5b6552129d7e20f8a3466aca2d6f1dd2cdd578780
  • image with hideproc rootkit
    • cf9000db6b026ce350982a7dac67152d1649b0021d4b3f0b2cc7315b254e7161
  • Koske miner shell script
    • ac6d9c301cd098804841e82704257aeb7c9ebb7b3cb2966a1f443ef383238704
  • hideproc rootkit source code
    • 60f4b67f349a13fbf6ef1f45eb6c3147e88015571b2de179e32605e2ead651a0

URLs

  • primary URL shortener for image with Koske miner shell script
    • hxxps[://]k0ske[.]short[.]gy/panda_v14
  • backup URL shortener for image with Koske miner shell script
    • hxxp[://]tiny[.]cc/panda-v14
    • hxxps[://]tini[.]fyi/panda_v14[.]jpg
  • image with K0sk miner shell script
    • hxxps[://]i[.]imgs[.]ovh/2025/07/22/P4XLO[.]jpeg
    • hxxps[://]iili[.]io/FNpWEOJ[.]jpg
  • URL shortener for image with hideproc rootkit
    • hxxps[://]tini[.]fyi/panda_v14[.]jpg
  • image with hideproc rootkit
    • hxxps[://]i[.]imgs[.]ovh/2025/07/17/DGlLc[.]jpeg
    • hxxps[://]iili[.]io/FWJp7u2[.]jpg

References