PyPi的Typosquatting Attack
起因
今天对接一个项目时需要用到tensorflow等库,于是创建了一个虚拟环境后在里面直接pip安装。
pip install tensoflow
等到下载结束后发觉不对劲,原来我打错了,心中一惊,因为最近正好有一个利用用户拼写错误的pip攻击事件闹得沸沸扬扬,主角是request包(正确包名应该是requests,之前也经常敲错,当时还没有被污染)不过没太在意,过了大约几十分钟在/home目录下才注意到多出了一个txt文件名为typosquating-attack,里面的内容是
You have been hacked since 2020-08-11 11:05:20.548690
emmmmmm,我中招了。
回溯
好吧,首先确定的是这个攻击者大概率是个善意攻击者,否则就不会这么好心留下这个字条了。检查日志发现没有什么恶意的操作,这个东西可能就是个概念验证的产物,可以一步步回去看它是怎么完成这一系列操作的。
尽管十分怀疑是pip的问题,还是需要先定位到我在11:05分时运行了哪个命令。
# 如果你使用的是bash
# if you are using bash as your defaut shell
export HISTTIMEFORMAT='%F %T'
history
# 如果用的是zsh
# or if you are using zsh
history -i # or history -E
最终定位到如下几条命令
6726 11.8.2020 11:05 ls
6727 11.8.2020 11:05 python detection.py
6728 11.8.2020 11:05 pip install tensoflow
6729 11.8.2020 11:05 pip install tensorflow
确认其是来自tensoflow的攻击,接下来来到之前的虚拟环境文件夹venv中,在site-packages里仅找到tensoflow-distinfo,里面的METADATA显示它的确是一个typosquatting_attack的概念代码,还有github链接,可以直接去上面看代码了。
如果没有找到这类信息的话,我会去对应源的index中寻找,以tensoflow为例,我去的就是https://pypi.tuna.tsinghua.edu.cn/simple/,找到tensoflow的包,把对应的tar.gz下载下来进行分析。
代码
解压tar.gz包后目录如下,重点只关注setup的代码
├─PKG-INFO
├─README.md
├─setup.cfg
├─setup.py
└─tensoflow.egg-info/
├─dependency_links.txt
├─PKG-INFO
├─SOURCES.txt
└─top_level.txt
setup.py代码如下:
#!/usr/bin/env python
from __future__ import print_function
import getpass
import os
import time
import datetime
import ctypes
import sys
import platform
from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
long_description_filename = os.path.join(
os.path.dirname(os.path.abspath(__file__)), 'README.md')
with open(long_description_filename) as fd:
long_description = fd.read()
FILENAME = 'typosquating-attack'
USER_PATH = os.path.join(os.path.expanduser('~'), FILENAME)
TIME = str(datetime.datetime.now())
def touch_file():
with open(USER_PATH, 'a') as user_fd:
message = 'You have been hacked since {}'.format(TIME)
print(message)
user_fd.write(message + '\n')
class PostDevelopCommand(develop):
def run(self):
touch_file()
develop.run(self)
class PostInstallCommand(install):
def run(self):
touch_file()
install.run(self)
setup(
name='tensoflow',
version='0.0.5',
description='A typosquatting attack under package name tensoflow.',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/amboulouma/tensoflow',
packages=[],
license='MIT',
classifiers=[
'Environment :: Console',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Security',
],
install_requires=[],
tests_require=[],
cmdclass={
'develop': PostDevelopCommand,
'install': PostInstallCommand,
},
include_package_data=True,
)
检查下来,三个函数都没有恶意行为,仅仅是生成了一个文本文件,整个过程就是pip下载,利用user的权限运行该setup脚本,在user的home目录中创建了文本文件。postdevelop应该是作者测试时使用,install内的内容才是安装时的行为。
后记
pip的第三方库行为依赖于第三方库实现者,官方对此没有进行校验和审核,除了开源社区对代码的检视以外(而且一是代码贡献者并不多,二是代码贡献者也不一定会完整地阅读整个项目源码,这也导致理解代码并有足够水平发现后门的可能性降低,大项目可能情况好些,对于小项目参与代码审计的可能就很少了),其实没有什么更强的约束力,所以恶意攻击者完全可以在代码中埋后门。
这个攻击之前javascript的npm仓库也发生过,而且pip的投毒感觉是一个几年前的老技术了,不知道为何最近又被提起。可能是最近的request攻击实实在在地搭载了恶意代码进行挖矿吧。还好这次的tensoflow是一个19年的概念验证,而非真正的恶意程序。