Compiled Python Code Used in a New PyPI Attack
The Python Package Index (PyPI), can’t catch a break. The popular Python programming language code repository has been subject to numerous attacks and has had to restrict new members for a while. Now, ReversingLabs, a software supply chain company, has found a novel attack using compiled Python code to dodge software code security scanners.
This technique leverages the direct execution of Python byte code (PYC) files and could be the first of its kind. Great. Just great.
Stumbled on the Attack
While hunting for threats across open source repositories looking for suspicious files, ReversingLabs stumbled upon this unique supply chain attack. It employs a previously unexplored approach, exploiting the capability of PYC files to be directly executed. Thus, it avoids security tools that scan Python source code (PY) files for trouble.
The ReversingLabs crew found the suspect package when its ReversingLabs Software Supply Chain Security platform, discovered suspicious behaviors from a fshec2 compiled binary. Specifically, once the binary was decompiled, they discovered URLs that reference the host by IP address, as well as the creation of a process and execution of a file.
Digging deeper with a manual analysis revealed that there was nothing obviously wrong with the source code. Instead, the malicious functionality was hidden within a single compiled Python byte code file.
Unlike more commonplace attacks that rely on obfuscation code, here, the entry point of the package was found in the __init__.py file, which imports a function from the other plaintext file, main.py. This contains Python source code responsible for loading the Python compiled module located in one of the other files, full.pyc.
So far, so innocent. But. this function import triggered a previously unseen loading technique inside the main.py file that avoids using the usual import directive, which is the simplest way to load a Python-compiled module. Had it done so, that would likely have raised a red flag. Instead, Importlib, the implementation of import in Python source code portable to any Python interpreter, is used to avoid detection by security tools. Importlib is typically used in cases where the imported library is dynamically modified upon import. However, the library loaded by main.py was unchanged, meaning that the regular import function would have sufficed. In short, they were up, the writers were up to mischief.
Loader scripts such as those in this package contain a minimal amount of Python code and perform a simple action: Loading of a compiled Python module. It just happens to be a malicious module. Inspector, the default PyPI security team tool, doesn’t, at the moment, provide any way of analyzing binary files to spot malicious behaviors.
Once active, the loaded library would then execute a host of malicious functions, such as collecting usernames, hostnames, and directory listings, and fetching commands for execution using scheduled tasks or cronjob.
The attack showed an ability to evolve, with the functionality to download commands from a remote server. This would have allowed the attackers to add new programs to their malware infection. It appears a keylogger was one such addition.
Two Targets Affected
Further research confirmed that at least two targets, which appear to be developer machines, had been infected. The hosts have had their machine names, usernames, and directory listings harvested. But, since the PyPI security team removed it immediately from the repository on April 17, 2023, there aren’t likely to be any additional cases in the wild.
That said, while the fshec2 package and its associated Command-and-Control (C2) infrastructure isn’t cutting-edge, a new method of attack is still bad news. We can expect other, more experienced Python hackers to adopt this path for their more sophisticated attacks.
For us, that means we must be more suspicious of Python-compiled byte code. What looks harmless at the surface may conceal a vicious attack.