这是python pip安装脚本legitmate还是特洛伊木马?
我将按照本教程安装python: 当谈到关于安装安装工具和pip的部分时,它会链接到我下载并运行的ez_setup.py脚本。它似乎安装了安装工具。然后我点击了指向pip-get.py的链接,只注意到了它 其中包括:这是python pip安装脚本legitmate还是特洛伊木马?,python,security,pip,antivirus,Python,Security,Pip,Antivirus,我将按照本教程安装python: 当谈到关于安装安装工具和pip的部分时,它会链接到我下载并运行的ez_setup.py脚本。它似乎安装了安装工具。然后我点击了指向pip-get.py的链接,只注意到了它 其中包括: #!/usr/bin/env python import sys def main(): sys.exit( "You're using an outdated location for the get-pip.py script, please "
#!/usr/bin/env python
import sys
def main():
sys.exit(
"You're using an outdated location for the get-pip.py script, please "
"use the one available from https://bootstrap.pypa.io/get-pip.py"
)
if __name__ == "__main__":
main()
引用的url包含以下看似可疑的代码。这是恶意代码还是安装pip的合法方式
注意:我已经删除了“二进制blob”的大部分行(比如18000行),因为若它是恶意的,我不希望这篇文章成为一个感染媒介
#!/usr/bin/env python
#
# Hi There!
# You may be wondering what this giant blob of binary data here is, you might
# even be worried that we're up to something nefarious (good for you for being
# paranoid!). This is a base85 encoding of a zip file, this zip file contains
# an entire copy of pip.
#
# Pip is a thing that installs packages, pip itself is a package that someone
# might want to install, especially if they're looking to run this get-pip.py
# script. Pip has a lot of code to deal with the security of installing
# packages, various edge cases on various platforms, and other such sort of
# "tribal knowledge" that has been encoded in its code base. Because of this
# we basically include an entire copy of pip inside this blob. We do this
# because the alternatives are attempt to implement a "minipip" that probably
# doesn't do things correctly and has weird edge cases, or compress pip itself
# down into a single file.
#
# If you're wondering how this is created, it is using an invoke task located
# in tasks/generate.py called "installer". It can be invoked by using
# ``invoke generate.installer``.
import os.path
import pkgutil
import shutil
import sys
import struct
import tempfile
# Useful for very coarse version differentiation.
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY3:
iterbytes = iter
else:
def iterbytes(buf):
return (ord(byte) for byte in buf)
try:
from base64 import b85decode
except ImportError:
_b85alphabet = (b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
b"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~")
def b85decode(b):
_b85dec = [None] * 256
for i, c in enumerate(iterbytes(_b85alphabet)):
_b85dec[c] = i
padding = (-len(b)) % 5
b = b + b'~' * padding
out = []
packI = struct.Struct('!I').pack
for i in range(0, len(b), 5):
chunk = b[i:i + 5]
acc = 0
try:
for c in iterbytes(chunk):
acc = acc * 85 + _b85dec[c]
except TypeError:
for j, c in enumerate(iterbytes(chunk)):
if _b85dec[c] is None:
raise ValueError(
'bad base85 character at position %d' % (i + j)
)
raise
try:
out.append(packI(acc))
except struct.error:
raise ValueError('base85 overflow in hunk starting at byte %d'
% i)
result = b''.join(out)
if padding:
result = result[:-padding]
return result
def bootstrap(tmpdir=None):
# Import pip so we can use it to install pip and maybe setuptools too
import pip
from pip.commands.install import InstallCommand
from pip.req import InstallRequirement
# Wrapper to provide default certificate with the lowest priority
class CertInstallCommand(InstallCommand):
def parse_args(self, args):
# If cert isn't specified in config or environment, we provide our
# own certificate through defaults.
# This allows user to specify custom cert anywhere one likes:
# config, environment variable or argv.
if not self.parser.get_default_values().cert:
self.parser.defaults["cert"] = cert_path # calculated below
return super(CertInstallCommand, self).parse_args(args)
pip.commands_dict["install"] = CertInstallCommand
implicit_pip = True
implicit_setuptools = True
implicit_wheel = True
# Check if the user has requested us not to install setuptools
if "--no-setuptools" in sys.argv or os.environ.get("PIP_NO_SETUPTOOLS"):
args = [x for x in sys.argv[1:] if x != "--no-setuptools"]
implicit_setuptools = False
else:
args = sys.argv[1:]
# Check if the user has requested us not to install wheel
if "--no-wheel" in args or os.environ.get("PIP_NO_WHEEL"):
args = [x for x in args if x != "--no-wheel"]
implicit_wheel = False
# We only want to implicitly install setuptools and wheel if they don't
# already exist on the target platform.
if implicit_setuptools:
try:
import setuptools # noqa
implicit_setuptools = False
except ImportError:
pass
if implicit_wheel:
try:
import wheel # noqa
implicit_wheel = False
except ImportError:
pass
# We want to support people passing things like 'pip<8' to get-pip.py which
# will let them install a specific version. However because of the dreaded
# DoubleRequirement error if any of the args look like they might be a
# specific for one of our packages, then we'll turn off the implicit
# install of them.
for arg in args:
try:
req = InstallRequirement.from_line(arg)
except:
continue
if implicit_pip and req.name == "pip":
implicit_pip = False
elif implicit_setuptools and req.name == "setuptools":
implicit_setuptools = False
elif implicit_wheel and req.name == "wheel":
implicit_wheel = False
# Add any implicit installations to the end of our args
if implicit_pip:
args += ["pip"]
if implicit_setuptools:
args += ["setuptools"]
if implicit_wheel:
args += ["wheel"]
delete_tmpdir = False
try:
# Create a temporary directory to act as a working directory if we were
# not given one.
if tmpdir is None:
tmpdir = tempfile.mkdtemp()
delete_tmpdir = True
# We need to extract the SSL certificates from requests so that they
# can be passed to --cert
cert_path = os.path.join(tmpdir, "cacert.pem")
with open(cert_path, "wb") as cert:
cert.write(pkgutil.get_data("pip._vendor.requests", "cacert.pem"))
# Execute the included pip and use it to install the latest pip and
# setuptools from PyPI
sys.exit(pip.main(["install", "--upgrade"] + args))
finally:
# Remove our temporary directory
if delete_tmpdir and tmpdir:
shutil.rmtree(tmpdir, ignore_errors=True)
def main():
tmpdir = None
try:
# Create a temporary working directory
tmpdir = tempfile.mkdtemp()
# Unpack the zipfile into the temporary directory
pip_zip = os.path.join(tmpdir, "pip.zip")
with open(pip_zip, "wb") as fp:
fp.write(b85decode(DATA.replace(b"\n", b"")))
# Add the zipfile to sys.path so that we can import it
sys.path.insert(0, pip_zip)
# Run the bootstrap
bootstrap(tmpdir=tmpdir)
finally:
# Clean up our temporary working directory
if tmpdir:
shutil.rmtree(tmpdir, ignore_errors=True)
DATA = b"""
P)h>@6aWAK2mly|Wk_|XSV~_F001E<000jF003}la4%n9X>MtBUtcb8d7WDSZ`-yK|J{ED>nxD8%G$E
w;SJgIu%S({0^J&<?b`!VLy#@n<|0cPDLHYs{qOJYNQ#stXW2BYmPFnc-j@&WsGL3fqE+&Xr6|AP<(}
1tW?Pk$wXAk5P1kMHN}i@n?CMH3EL*CoXd9mD=gGvpFRIN(lpFh4sqU_B>P#wbpYJnS!bH_kszWzd@`
H<yy>jp@sr7ZwDlGf&a-YEanKd3T&PZSB8xIW}4#deBf88!4R+dd5;5p$#pOUa^5aT0Nk+BIptF)mwO
xjJjFJ?H+W&B2{TtylTo<j0GFr)fNUDQIC5u!#EK|<945pLJg)3w2@^h6n(oAv4gUo>xXfT^H*v|rV`
Qf>&QoJEizcI-q^mp#kf>pM6NX_ZErFw2hh^uk2n|nM{8?fo*PBWjxO8U$uZxv0l}Dh+oJ9x(83VFs)
2<8d2{Jx`7Y(rd<REF6I*yg7!+JBfyDphOs8@@)t|QEJSw*YDBeZyaWmzU6csB~+(~1M_TE}r6vxIiR
?Ik89#CMk(g<2|&Lyn3;TdKH*QW3HbSiA0U_j??u<5;{jUXYm#(!?cp#E2HYewxW0s;v~`5sv}w`DLA
iCeGrx?
)H
"""
if __name__ == "__main__":
main()
#/usr/bin/env python
#
#你好!
#你可能想知道这里这个巨大的二进制数据块是什么,你可能想知道
#甚至担心我们在搞一些邪恶的事情(对你来说是好事)
#偏执狂。这是一个zip文件的base85编码,该zip文件包含
#pip的完整副本。
#
#Pip是一种安装软件包的东西,Pip本身就是一个有人需要的软件包
#可能需要安装,特别是如果他们希望运行这个get-pip.py
#剧本。Pip有很多代码来处理安装的安全性
#软件包,各种平台上的各种边缘案例,以及其他类似的
#编码在其代码库中的“部落知识”。因此
#我们基本上在这个blob中包含一个完整的pip副本。我们这样做
#因为替代方案是尝试实现一个可能
#无法正确执行操作,并且有奇怪的边缘情况,或者压缩pip本身
#下放到一个文件中。
#
#如果您想知道这是如何创建的,那么它使用的是位于
#在tasks/generate.py中称为“安装程序”。可以使用
#`invoke generate.installer`。
导入操作系统路径
进口蛋白胶
进口舒蒂尔
导入系统
导入结构
导入临时文件
#对于非常粗糙的版本差异非常有用。
PY2=系统版本信息[0]==2
PY3=系统版本信息[0]==3
如果PY3:
iterbytes=iter
其他:
def T红细胞(buf):
返回(ord(字节)表示buf中的字节)
尝试:
从base64导入b85decode
除恐怖外:
_B85字母表=(b“0123456789ABCDefghijklmnopqrstuvxyz”
b“abcdefghijklmnopqrstuvxyz!#$%&()*+-?@^ `{124;}~”)
def B85解码(b):
_b85dec=[无]*256
对于枚举中的i,c(i红细胞(_b85字母表)):
_b85dec[c]=i
填充=(-len(b))%5
b=b+b'~'*填充
out=[]
packI=struct.struct(“!I”).pack
对于范围(0,len(b),5)内的i:
区块=b[i:i+5]
acc=0
尝试:
对于以iterbytes(块)表示的c:
acc=acc*85+b85dec[c]
除类型错误外:
对于枚举中的j,c(iterbytes(chunk)):
如果_b85dec[c]为无:
升值误差(
“位置%d%”(i+j)处的错误base85字符”
)
提升
尝试:
out.追加(packI(acc))
除了struct.error:
raise VALUERROR('从字节%d开始的大块中的base85溢出'
%(一)
结果=b“”。加入(输出)
如果填充:
结果=结果[:-填充]
返回结果
def引导(tmpdir=None):
#导入pip,以便我们可以使用它安装pip,也可以安装工具
进口pip
从pip.commands.install导入InstallCommand
从pip.req导入安装要求
#包装器提供具有最低优先级的默认证书
类CertInstallCommand(InstallCommand):
def parse_参数(self,args):
#如果配置或环境中未指定证书,我们将提供
#通过默认设置拥有证书。
#这允许用户在任何喜欢的地方指定自定义证书:
#配置、环境变量或argv。
如果不是self.parser.get_default_values()。证书:
self.parser.defaults[“cert”]=cert_path#计算如下
返回super(CertInstallCommand,self).parse_args(args)
pip.commands\u dict[“安装”]=证书安装命令
隐式_pip=True
隐式设置工具=真
隐式_轮=真
#检查用户是否要求我们不要安装setuptools
如果sys.argv或os.environ.get中的“-no setuptools”(“PIP_no_setuptools”):
args=[x代表sys.argv[1:]中的x,如果x!=“--无设置工具”]
隐式设置工具=False
其他:
args=sys.argv[1:]
#检查用户是否要求我们不要安装车轮
如果args或os.environ.get中的“-no wheel”(“PIP_no_wheel”):
args=[x表示参数中的x,如果x!=“--no wheel”]
隐式_轮=假
#我们只想隐式安装setuptools和wheel,如果它们没有
#已存在于目标平台上。
如果使用默认设置工具:
尝试:
导入设置工具#noqa
隐式设置工具=False
除恐怖外:
通过
如果是U形车轮:
尝试:
进口车轮#noqa
隐式_轮=假
除恐怖外:
通过
#我们希望支持人们传递诸如“pip之类的东西,如果你在谈论它的脚本,那么它是完全安全的*
事实上,您可以按照注释中的说明,自己解码编码的文本,然后看到它是完美的
如果你特别偏执,就把它复制到一台有空隙的电脑上,然后试着执行它
*假设您的连接实际上是安全的,并且pypa.io没有被破坏。但是如果是这样的话,那么你可能会遇到更大的问题。如果你是从一个完全安全的角度来谈论脚本的话*
事实上,您可以按照注释中的说明,自己解码编码的文本,然后看到它是完美的
如果你特别偏执,朱