万字长文学习云安全 STS Policy注入在漏洞挖掘中的妙用
Z2O安全攻防
2026年10月15日 21:08
北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
以下文章来源于亿人安全
,作者行之
亿人安全
.
知其黑,守其白。手握利剑,心系安全。主要研究方向包括:Web、内网、红蓝对抗、代码审计、安卓逆向、CTF。
前言
我是行之,好久都没更新了,发一篇最近分析的文章吧。随着云原生架构的普及,针对凭据与身份边界的攻击正成为主流。正好近期得知朋友挖掘了几个严重漏洞,于是跟他学习了一下思路,然后研读了一下海外云安全文献,发现是通过针对%20STS(Security%20Token%20Service,安全令牌服务)的攻击:借助文件名、接口入参等可控字段篡改%20STS%20令牌下发逻辑,通过%20STS%20Policy%20注入获取高权限临时令牌,由此触发高危云上漏洞。原本计划讲个议题的,但国内相关研究文章偏少,既然没什么文章基础,于是先写篇长文沉淀一下,本文是我的学习过程,会从%20AK/SK、STS%20的基础原理讲起,搭配本地靶场搭建与真实的实战案例,为国内安全同行、白帽子提供攻防思路参考。本文纯手写原创,全文共一万字,欢迎各位安全同行交流探讨,也在此感谢先知社区提供发布平台。
一、先从一个最熟悉的注入说起:SQL
首先讲解STS云注入,我们最好先回到所有人都见过的%20SQL%20注入。它的本质其实是用户输入的数据被当作数据库代码进行了执行,也就是输入流入侵到了控制流的一个过程。
后端这么去写:
SELECT%20\*%20FROM%20uploads%20WHERE%20owner%20=%20'{input}';
开发者心里,input只是一个字符串值。正常输入alice时,数据库看到:
SELECT%20\*%20FROM%20uploads%20WHERE%20owner%20=%20'alice';
但当input变成alice'%20OR%20'1'='1,前面那个单引号先把原字符串闭合,后面的内容就进入了%20SQL%20语法,数据库最后看到的是一个永真条件:
SELECT%20\*%20FROM%20uploads%20WHERE%20owner%20=%20'alice'%20OR%20'1'='1';
记住这条数据流,下面会把同一个解释器换成%20JSON%20和云授权:
用户输入%20→%20字符串拼接%20→%20某门语言的源码%20→%20解释器%20→%20改变了语义
这里关于SQL注入,笔者不再赘述。历史上的很多漏洞都是输入流入侵到了控制流的过程,例如
SSTI(模板注入):输入进入%20Freemarker、Velocity、Jinja2%20的模板语法,${}%20或%20#{}%20之间的内容被模板引擎当代码渲染,变成%20RCE
Log4Shell(Log4j%20JNDI):输入的字符串里带%20${jndi:...},本该只是一行日志,却被%20Log4j%20当成查找指令触发%20JNDI%20加载,RCE。
所以只要我们能够找到输入流和控制流之间的关系,就可以更好的挖掘漏洞。
二、STS到底是个什么东西?
关于STS,很多人挖洞看到的通常是AK、SK、还有一个Token,比如长这个样子。
然后测试的时候一般会尝试能不能../../../或者直接调用一些现有的安全工具对这个下发的sts安全凭证进行测试,我们也可以在公众号上看到一些前辈发的文章和工具
但其实我们在挖掘一个东西之前,要去深入的了解这个东西,于是我们可以看一下云厂商文档对于STS的介绍。
其中我们可以看到一个有趣的东西,就是它的名字叫做Security%20Token%20Service,翻译过来就是安全令牌服务,那么为什么要这个东西呢,其实在早期阶段,存储桶刚出来的时候。很多开发在做文件上传,喜欢把AccessKey%20Secret硬编码在前端,来做文件上传。后来通过很多工具,例如Hae、或者Yakit,都可以对此类密钥进行扫描。互联网上关于AKSK的利用工具也是层出不穷。例如笔者曾经用过的一款teamssix%20的cf(Cloud%20Exploit%20Framework,云利用工具)(现已停更),就有很多的功能。因此云厂商后来统一推荐用%20STS:简单来说,就是由可信后端保管长期凭证,或者通过%20RAM%20角色获取调用%20STS%20的权限(这里用的比较多的就是PutObject和GetObject),再针对当前这一次上传签发一组临时凭证。这组凭证的有效期可以很短,权限也可以通过会话%20Policy%20进一步收窄,比如只允许向指定存储桶、指定目录,甚至指定对象上传文件。这样一来,长期%20AK/SK%20就不需要进入前端;即使临时凭证意外泄露,攻击者能够利用的时间和权限范围也都比较有限。
如果还是听不懂的话,我们可以来看看这个例子
很多业务都有\"用户往对象存储传文件\"的场景:工单附件、客服图片、头像、竞赛作品上传。把长期%20AccessKey%20放进浏览器是不可能的(谁拿到页面谁能复用),所以正常做法是:
用户登录业务系统;
浏览器要传文件时,先问业务后端要一份
短期凭证
;
业务后端用自己的长期身份,向云厂商申请一枚%2015%20分钟的临时凭证(STS);
浏览器拿着这枚临时凭证,
直接
把文件传到对象存储。
三、一个简单的输入流入侵到了控制流案例
如果放到代码上,我们可以手搓一个真实的业务环境,这里就拿官网的API文档举例
这里我们需要先去创建一个RAM%20用户,拿到AccessKey%20ID%20和%20AccessKey%20Secret
{
\"Version\":%20\"1\",
\"Statement\":%20[
//Statement%20是具体的授权规则列表
{
\"Effect\":%20\"Allow\",
//Effect%20表示这条规则的效果。常见取值有:Allow:允许。Deny:拒绝。这里默认是Allow放过去
\"Action\":%20\"oss:PutObject\",
//动作,这里可以从文档里面获取,PutObject就是可以上传对象,ListObject就是列出对象
\"Resource\":%20\"acs:oss:\:\:examplebucket/exampledir/\*\"
//持有这份权限的身份,可以向%20examplebucket%20存储桶中所有以%20exampledir/%20开头的对象写入文件,但没有读取、删除或访问其他目录的权限。
}
]
}
在权限编辑页面,我们可以选择对角色权限进行编辑,以上是笔者自己从官网获取到的
oss%20:%20PutObject
│%20 %20 %20 %20│
│%20 %20 %20 %20└──%20具体操作:写入对象
└──────────%20云服务:对象存储%20OSS
oss:PutObject%20主要用于向%20OSS%20上传或写入对象。比如:
exampledir/avatar.png
exampledir/report.pdf
exampledir/2026/07/demo.txt
Resource 表示这条权限可以作用在哪些资源上。把它拆开来看:
acs : oss : \ : \ : examplebucket / exampledir/\*
│ │ │ │ │ │
│ │ │ │ │ └─ 对象名称前缀
│ │ │ │ └──────────────── Bucket 名称
│ │ │ └─────────────────────────── 阿里云账号范围
│ │ └─────────────────────────────── 地域region
│ └───────────────────────────────────── 云服务
└─────────────────────────────────────────── 阿里云资源名称前缀
为什么我不能任意对象读取?
在传统文件系统中: exampledir/../../target.txt 会被路径解析函数归一化为: ../target.txt 因此可能逃出原来的目录。 但 OSS 使用的是 Object Key,不是真实文件路径。阿里云官网明确说明,OSS 本身没有传统文件系统的文件夹概念,只是通过 Key 中的 / 模拟目录效果。所以在 OSS 语义中: exampledir/../../target.txt 通常表示的就是一个完整 Key: Key = \"exampledir/../../target.txt\" .. 并不天然具有“返回上级目录”的含义。它不会自动变成: target.txt 如果会话 Policy 是: \"Resource\": \"acs:oss:\:\:examplebucket/exampledir/\*\" 那么 exampledir/../../target.txt 即使被接受,仍然只是一个以 exampledir/ 开头的 Key。它不会因此覆盖 Bucket 根部真正名为 target.txt 的对象。
简单来说就是无论你在客户端怎么传递,到了调用的时候其实还是会以字符串的形式进行传入,不能从输入流入侵到控制流。
哪些情况下会真的出现跨范围写入
这里自己学习了开发角度,就可以很容易明白如下这个案例
\"Statement\": [
{
\"Effect\": \"Allow\",
\"Action\": [
\"oss:GetObject\",
\"oss:PutObject\"
],
\"Resource\": [
\"acs:oss:\:\:BUCKET/uploads/alice/123.png\"
]
},
{
\"Effect\": \"Allow\",
\"Action\": [
\"oss:ListObjects\"
],
\"Resource\": [
\"acs:oss:\:\:BUCKET\"
]
}
]
}
但如果所有上传请求都直接获得第二条 Statement,那么普通用户无需输入\*,申请一次正常 STS 就可能列桶。这属于上传凭证权限配置过宽,你也可以理解成脱裤子放屁,直接sts拿cdk探测权限就探测出来了,无论你输入啥他肯定都有这个权限
所以在输入\*的时候其实并不会当作资源通配符去解析,也就不存在列桶的问题
九:文末
STS Policy 注入的价值,其实仍然在于输入流入侵控制流这个老问题。当文件名、目录、扩展名、Object Key 等原本只应作为业务数据使用的参数,跨越数据边界进入 JSON Policy、模板、命令或查询语句时,它们就可能改变原本的授权语义。最终造成的未必都是传统意义上的代码执行,也可能是动作范围扩大、资源范围扩大、跨目录访问、对象覆盖,甚至临时凭证权限提升。
所以审计 STS 相关接口时,重点不只是看有没有下发临时凭证,而是要继续思考:用户输入最终进入了哪里?服务端生成了怎样的Action、Resource、Condition 和 Object Key?角色上限是什么?这份临时凭证在数据面实际可以做什么?
感谢 weiwei、zer0one、Clown 、知名小朋友等师傅在案例、思路和测试细节上提供的帮助。
参考文献
[1] 《STS 身份注入攻击》
https://mp.weixin.qq.com/s/RGHT7brTuLaJ91ouaLvRzQ
[2] 阿里云 RAM:AssumeRole API
https://help.aliyun.com/zh/ram/developer-reference/api-sts-2015-04-01-assumerole
[3] 阿里云 RAM:权限策略基本元素
https://help.aliyun.com/zh/ram/user-guide/policy-elements
[4] 腾讯云 CAM:策略语法
https://cloud.tencent.com/document/product/598/10603
[5] AWS IAM:Session Policies
https://docs.aws.amazon.com/IAM/latest/UserGuide/access\_policies.html#policies\_session
[6] AWS STS:AssumeRole API
https://docs.aws.amazon.com/STS/latest/APIReference/API\_AssumeRole.html
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论