跳到正文
Hacker News· bigfish2026·· 4 小时前精选AI 评分83

如何定位并确认 PHP2Shell、LiteLLM 与 GitLab 漏洞的待修补资产

PHP2Shell, LiteLLM, GitLab: Find What You Need to Patch

AI 导读

作者用 AWS 与 Azure 的只读命令,梳理 PHP2Shell、LiteLLM 1.107.0、GitLab 等安全事件的受影响资产、责任归属与凭据暴露范围。

推荐理由

以多起高危漏洞为实例,给出跨 AWS 与 Azure 定位运行位置、公网暴露、责任归属和凭据权限的只读排查流程。

正文 · AI 翻译

2026年10月16日至23日期间,PHP、Node.js、GitLab、LiteLLM、OpenCode 和 eMudhra 证书颁发机构均发生了严重安全事件。PHP、Node.js 和 GitLab 于10月21日发布了修复版本,与问题 LiteLLM 版本发布于同一天。每份公告最后都给出了某种形式的升级、重建或轮换建议。

完成升级是容易的部分。真正耗时的是,针对你自己的账户查明受影响组件在哪里运行、由谁负责,以及它能访问什么。如果你有可信的资产清单,这只需一个下午。如果没有,那就要花一周时间在 Slack 消息串中来回沟通,而这一周并没有给任何人留出一周的时间。Amazon 的 MadPot 蜜罐在漏洞披露前四天记录到了一次 PHP2Shell 利用尝试 在漏洞披露前四天。

Meme titled 'The internet this week' listing PHP: critical RCE, and the patch may be incomplete; Node.js: urgent RCE patches; GitLab: CVSS 10.0 unauthenticated RCE, 12 years of releases; LiteLLM 1.107.0: shipped with credential-stealing malware; OpenCode Console: leaked users' API keys; eMudhra CA: private key was literally 4. Below it, SpongeBob gets up from his armchair with the caption 'Ight imma head out'.
本周的互联网。很有诱惑力,但总得有人找到那些服务器。

本周的事件

事件发生了什么修复措施你必须查明的事项
PHP2Shell (CVE-2026-109618, CVE-2026-109619)PHP 中的两个预认证远程代码执行漏洞,评分均为 9.2。漏洞披露前就出现了利用尝试。PHP 8.5.12、8.4.27、8.3.36 或 8.2.35。临时配置变通方案无法覆盖所有变体,因此升级是唯一完整的修复方法。哪些实例、容器和 App Service 应用运行 PHP,其中哪些使用 8.1 或更早版本?
Node.js (CVE-2026-111497)内置 Brotli 解码器中的越界写入,可能导致崩溃、内存泄露或远程代码执行,另有九项修复。22.23.4、24.22.1 或 26.12.1。生命周期结束的发布分支不会获得修复。哪些 Lambda 函数、容器和虚拟机运行 Node.js,其中哪些使用 20.x 或更早版本?
GitLab (CVE-2026-110264)通过 GitLab 正则表达式编译器中的整数溢出实现未经身份验证的远程代码执行,CVSS 评分为 10.0。该问题可追溯到 2014 年发布的 GitLab 7.0。补丁版本于10月21日发布。自托管实例没有变通方案。是否存在无人记得的自托管 GitLab,以及互联网能否访问它?
LiteLLM 1.107.0 (Microsoft 的分析)PyPI 和官方容器镜像中的恶意版本会在每次 Python 启动时运行凭据窃取程序。从经过验证的版本重建,然后轮换该环境能够访问的所有凭据。它在哪里运行、以什么身份运行,以及该身份能够访问什么?
OpenCode Console (TechCrunch)入侵者进入了一个遗留系统,用户保存在 Console 中的 AI 服务商密钥可能已经泄露。一些用户报告了未经授权的扣费。撤销并重新签发这些密钥。该密钥还存储在哪里,撤销后哪些工作负载会中断?
eMudhra (The Register)八个中间 CA 私钥都是小于 256 的整数。其中一个就是数字 4。浏览器屏蔽了这些中间证书。我们是否持有来自该证书链的证书,我们的镜像是否仍然信任它?

