常见概念

“S3 存储桶” 是亚马逊 AWS(Amazon Web Services)对象存储服务(Simple Storage Service)的专属术语,其命名、API 接口、权限模型均为 AWS 私有标准。例如:AWS S3 存储桶的域名格式为 bucket-name.s3.amazonaws.com

主流厂商的命名惯例
所有云服务商的对象存储服务均使用独立品牌名称,避免与 AWS S3 混淆:

- **腾讯云**:对象存储(COS,Cloud Object Storage),存储桶称为 “COS 存储桶”
- **华为云**:对象存储服务(OBS,Object Storage Service),存储桶称为 “OBS 桶”
- **谷歌云**:云存储(Cloud Storage),存储桶称为 “GCS 存储桶”
- **<font style="color:rgba(0, 0, 0, 0.85);">阿里云</font>**<font style="color:rgba(0, 0, 0, 0.85);">: 对象存储服务名为 </font>**OSS(Object Storage Service)**<font style="color:rgba(0, 0, 0, 0.85);">,其存储桶在官方文档中统一称为 “OSS 存储桶”,域名格式为 </font>`<font style="color:rgba(0, 0, 0, 0.85);">bucket-name.oss-cn-hangzhou.aliyuncs.com</font>`<font style="color:rgba(0, 0, 0, 0.85);">(以杭州区域为例),API 接口遵循阿里云自有规范(如</font>`<font style="color:rgba(0, 0, 0, 0.85);">x-oss-acl</font>`<font style="color:rgba(0, 0, 0, 0.85);">头部字段)。</font>

后文主要涉及阿里云的内容,详细介绍一下阿里云OSS的相关概念:

OSS:对象存储服务。对象存储可以简单理解为用来存储图片、音频、视频等非结构化数据的数据池。相对于主机服务器,具有读写速度快,利于分享的特点。

OSS工作原理: 数据以对象(Object)的形式存储在OSS的存储空间(Bucket )中。如果要使用OSS存储数据,您需要先创建Bucket,并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后,您可以将数据以Object的形式上传到Bucket,并指定Object的文件名(Key)作为其唯一标识。

相关定义:

Bucket:用户用来管理所存储Object的储物空间。

Object:OSS存储数据的基本单元。

Key:当存储文件(Object)时,需要指定此Object的名称(Key),后续您将通过这个Key来获取该Object的内容。 Key也可以用来模拟文件夹的一些属性。

Data:存储的数据本体。

AccessKey

  • AccessKey ID:它是一个唯一的标识符,类似于用户名,用于标识访问云服务的用户身份。云服务系统可以通过它识别出是哪个用户在发起请求。
  • AccessKey Secret:它是一个保密的字符串,类似于密码,需要严格保密。与 AccessKey ID 配合使用,用于对请求进行签名,确保请求的合法性和数据的安全性。

几种策略

Bucket ACL策略

1
2
3
当您希望粗粒度地控制某个Bucket的读写权限,即Bucket内的所有Object均为统一的读写权限时
您可以选择使用Bucket ACL的方式。Bucket ACL包含公共读、公共读写和私有。
您可以在创建Bucket时设置Bucket ACL,也可以在创建Bucket后根据自身的业务需求修改Bucket ACL

Bucket 策略

OSS支持面向资源的授权方式,允许在Bucket级别而不是用户级别设置权限策略。使用Bucket Policy可以授权当前云账号或者其他阿里云账号下单个或多个RAM用户、RAM角色等访问Bucket内的指定资源。Bucket Policy除提供策略语法的授权方式以外,还提供了图形化界面的授权方式,助力您结合业务场景,快速完成授权。

环境搭建

先配置一下AWS命令,方便本地命令行去操作

https://blog.csdn.net/qq_45392321/article/details/134488239

没有信用卡,注册不了AWS的海外账户,暂时不能测试AWS S3了

阿里云

先试试阿里云吧,先去阿里云官网免费试用一个oss

试用成功后,找到对象存储控制台-创建Bucket

找到文件上传部分,随意上传几个测试文件

华为云

华为云用于 bucket策略修改处使用

https://www.huaweicloud.com/product/obs.html

选最便宜的套餐

进入控制台创建

先随意配置一下权限

漏洞学习

遍历漏洞

在创建Bucket桶时,默认是private的权限,如果在错误的配置下,给了listobject权限,就会导致可遍历存储桶。

情况一 仅公有读写

在只配置读写权限设置为<font style="color:rgb(28, 30, 33);">公有读</font><font style="color:rgb(28, 30, 33);">公共读写</font>,未配置Listobject的情况下

