点击上方蓝字关注我们
PyPI是Python官方的第三方库的仓库,在运行pip install [package name]等命令时会引用它。PyPI存储库的GitHub Actions中存在一个漏洞,该漏洞允许恶意拉取请求执行任意命令。这允许攻击者获得对存储库的写权限,从而在pypi.org上实现任意代码执行。
研究人员阅读了发布在GitHub上的PyPI源代码,发现它使用了一个名为Pyramid的 Python网络框架。之后,研究人员继续检查PyPI源代码,并发现了以下两个漏洞。
PyPI曾具有可用于Python项目的文档功能。该功能之后由于使用率不高被开发人员删除,但他们没有删除现有文档。
因此,删除这些文档的功能可以被请求,并在此拉取请求中实现。此功能通过在内部使用以下代码来删除文档:
def remove_by_prefix(self, prefix):
if self.prefix:
prefix = os.path.join(self.prefix, prefix)
keys_to_delete = []
keys = self.s3_client.list_objects_v2(Bucket=self.bucket_name, Prefix=prefix)
for key in keys.get("Contents", []):
keys_to_delete.append({"Key": key["Key"]})
if len(keys_to_delete) > 99:
self.s3_client.delete_objects(
Bucket=self.bucket_name, Delete={"Objects": keys_to_delete}
)
keys_to_delete = []
if len(keys_to_delete) > 0:
self.s3_client.delete_objects(
Bucket=self.bucket_name, Delete={"Objects": keys_to_delete}
)
从上面的代码片段中可以看出,它使用带有前缀参数的list_objects_v2函数来获取要删除的对象。并且用户拥有的项目的名称会被传递到前缀参数中。
这意味着如果有人删除了名为examp的项目中的遗留文档,它将删除名称以examp开头的项目文档,例如example、exampleasdf。
PyPI具有包的权限管理功能。在此功能中,项目所有者可以授予/删除权限。在删除权限过程中存在一个漏洞。从数据库中获取权限信息时,PyPI使用以下代码:
role = (
request.db.query(Role)
.join(User)
.filter(Role.id == request.POST["role_id"])
.one()
)
从上面的代码片段可以看出,它在获取要删除的权限信息时没有指定项目ID。因此,攻击者可以通过假设role_id来删除其他项目的权限。
以上发现的这些漏洞不会产生太大影响,充其量只能用于骚扰。因此,研究人员决定继续深挖,以寻找一个可用于执行任意代码的漏洞。
一番探索之后,研究人员发现推送到pypa/warehouse存储库主分支的代码会自动部署到pypi.org。这意味着,如果我们能够获得pypa/warehouse存储库的写权限,就可以在pypi.org上执行任意代码。
因此,研究人员检查了GitHub Actions的工作流文件,该文件默认具有pypa/warehouse存储库的写权限,并发现了以下漏洞。
在pypa/warehouse中,有一个名为combine-prs.yml的工作流。该工作流被用于收集分支名称以dependabot开头的拉取请求,并将它们合并为一个拉取请求。
combine-prs.yml工作流中,缺少对拉取请求作者的验证。这意味着,如果有人创建了一个分支名称以dependabot开头的拉取请求,则可以强制此工作流处理精心制作的拉取请求。
但是,此工作流仅将拉取请求合并为一个拉取请求。因此,此工作流生成的拉取请求将由人工审核,如果其中包含恶意更改,他们将直接丢弃它。
因此,这不能直接用于执行任意代码。但是,研究人员在通读代码时发现了另一个漏洞。在combine-prs.yml的第119行,有以下代码。
script: |
const prString = `${{ steps.fetch-branch-names.outputs.prs-string }}`;
${{ }}表达式将在被传递到Bash之前进行求值。这意味着${{ }}表达式不关心Bash中的上下文,因此如果steps.fetch-branch-names.outputs.result包含像";curl https://example.com;# 之类的字符串,curl https://example.com将被执行。
因为这个工作流使用了actions/checkout,.git/config 包含secrets.GITHUB_TOKEN,该令牌具有写权限。因此,通过执行诸如cat .git/config之类的命令,可能会泄漏具有pypa/warehouse存储库写权限的GitHub访问令牌。
如上所述,如果有人将更改推送到主分支,它将被自动部署到pypi.org。由于steps.fetch-branch-names.outputs.prs-string包含拉取请求的标题,因此可以使用以下攻击步骤,在pypi.org上实现任意命令执行。
2. 在pypa/warehouse中找到一个以dependabot开头的分支
4. 创建一个名为`;github.auth().then(auth=>console.log(auth.token.split("")))//的拉取请求
6. 对pypa/warehouse具有写权限的GitHub访问令牌将被泄露,因此可以在主分支添加任意修改
![PyPI中潜在的远程代码执行漏洞 PyPI中潜在的远程代码执行漏洞]()
本文始发于微信公众号(SecTr安全团队):PyPI中潜在的远程代码执行漏洞
评论