上述名单中没有哪一项是冷门技术。其中两个是网络上很大一部分站点所依赖的运行时,一个是许多公司仍在自行托管的源代码管理服务器,还有一个是为路由 LLM 流量而仓促采用的 AI 网关。如果你在 AWS 或 Azure 上运行着规模不小的环境和资产,那么其中至少有一项很可能需要你来处理。

漏洞利用窗口正不断缩短

Mandiant 追踪攻击者在漏洞披露后多久才会利用漏洞。其 漏洞利用时间分析 显示,平均利用时间在 2018–2019 年为 63 天,在 2020–2021 年为 44 天,在 2021–2022 年为 32 天。2023 年这一平均值为 5 天,Mandiant 当年追踪到的已遭利用漏洞中,70% 是零日漏洞,即在补丁发布之前就已被利用。

Drew Silcock 的文章这就是新的网络安全常态吗?于 10 月 23 日登上 Hacker News 首页,认为 LLM 进一步压缩了这一过程,因此,从严重 RCE 公开到针对它发动自动化攻击之间的间隔,如今已从数周缩短至数小时。PHP2Shell 正是如此。这些漏洞是在 AI 模型的协助下发现的;在禁披露期争议之后,打好补丁的二进制文件在安全公告之前就出现了;而大多数人还没来得及安装修复,利用尝试就已经开始。

你的暴露窗口期,是查明哪些对象受影响所需的时间,加上完成修复所需的时间。多年来,大多数团队一直借助 CI/CD、托管运行时和自动补丁来缩短第二个数字。第一个数字仍然取决于一张电子表格、一条 Slack 讨论串,以及那个还记得旧 GitLab 主机当初如何配置的人。

这正是这些框架把资产清单放在首位的原因。CIS Controls 将企业资产清单和软件清单列为控制项 1 和 2;直到控制项 7 才涉及漏洞管理。CISA 的BOD 23-01 要求美国联邦机构每 7 天运行一次自动化资产发现,每 14 天进行一次漏洞枚举。如果你不知道某台服务器存在,就不会给它打补丁。

使用原生工具处理漏洞公告

下面我将结合本周发生的事件,说明如何利用 AWS 和 Azure 开箱即用的功能回答上述每个问题。下面的每条命令都是只读的。

1. 运行位置

从 Node.js 开始。在 Lambda 上,受支持的托管运行时默认自动获取运行时更新,因此,大多数使用当前 Node.js 运行时的函数无需重新部署即可获得修复。有两组例外。运行在已弃用的 nodejs20.x 运行时上的函数,在 Node.js 20 于 2026 年 4 月结束生命周期后,便停止接收安全补丁。以容器镜像部署的函数则沿用固化在镜像中的 Node.js 版本。因此,你真正需要的是一份清单,列出使用旧运行时或以镜像形式打包的函数:

# Node.js and container-image Lambda functions in every enabled region
for region in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
  echo "== $region"
  aws lambda list-functions --region "$region" \
    --query "Functions[?PackageType=='Image' || (Runtime && starts_with(Runtime, 'nodejs'))].[FunctionName, Runtime || PackageType]" \
    --output text
done

基于镜像的函数会出现在该输出中,因为 Lambda API 无法告诉你镜像内部包含什么。对于这类函数,你需要使用镜像扫描器,或者重新构建。

在 Azure 上排查 PHP2Shell 时,App Service 会记录每个 Linux 应用的运行时技术栈,而 Azure Resource Graph 可以在你有权读取的所有订阅中对其进行搜索:

az graph query -q "
resources
| where type =~ 'microsoft.web/sites'
| mv-expand setting = properties.siteProperties.properties
| where setting.name =~ 'LinuxFxVersion' and tostring(setting.value) startswith 'PHP'
| project name, resourceGroup, subscriptionId, stack = tostring(setting.value)
" --first 1000 -o table

任何运行 PHP 8.1 或更旧版本的环境都不会再获得常规的上游修复,因此应将其置于列表首位。

虚拟机和容器更难处理,因为云控制平面并不知道其中安装了哪些软件。AWS Systems Manager Inventory、Amazon Inspector 和 Microsoft Defender for Cloud 正是为此而生,而且每个工具只能看到已为其启用对应工具的机器。这个覆盖缺口危害最大,我稍后会再回来讨论。

2. 互联网能否访问它