无法直接列出对象

但可以直接访问对应的文件路径

情况二 ListObject

  1. 关闭阻止公共访问

OSS支持通过设置Bucket Policy和ACL来实现公共访问。公共访问无需特定权限或身份验证,容易引发数据泄露和外网下行流量的风险

  1. 授权ListObject操作

  1. 访问bucket域名测试

发现我们上传的文件列表被成功遍历,通过拼接文件名即可下载所有文件。

[https://bucket-drblack.oss-cn-beijing.aliyuncs.com/flag.txt](https://bucket-drblack.oss-cn-beijing.aliyuncs.com/flag.txt)

Bucket桶名爆破

类似于目录爆破,只不过目录爆破一般通过状态码判断,而这个通过页面的内容判断。阿里云OSS的Bucket 不存在有两种状态,分别是 <font style="color:rgba(0, 0, 0, 0.85);">InvalidBucketName</font><font style="color:rgba(0, 0, 0, 0.85);">NoSuchBucket</font>

无权限访问

访问成功

任意文件上传/覆盖

设置读写权限

文件成功上传并覆盖原文件

Bucket接管

漏洞原理:管理员通过域名解析并绑定了一个存储桶,但是管理员将存储桶删除后,没有将域名解析的CNAME删除,访问域名会出现NoSuchBucket。因此可以登录自己的华为云账号,创建同样的Bucket 进行接管。阿里云华为云等云存储桶接管方法差不多。

当 Bucket 显示<font style="color:rgb(28, 30, 33);"> NoSuchBucket </font>即表明可接管。

1
body="NoSuchBucket" && body="BucketName" && body="aliyuncs.com"

找到一个阿里云的桶,显示为NoSuchBucket

http://ztkrewitzhao.img-ap-southeast-1.aliyuncs.com/

注意地区、桶名称必须完全一致。翻阅文档确认为新加坡地区

刷新后变为AccessDenied,接管成功

修改权限后上传flag.txt,上传成功!

Access key 泄露

工作原理

当你向云服务提供商的 API 发送请求时,需要在请求中包含 AccessKey ID 和经过 AccessKey Secret 签名的信息。云服务提供商接收到请求后,会根据 AccessKey ID 找到对应的用户,并使用相同的签名算法和 AccessKey Secret 对请求进行验证。如果验证通过,就会处理该请求;如果验证不通过,则会拒绝请求。

如果攻击者设法找到了AK与AS,就意味着对OSS云存储服务的直接接管

寻找方法

  1. 敏感文件的泄露(Spring泄露的heapdump文件、数据库、运维的备份文件、内存泄漏等)
  2. phpinfo等探针文件也会抛出AS与AK
  3. ThinkPHP的Debug模式,以及其他的一些因配置不当报错而泄露AK与AS
  4. github等开源平台入手(适用于体量较大的目标)

下面以本人的AccessKeyId做个简单测试。

首先下载一个OSS浏览器,填充ID和Secret

即可正常操作oss

STS token重放攻击

在阿里云 OSS(对象存储服务)中,STS(Security Token Service)Token 是一种临时安全凭证,用于替代长期访问密钥(AccessKey),为用户或应用程序提供临时、受限的 OSS 资源访问权限。STS提供的是一种临时访问授权。通过STS可以返回临时的AK\SK和STSToken,这些信息可以直接发给临时用户用来访问OSS。

具体案例查看如下链接

【漏洞挖掘系列】OSS的STS模式授权案例

Bucket策略修改

这里阿里云和华为云都配置出来有点问题,

先安装一个OSS的工具ossutil

下载并安装命令行工具ossutil_对象存储(OSS)-阿里云帮助中心

配置bucket策略。

允许 :<font style="color:rgb(51, 51, 51);background-color:rgb(248, 250, 251);">oss:PutBucketPolicy </font> <font style="color:rgb(51, 51, 51);background-color:rgb(248, 250, 251);">oss:GetBucketPolicy</font>

禁止: <font style="color:rgb(51, 51, 51);">oss:ListObjects</font> <font style="color:rgb(51, 51, 51);">oss:GetObject</font>

直接请求资源,被policy禁止

通过ossutil查看bucket策略,可以通过Put上传Policy进行覆盖

修改下面的DenyAllow,存储为oss.json 然后上传

1
ossutil bucket-policy oss://bucket-drblack --method put oss.json

访问,恢复正常访问

并且策略成功修改

ACL策略修改

华为云ACL权限配置之前

配置可读后,可以看见成功显示了acl策略信息

但目前只配置了可读权限,还不能实现ACL的文件覆盖进行策略修改。把权限改为ACL可读可写, 并且公共权限为私有

当直接访问界面,会显示403无权限,这时候尝试访问acl文件,查看权限。

可建存在匿名用户对ACL的可写权限

官方权限图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<AccessControlPolicy xmlns="http://obs.myhwclouds.com/doc/2015-06-30/">
<Owner>
<ID>ba3b02b27e1e48c2b71410ecc2c90fac</ID>
</Owner>
<AccessControlList>
<Grant>
<Grantee>
<ID>ba3b02b27e1e48c2b71410ecc2c90fac</ID>
</Grantee>
<Permission>FULL_CONTROL</Permission>
<Delivered>false</Delivered>
</Grant>
<Grant>
<Grantee>
<Canned>Everyone</Canned>
</Grantee>
<Permission>FULL_CONTROL</Permission>
<Delivered>false</Delivered>
</Grant>
</AccessControlList>
</AccessControlPolicy>

PUT成功

再次查看ACL发现成功,同时访问根目录成功

403 AccessDenied 绕过

容易碰到以下的403现象


权限为私有

除非有Accesskey 和AccessSecret,否则没办法利用

没有配置listobject

没有包含ListObject操作,所以无法访问

但可通过遍历文件目录去获取文件

存储桶地点错误

如果存储桶端点错误,也会出现403 AccessDenied,但存储桶不一定就是私有的,它会出现提示,给出正确的地点,只需要改为正确的地点访问就行,改为正确地点后,判断

https://anern.oss-us-east-1.aliyuncs.com/

比如先为hangzhou,改为beijing后恢复

网络上还有个情况说是没有文件,即使存储桶非私有也会出现403,但是我测试后是正常的。

一些疑问

策略修改这部分,查询策略的时候,工具需要先配置accessKeySecret和accessKeyID,这里两个值目前认为是两种情况:

  1. 配置自己的

利用对方bucket策略缺陷,可以任何人查询其策略,然后再进行策略修改。实验一下

但是阿里云测试时,只能当配置bucket策略为完全控制的时候可以访问到policy

但是如果是拎出来单独配置就不行?为什么 应该是哪里配置限制了。

  1. 配置目标对象的(感觉就很鸡肋了,如果有对方的Key了何必再修改策略)

模拟测试

用了两个html去模拟了一个简单的场景:请求外部存储桶内容进行头像显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>获取头像</title>
<style>
button {
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
border: none;
background-color: #4CAF50;
color: white;
cursor: pointer;
border-radius: 5px;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<button id="fetchButton">点击获取头像</button>

<script>
document.getElementById('fetchButton').addEventListener('click', function() {
const imageUrl = 'https://bucket-drblack.oss-cn-beijing.aliyuncs.com/2.png';

// 使用时间戳创建唯一URL,避免缓存
const timestamp = new Date().getTime();
const url = `displayImage.html?imageUrl=${encodeURIComponent(imageUrl)}&t=${timestamp}`;

// 直接跳转,携带图片URL参数
window.location.href = url;
});
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>展示头像</title>
<style>
img {
width: 100%;
max-width: 800px; /* 设置最大宽度,防止图片过大撑破页面 */
height: auto;
display: block;
margin: 50px auto;
}
</style>
</head>
<body>
<img id="avatarImg" src="" alt="头像">
<script>
const urlParams = new URLSearchParams(window.location.search);
const imageUrl = urlParams.get('imageUrl');
if (imageUrl) {
document.getElementById('avatarImg').src = imageUrl;
} else {
const xhr = new XMLHttpRequest();
xhr.open('GET', window.location.href, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
const responseData = JSON.parse(xhr.responseText);
const imageUrl = responseData.imageUrl;
if (imageUrl) {
document.getElementById('avatarImg').src = imageUrl;
}
}
};
xhr.send();
}
</script>
</body>
</html>

点击获取头像按钮后,界面跳转

显示了一个图片

通过抓包可以分析,此处链接里是一个存储桶的链接。

访问该存储桶,已经列出了目录文件

这时候就可以试试能否直接put文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT /towdgg.txt HTTP/1.1
Host: bucket-drblack.oss-cn-beijing.aliyuncs.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Content-Length: 7
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Priority: u=0, i
Sec-Ch-Ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip

asiawr

用xray也可以检测出来

参考链接

干货 | 实战中通过AccessKey与AccessSecret接管文件存储服务的攻击场景

AWS Pentesting - HackTricks Cloud

Bucket 策略可写 | T Wiki

浅析OSS存储桶漏洞