GitLab 已为 GitLab.com 本身打了补丁。自托管实例要靠你们自己处理,除非进行升级,否则没有变通办法。真正让我担心的通常不是平台团队运维的 GitLab,而是某个团队在 2019 年搭建的实例,或是随某项收购一并接手的那个实例,它仍在响应 443 端口上的请求。

先按名称和标签搜索,然后查看暴露情况:

# Instances that look like GitLab, with public IPs and security groups
aws ec2 describe-instances \
  --filters "Name=tag:Name,Values=*gitlab*,*GitLab*" \
  --query "Reservations[].Instances[].[InstanceId, State.Name, PublicIpAddress, join(',', SecurityGroups[].GroupId)]" \
  --output text

# Security groups with an inbound rule open to the whole internet
aws ec2 describe-security-groups \
  --filters Name=ip-permission.cidr,Values=0.0.0.0/0 \
  --query "SecurityGroups[].[GroupId, GroupName, VpcId]" \
  --output text

在 Azure 中,az vm list -d --query "[?contains(name, 'gitlab')].{name:name, rg:resourceGroup, ips:publicIps}" -o table 也能让你获得相同的第一轮排查结果。

请谨慎解读这些信息。名称筛选只能找到由他人如实命名的服务器,而没有公共 IP 的实例仍可通过公共负载均衡器访问。这两点都让你在事件处置过程中很难仅凭控制台得出答案。如果已经有一份记录了这些关系的资产清单,就会容易得多。

3. 它归谁所有

找到服务器后,必须有人批准停机,而且最好这个人知道它是如何安装的。首先应该查看标签。如果没有标签,CloudTrail 可以告诉你是谁创建了该资源:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=ResourceName,AttributeValue=i-0abc123example \
  --query "Events[].[EventTime, EventName, Username]" \
  --output table

事件历史只能追溯 90 天,Azure Activity Log 也是如此。要调查 2019 年的服务器,你需要使用 S3 中的跟踪记录并发起 Athena 查询,是谁创建了这个 AWS 资源? 一文介绍了具体做法。即便如此,创建者也可能已经离职。在我们调查过的一个案例中,89 台闲置的 Azure 虚拟机源于一次收购,而当前团队中没人能说出它们的用途。正是在这类资源中,未打补丁的 GitLab 最终会长期潜伏。

4. 它能访问什么

LiteLLM 说明了为什么发现软件包存在问题只是第一步。根据Microsoft 的分析,这个恶意版本窃取了 AWS、Azure 和 Google Cloud 的凭据缓存、Kubernetes 服务账户文件、Docker 配置以及挂载的密钥。它还试图从 AWS 和 GCP 元数据服务中获取凭据,并在代理主机上从 LiteLLM 自己的数据库中读取提供商密钥。

扫描器报告的是恶意软件包。你真正需要响应的是主机运行时所使用的身份。对于每个安装了 1.107.0 的环境,查明它所具有的角色以及该角色被允许执行哪些操作:

# The instance profile behind an EC2 instance
aws ec2 describe-instances --instance-ids i-0abc123example \
  --query "Reservations[].Instances[].IamInstanceProfile.Arn" --output text

# The role inside that profile, and the policies attached to it
aws iam get-instance-profile --instance-profile-name litellm-proxy \
  --query "InstanceProfile.Roles[].RoleName" --output text
aws iam list-attached-role-policies --role-name litellm-proxy-role
aws iam list-role-policies --role-name litellm-proxy-role

在 ECS 上,身份是任务定义中的任务角色。在 EKS 上,则是映射到 Pod 服务账户的角色。微软的建议是:从一台干净的机器开始调查,使用经验证的制品进行重建,轮换所有可访问的凭据,并按摘要固定容器镜像,而不是使用 latest 这样的浮动标签。我要特别强调“干净的机器”这一点:他们的分析表明,载荷会在 Python 启动时运行,因此在被怀疑的环境中运行 pip 来检查该包,可能会触发它。

5. 密钥或证书还存放在哪里

OpenCode 告诉用户撤销并重新签发已暴露的密钥。撤销只需点击一下。真正的工作是弄清楚撤销后哪些东西会出问题,因为 AI 服务提供商密钥最终会出现在 Secrets Manager 或 Key Vault 中、Lambda 和 App Service 设置中、CI 变量中,以及开发人员的 .env 文件中。在 AWS 上,Secrets Manager 至少会记录每个机密最后读取和轮换的时间,而 CloudTrail 的 GetSecretValue 事件会显示是哪些角色读取了它:

aws secretsmanager list-secrets \
  --query "SecretList[].[Name, LastAccessedDate, LastRotatedDate]" \
  --output table

eMudhra 暴露了证书领域的同一问题。私钥规模这么小,任何人都可能计算出它并签发证书;在相关中间证书被拦截之前,浏览器都会信任这些证书。值得进行两项检查。首先,在你导入的证书中搜索颁发者为 eMudhra 或 emSign 的证书。ACM 按区域划分,而 CloudFront 使用的证书位于 us-east-1,因此要在你使用的每个区域中执行此操作,包括 us-east-1:

for arn in $(aws acm list-certificates \
    --includes keyTypes=RSA_2048,RSA_3072,RSA_4096,EC_prime256v1,EC_secp384r1,EC_secp521r1 \
    --query "CertificateSummaryList[].CertificateArn" --output text); do
  aws acm describe-certificate --certificate-arn "$arn" \
    --query "Certificate.[DomainName, Issuer, Type]" --output text
done | grep -i -E "emudhra|emsign"

在 Azure 中,Resource Graph 可查询各订阅中的 App Service 证书:

az graph query -q "
resources
| where type =~ 'microsoft.web/certificates'
| where tostring(properties.issuer) contains 'emSign' or tostring(properties.issuer) contains 'eMudhra'
| project name, resourceGroup, subscriptionId, issuer = tostring(properties.issuer), expires = properties.expirationDate
" -o table

其次,拥有独立信任存储的软件在更新该存储之前会继续信任某个 CA。在旧 AMI、基础镜像和捆绑自带 CA 列表的运行时中,即使浏览器早已不再信任某个被拦截的证书链,它仍会继续生效。

扫描器和控制台止步之处

Amazon Inspector 和 Defender for Cloud 很擅长判断给定机器上的某个软件包版本是否存在漏洞。AWS 和 Azure 控制台很擅长告诉你一个账号在某个区域里有什么。但在安全公告发布的那个早晨,这两者都不是你需要的。

第一个问题是覆盖面。扫描器只能看到已为其启用扫描的账号、订阅和机器,而收购获得的 GitLab 服务器通常位于一个无人接入管理的账号中。第二个问题是归属。扫描结果汇入一个共享队列,而其中没有人有权重启其他人的服务器,因此结果就一直搁在那里。没有关联负责人的发现项不过是又一个告警。第三个问题是上下文。扫描器会告诉你某个软件包存在问题,却不会说明该主机的角色可以读取该账号中的每个 S3 存储桶,或另外三个团队的服务会调用它。在 LiteLLM 这起事件中,这些上下文构成了事件的大部分。

填补这些缺口的是一份保持最新、并记录系统中存在什么、由谁负责以及如何与其他一切相连的资产清单。这正是我们开发 Cloud Sleuth 的目标。

Cloud Sleuth 中的实际效果

Cloud Sleuth 会映射你的 AWS 和 Azure 资源,无论资源是否带有标签,都会为每项资源指定负责人,并让资源及其归属信息持续保持最新。下面就是按照 Cloud Sleuth 的设计方式提出的 GitLab 问题。

示意示例——命令和输出并非最终版本:

$ sleuth ask "gitlab servers the internet can reach, and who owns them"

ec2  scm-legacy-01            account acquired-prod · eu-west-1
  image     GitLab CE 13.12 AMI, launched 2021-06-02
  exposure  internet → alb-scm (public) → target group scm-https → :443
  owner     team-devex            confidence 88%
    created by  role/terraform-ci (CloudTrail, 2021-06-02)
    managed by  github.com/acme/legacy-infra (terraform state)
  role      scm-legacy-instance → read on 4 S3 buckets, 2 secrets
  findings  no owner tag · public ingress

这一条结果就涵盖了暴露面、归属和可达性:该服务器、从互联网通往它的路径、应呼叫的团队及得出该答案的证据,以及该服务器的角色能够触达的对象。没有它,你就得在四个控制台和一次 CloudTrail 搜索之间来回排查,而且每个账号都得重新来一遍,包括收购而来的那个账号。

资产清单搜索将 AWS 和 Azure 资源置于同一套模式中,你可以用 SQL 或普通英语进行查询,因此,上面逐个区域排查 Lambda 的循环会变成跨两个云的一条查询,而且负责人信息已经关联在内:

示例——架构尚未最终确定:

select cloud, account, type, name, runtime, owner
from resources
where runtime in ('nodejs18.x', 'nodejs20.x')
order by owner;

云图谱根据你的实际账户绘制网络路径、负载均衡器目标、挂载关系和 IAM 关系,让你在开始轮换之前就能看到被遗忘服务器前面部署了什么,以及它的角色可以访问什么。所有权模型根据 CloudTrail、Azure Activity Log、IaC 状态、命名方式和账户结构推断负责人,并显示置信度分数及其背后的证据。防护栏会标记无归属、无标签和孤立的资源;在 Cloud Sleuth Cloud 中,相关发现可通过 Slack 或 Jira 路由给所属团队,同时持续运行诸如“弃用的运行时上不得运行函数”之类的自定义策略。还有一个只读的 MCP 服务器,因此在事故处理期间,你可以询问 Claude 或 Cursor 等智能体:“我们的哪些函数运行在 Node.js 20 上,分别由谁负责?”

鉴于本周发生了供应商控制台泄露客户存储于其中的密钥,以及热门软件包中夹带凭据窃取器的事件,信任模型至关重要。Cloud Sleuth CLI 默认只读,不会在你的服务器上安装任何东西,并且可在你的机器或 VPC 中运行。如果你想试用,可以加入早期访问名单。

一小时的演练

从本周的安全公告中选一个,计时看看你的团队完成以下事项需要多久。列出 Node.js 和 PHP 运行的所有位置,包括 Lambda 运行时、App Service 堆栈、容器镜像和 VM。找出所有自行部署的 GitLab,以及任何其他自托管的开发者工具,并检查互联网能否访问它们。在每一项旁边写上负责人的姓名。对于任何安装了 LiteLLM 1.107.0 的环境,列出其运行时承担的角色,并轮换这些角色能够访问的所有内容。记录 AI 提供商密钥的存储位置,以及哪些工作负载使用这些密钥。在证书中搜索 eMudhra 或 emSign 签发方。

如果这花了超过一个小时,预计处理下一份公告也要花大约同样长的时间。

常见问题

我的 AWS Lambda 函数是否受到 Node.js Brotli 漏洞影响?

只有使用 node:zlib 解压缩来自不可信来源的 Brotli 数据的代码才存在暴露风险。默认情况下,Lambda 会自动向受支持的托管运行时推送运行时更新,函数日志中的 INIT_START 行会显示其正在运行的运行时版本。已弃用的 nodejs20.x 运行时上的函数不再获得安全补丁;容器镜像函数则使用镜像中所带的 Node.js 版本,因此应升级或重新构建这些函数。

GitLab.com 是否受到 CVE-2026-110264 影响?

GitLab 会修补 GitLab.com 和 GitLab Dedicated 本身,发布版本的覆盖情况显示,两者均已在运行修复后的版本。自行部署的 GitLab Community 和 Enterprise Edition 实例需要升级至已修补的版本。没有可用的变通方案。

如果某个环境安装了 LiteLLM 1.107.0,我应该怎么办?

应将其视为已遭入侵。从一台干净的机器上开展调查,使用经过验证的版本重新构建,确认 Python 库路径中已不存在 cook.pth、cook.py 和 sitecustomize.py,并轮换该环境能够访问的每项凭据:云端角色、CI/CD 密钥、SSH 密钥和模型提供商密钥。Microsoft 的分析列出了应搜索的指标。

新漏洞公布时,Cloud Sleuth 有何帮助?

它能回答决定你响应速度的问题:哪些 AWS 和 Azure 资源在影响范围内、哪些资源可由互联网访问、每项资源的所有者是谁,以及每项资源能够访问什么。负责人信息会附有相关证据,因此修复工作可以交给真正能够实施修复的团队。CLI 在你的机器上以只读模式运行,你现在就可以加入早期访问名单。

来源:Hacker News · cloudsleuth.io