云服务安全学习
云服务就是云上的服务,比如从云厂商(AWS、阿里云)买来的服务
国内云厂商:
- 阿里云
- 腾讯云
- 华为云
- 天翼云
- Ucloud
- 金山云
- ......
国外云厂商:
- AWS
- GCP
- Azure
- ......
每个云厂商对云服务的叫法不同,这里以AWS的为例:
- S3对象存储(Simple Storage Service),可以简单理解为网盘,略有区别
- EC2弹性计算服务(Elastic Computer Cloud),简单理解为云上的虚拟机
- RDS云数据库(Relational Database Service),简单理解为云上数据库
- IAM身份管理和访问管理(Identity and Access Management),简单理解为云控制台上的一套身份管理服务,可以用来管理每个子账号的权限
综上来看,其实可以简单看作一些本地的功能/服务放到了云上,那么就会产生对应的风险,值得研究
在下文的案例图片中,笔者可能会更多用国内厂商(比如aliyun)进行举例,漏洞实例使用TerraformGoat靶场进行演示
学习顺序参考https://wiki.teamssix.com/
对象存储
对象存储(Object-Based Storage),也可以叫做面向对象的存储,现在也有不少厂商直接把它叫做云存储,很经典的就是Amazon S3 (Simple Storage Service) 简单存储服务,是 Amazon 的公开云存储服务,与之对应的协议被称为 S3 协议,目前 S3 协议已经被视为公认的行业标准协议,因此目前国内主流的对象存储厂商基本上都会支持 S3 协议
Amazon S3标准中,对对象存储中可以有多个桶(Bucket),而对象(object)存放在桶里,对象包含三个key、Data、Metadata部分:

- Key指存储桶中的唯一标识符,例如一个 URL 为:
https://yuy0ung.s3.ap-northeast-2.amazonaws.com/d0g3,这里的 yuy0ung 是存储桶 Bucket 的名称,/d0g3就是 Key - Data很好理解,就是存储的数据本体
- Metadata意味元数据,可以简单理解为数据的标签、描述之类的信息(区别于传统的文件存储,在传统的文件存储中这类信息是直接封装在文件里的,而云上有了元数据的存在,可以大大的加快对象的排序、分类和查找)
操作使用Amazon S3的方式大致如下:
- AWS 控制台操作
- AWS 命令行工具操作
- AWS SDK 操作
- REST API 操作,通过 REST API,可以使用 HTTP 请求创建、提取和删除存储桶和对象
接下来记录S3相关攻击手法
Bucket爆破
在不知道bucket名称的时候,可以通过爆破获得Bucket名称,类似于在常规渗透中的子域名挖掘,但略有区别:
- 子域名挖掘通常通过响应的状态码进行判断
- Bucket爆破通过页面回显的内容进行判断
当 Bucket 不存在时有如下两种返回情况,分别是 InvalidBucketName 和 NoSuchBucket:


存在时同样有两种情况,一种是列出Object,当然这样可能存在存储桶遍历导致敏感信息泄漏:

一种是显示AccessDenied:

这样通过返回内容的不同,就可以进行 Bucket 名称爆破了,知道 Bucket 名称后,Key 的爆破
Bucket接管
假如在进行渗透时,发现目标的一个子域名显示NoSuchBucket,那么只需要重新创建一个与HostID一样的存储桶名称即可接管该存储桶,接管后上传文件并设置公开即可让该域名显示我们上传的任意文件
在腾讯云的对象存储中,无法造成以上的操作,因为在腾讯云的对象存储域名中,有一个APPID,这个APPID来自我们的账户信息中
任意文件上传
如果对象存储的配置不当,比如公共读写,就有可能造成任意文件上传,甚至是文件覆盖
攻击方法与中间件的PUT漏洞类似,使用PUT方法上传文件即可,若目标的对象存储支持html解析,那么还可以尝试进行XSS、挂暗链、挂黑页、供应链投毒等操作
比如这里访问可以发现有一张图片:

尝试使用PUT方法覆盖:

接下来再尝试访问图片,可以发现内容已经被覆盖:

Bucket ACL 可写
ACL即访问控制列表,用来管理访问权限的规则,若 ACL 可写,意味着用户或攻击者可以直接修改这些权限规则
比如下面的S3对象存储,在Bucket ACL可写时将Permission权限修改为FULL_CONTROL:
{
"Owner": {
"ID": "d24***5"
},
"Grants": [
{
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers"
},
"Permission": "FULL_CONTROL"
}
]
}
这样一来,写入策略后即可实现存储桶的遍历等操作
Object ACL 可写
原理和上面的Bucket ACL可写类似
比如这里访问flag没有权限:

我们通过?acl来查看这个对象的权限:

发现是private,尝试通过PUT方法修改为public-read,需要在请求头添加x-oss-object-acl参数:

回显200,看来修改成功了,再次尝试访问flag,发现成功将flag改为公共可读:

Bucket 策略可写
部分环境的acl可读写:

可以尝试通过PUT方法修改策略读取敏感文件,比如这个S3对象存储的Bucket策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:GetBucketPolicy",
"s3:PutBucketPolicy"
],
"Resource": [
"arn:aws:s3:::teamssix"
]
},
{
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::teamssix/flag"
]
}
]
}
这里禁止读取flag
但如果将第20行的Deny改为Allow,即可成功访问flag
当然,有的场景将Allow改为Deny则有可能导致业务瘫痪
Bucket Object 遍历
和常规WEB服务的index of目录遍历类似,可以访问Bucket可以查看其中所有的Object,将其中的Key拼接到站点URL后面即可访问相应对象
比如这里的对象遍历,可以看见Key为flag:

拼接即可访问:

特殊的Bucket 策略
有些 Bucket 会将策略配置成只允许某些特定条件才允许访问,当我们知道这个策略后,就可以访问该 Bucket 的相关对象
比如这个Bucket,正常访问会被拒绝:

但如果我们添加一个策略指定的UA头HxSecurityLab,就能够成功访问:

弹性计算
前面提到EC2弹性计算可以简单理解为云上的虚拟机,而这里的“弹性”,则是其一大特点:
按需配置:CPU、内存、硬盘、网络等硬件参数随时调整(秒级切换)
弹性伸缩:服务器数量可根据流量自动增减,应对突发高峰或节省闲置成本
弹性计算在国内叫ECS居多,同样也存在一些安全问题,下面进行记录
弹性计算面临的风险
1.凭证泄露
云上的凭证泄漏可以如下划分:
- 控制台账号密码泄露,例如登录控制台的账号密码
- 临时凭证泄露
- 访问密钥泄露,比如AK/SK泄露
- 实例登录凭证泄露,例如 AWS 在创建 EC2 生成的证书文件遭到泄露
凭证信息的收集一般有如下方法:
- github敏感信息搜索
- 反编译APK、小程序
- 网站源码泄露
2.元数据
元数据服务是一种提供查询运行中的实例内元数据的服务,当实例向元数据服务发起请求时,该请求不会通过外部网络传输,而是通过本地网络请求
根据上面所说,如果获得了目标 EC2 权限或者目标 EC2 存在 SSRF 漏洞,就可以获得到实例的元数据
下面是可以 ssrf 的常见元数据点:
packet
https://metadata.packet.net/userdata
http://metadata.google.internal/computeMetadata/v1beta1/
http://169.254.169.254/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/
http://metadata/computeMetadata/v1/
http://metadata.google.internal/computeMetadata/v1/instance/hostname
http://metadata.google.internal/computeMetadata/v1/instance/id
http://metadata.google.internal/computeMetadata/v1/project/project-id
http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=trueorcale
http://192.0.0.192/latest/
http://192.0.0.192/latest/user-data/
http://192.0.0.192/latest/meta-data/
http://192.0.0.192/latest/attributes/alibaba
http://100.100.100.200/latest/meta-data/
http://100.100.100.200/latest/meta-data/instance-id
http://100.100.100.200/latest/meta-data/image-id
在云场景下,可以通过元数据进行临时凭证和其他信息的收集,以阿里云ECS(和EC2相似)的靶场为例:
-
这里有一个ssrf漏洞点:

-
能够进行任意文件读取:

-
尝试SSRF读取元数据:
http://100.100.100.200/latest/meta-data/
可以看见很多metadata,下面列出一些对于红队而言价值较高的metadata,可以用于参考:
mac 实例 MAC 地址 hostname 实例主机名 iam/info 获取角色名称 local-ipv4 实例本地 IP public-ipv4 实例公网 IP instance-id 实例 ID public-hostname 接口的公有 DNS (IPv4) placement/region 实例的 AWS 区域 public-keys/0/openssh-key 公有密钥 /iam/security-credentials/<rolename> 获取角色的临时凭证我们可以拼接路由访问其中内容:

-
当然我们也可以尝试读取user-data (前提是目标已经配置了用户数据,不然会返回 404):
http://100.100.100.200/latest/user-data/User Data 是在创建 ECS 实例时,可以提供给实例的一种自定义数据,通常用于自动化配置或脚本执行
它的内容类似于dockerfile的内容,能允许用户在实例启动时自动执行某些操作
发现在启动时写入了flag,尝试读取:

3.账号劫持
如果云厂商的控制台存在漏洞,用户账号也会存在一定风险
AWS 的控制台曾经出现过一些 XSS 漏洞,攻击者就可能会使用这些 XSS 漏洞进行账号劫持,从而获得目标云服务器实例的权限
4.恶意的镜像
其实就是我们常说的供应链攻击
AWS 在创建实例的时候,用户可以选择使用公共镜像或者自定义镜像,如果这些镜像中有恶意的镜像,那么目标使用该镜像创建实例就会产生风险
以 CVE-2018-15869 为例,关于该漏洞的解释是:当人们通过 AWS 命令行使用「ec2 describe-images」功能时如果没有指定 --owners 参数,可能会在无意中加载恶意的 Amazon 系统镜像 ( AMI),导致 EC2 被用来挖矿
对此,在使用 AWS 命令行时应该确保自己使用的是不是最新版的 AWS 命令行,同时确保从可信的来源去获取 Amazon 系统镜像
5.其他的初始访问方法
除了上面提到的方法,还可以通过云服务上的应用程序漏洞、SSH与RDP的弱口令等传统场景下的方法进入目标实例
使用用户数据执行命令
在上面我们提到了功能类似于dockerfikle的user-data,我们可以联想到:攻击者能修改实例的用户数据并向其中写入待执行的命令,这些代码将会在实例每次启动时自动执行
通常来说修改user-data只能在dashboard或命令行上操作设置,所以想要恶意修改难度很大
弹性计算下的权限维持
这里记录一些传统渗透之外的权限维持手法
1.用户数据
类似于开机启动项,利用user-data执行反弹shell命令即可实现维持
但很鸡肋的是:user-data只能在实例停止时修改,并且目标有可能很长时间不会重启实例
2.后门镜像
在获取到控制台权限后可以尝试对镜像进行修改、删除创建,以此替换上后门镜像
如此,下次用户在选用该镜像创建实例的时候,就会触发镜像中的恶意代码
3.创建访问密钥
如果条件允许,可以尝试创建新的访问密钥进行权限维持
4.创建辅助账号
通过创建高权限子账号的方式进行权限维持,然后通过这个子账号进行后续的持续攻击行为
获取共享快照数据
如果当前凭证有相关权限,可以通过创建共享快照的方式,将控制台下的实例挂载由该快照生成的卷,从而获取到目标的弹性计算中的内容
在拿到目标控制台权限时,如果无法登录到实例,可以为目标实例打个快照,然后将快照共享给自己,我们再将其挂载到自己的实例,即可查看里面的数据
另外,在平时进行云上攻防的时候,偶尔会碰到虽然有 ECS 实例管理权限但无法在实例上执行命令的情况,我们同样可以采取类似的思路:
为目标实例打快照 —> 创建磁盘 —> 创建实例 —> 挂载磁盘 —> 利用 SAM 等文件获取密码或哈希 —> 使用密码或哈希远程登录获取权限
其实如果对内网渗透比较熟悉的话,可以看出来这个思路其实就类似于卷影拷贝获取域控的ntds.dit
RDS云数据库
即云上的数据库服务,适用于需要托管和管理关系型数据库的各种场景
RDS信息收集
在RDS控制台中可以收集到一些目标公司人员信息,比如邮箱、目标 RDS TOP SQL 语句、TOP 连接主机、TOP 用户等
当然在共享快照中,可以根据快照名称判断查找,查看是否有和目标相关联的快照,然后再通过还原快照的方式,尝试获得快照中 RDS 的数据
MSSQL读取实例信息
在拿到MSSQL数据库权限后,可以通过BULK INSERT 读取数据库所在实例的文件,比如AWS下读取日志文件:
create table #testtable(context ntext);
BULK INSERT #testtable FROM 'C:\ProgramData\Amazon\EC2Launch\log\agent.log'
WITH (DATAFILETYPE = 'char',KEEPNULLS)
select * from #testtable
drop table #testtable;
PostgreSQL数据库SSRF
如果获得了 PostgreSQL 数据库权限,可以通过 PostgreSQL 中的 dblink 插件横向到其他同网段数据库,这里以 AWS RDS 为例
比如在无法通过外部网络连接另一目标PostgreSQL,就可以尝试使用已有PostgreSQL进行横向并执行数据库命令:
create extension dblink;
select dblink_connect('test','host=x.x.x.x port=xxx user=xxx password=xxx dbname=postgres sslmode=disable');
create table t(id int);
select * from dblink_send_query('test', 'select version();');
select * from dblink_get_result('test') as t(res text);
身份和访问管理
用于允许用户创建和管理云账户、用户组、角色、权限策略,并控制谁可以访问特定的资源,以及他们可以对这些资源执行哪些操作
国内各厂商叫法各不相同:RAM、CAM、IAM......
阿里云的RAM:

IAM权限操作
权限提升
若当前用户具备编辑 IAM 策略的权限,但没有某些服务权限的话,那么可以在 IAM 中开启这个服务权限,以实现提权
RAM中也有同样的功能点:

权限维持
原理也比较简单,直接在 IAM 中创建一个拥有高权限的用户即可:

创建用户后赋予管理权限即可,但国内通常都需要安全验证,所以比较有难度:

控制台接管
在上面我们提到了通过SSRF读取ECS的元数据以及user-data,其实我们还可以进一步利用,获取该云账户的所有阿里云服务权限:
-
首先分析一下我们获取到的元数据:

可以看到这里存在ram/目录,说明当前云服务器配置了RAM角色,这样我们可以尝试获取临时凭证
-
我们访问ram/:

-
这里有一个security-credentials/,存储了RAM角色名称信息:

可以看到RAM角色为huocorp-terraform-goat-role
-
访问角色内容获得临时凭证:

-
将该临时凭证配置到aliyun命令行工具:
aliyun configure --mode StsToken
-
配置好之后我们就可以来创建子账户并赋予管理员权限了:
aliyun ram CreateUser --UserName yuyoung aliyun ram CreateLoginProfile --UserName yuyoung --Password Yuy0ung@666 aliyun ram AttachPolicyToUser --PolicyType System --PolicyName AdministratorAccess --UserName yuyoung
-
接下来就可以通过新创建的RAM用户进行登录了https://signin.aliyun.com/login.htm#/main,这里的用户格式为 username@company-alias,其中 username 就是刚刚创建的用户名,company-alias 可以通过下面的这个命令获取到:
aliyun ram GetAccountAlias
-
登陆:

-
密码为我们创建的密码:

-
阿里云会强制你绑定MFA设备,使用任意手机绑定即可:

-
绑定设备后即可成功接管控制台:

接下来对这个靶场案例进行分析:
这个环境的问题除了存在SSRF,还有另外两个问题:
- RAM角色权限过大,导致可以通过该角色的权限进行创建子用户以及给子用户授予高权限等操作
- 云数据未作访问加固,导致一旦目标存在SSRF或权限被获取,元数据就存在被获取的风险
针对第一个 RAM 角色权限过大的问题,主要还是需要使用者严格遵守权限最小化的原则,在为 RAM 角色赋予权限时,避免赋予过高的权限,只赋予自己所需要的权限,这样可以将影响程度降到最低
针对第二个问题,可以将实例上的元数据访问模式设置为加固模式,方法有两种:
-
1.在创建实例时,可以在「系统配置」的「高级选项」中将「实例元数据访问模式」设置为「仅加固模式」
-
2.在已经创建好的实例中,可以在阿里云 OpenAPI 中开启元数据强制使用 Token 访问,OpenAPI 地址:https://next.api.aliyun.com/api/Ecs/2014-05-26/ModifyInstanceMetadataOptions

-
配置后就无法SSRF访问了,提示403:

-
当然,如果实例权限被获取了,这种方法就不行了,可以这样获取元数据:
-
先获取token:
TOKEN=`curl -X PUT "http://100.100.100.200/latest/api/token" -H "X-aliyun-ecs-metadata-token-ttl-seconds: 21600"` -
再通过token获取元数据:
curl -H "X-aliyun-ecs-metadata-token: $TOKEN" http://100.100.100.200/latest/meta-data/
-
完事记得删除创建的账号:
aliyun ram DetachPolicyFromUser --PolicyType System --PolicyName AdministratorAccess --UserName yuyoung
aliyun ram DeleteUser --UserName yuyoung
还要记得把ak改回来:
aliyun configure --mode AK
最后,给出这个上面方法的几个前提:
- ECS 实例需要被授予 RAM 角色,不然访问临时凭证的元数据会返回 404
- RAM 角色需要具备 ram 访问控制的相关操作权限,例如创建用户、赋予权限等,不然临时秘钥会没有创建子用户的权限
在实战中,如果遇到了 ECS 实例被授予了 RAM 角色的情况,大多时候该角色都是不具备创建用户权限的,这时就没法通过创建子账号登录控制台的方式了,只能通过阿里云命令行工具去操作目标云服务了
我们在这里也可以总结书一些云上攻防相比传统内网攻防的不同:
- 云上攻防的常见问题是配置错误
- 云上攻防的权限维持主要方法是创建 RAM 高权限用户,而不是像传统攻防里那样有五花八门的权限维持方法
- 云上攻防的内网横向主要是在云服务厂商命令行或者控制台中进行横向,从这个云服务横向到另一个云服务,而不是像传统攻防那样有各种各样的内网横向手法
杂谈
记录一些属于云服务但是不好分类的的零碎知识与Tricks
AK特征整理
记录一下不同云服务对应AK的正则:
Amazon Web Services
亚马逊云计算服务 (Amazon Web Services, AWS) 的 Access Key 开头标识一般是 "AKIA"。
^AKIA[A-Za-z0-9]{16}$
- Access Key ID: 20个随机的大写字母和数字组成的字符,例如 AKHDNAPO86BSHKDIRYTE
- Secret Access Key ID: 40个随机的大小写字母组成的字符,例如 S836fh/J73yHSb64Ag3Rkdi/jaD6sPl6/antFtU(无法找回丢失的 Secret Access Key ID)。
Google Cloud Platform
Google Cloud Platform (GCP) 的 Access Key 开头标识一般是 "GOOG"。
^GOOG[\w\W]{10,30}$
- 服务账号的JSON文件中包含了Access Key和密钥的信息,其中Access Key为
client_email,其长度不固定,由字母、数字和特殊字符组成。 - 密钥(Key)的长度为256个字符,由字母、数字和特殊字符组成。
Microsoft Azure
Microsoft Azure 的 Access Key 开头标识一般是 "AZ"。
^AZ[A-Za-z0-9]{34,40}$
- Azure AD Application的Client ID通常用作Access Key,长度为36个字符,由字母和数字组成。
- 对于Azure AD Application的密钥(Secret),长度为44个字符,由字母、数字和特殊字符组成。
IBM Cloud
IBM 云 (IBM Cloud) 的 Access Key 开头标识一般是 "IBM"。
^IBM[A-Za-z0-9]{10,40}$
或者是以下规则:
[a-zA-Z0-9]{8}(-[a-zA-Z0-9]{4}){3}-[a-zA-Z0-9]{12}$
Oracle Cloud
Oracle云 (Oracle Cloud) 的 Access Key 开头标识一般是 "OCID"。
^OCID[A-Za-z0-9]{10,40}$
阿里云
阿里云 (Alibaba Cloud) 的 Access Key 开头标识一般是 "LTAI"。
^LTAI[A-Za-z0-9]{12,20}$
- Access Key ID长度为16-24个字符,由大写字母和数字组成。
- Access Key Secret长度为30个字符,由大写字母、小写字母和数字组成。
腾讯云
腾讯云 (Tencent Cloud) 的 Access Key 开头标识一般是 "AKID"。
^AKID[A-Za-z0-9]{13,20}$
- SecretId长度为17个字符,由字母和数字组成。
- SecretKey长度为40个字符,由字母和数字组成。
华为云
华为云 (Huawei Cloud) 的 Access Key 是20个随机大写字母和数字组成,较难用正则表达式匹配。
[A-Z0-9]{20}
百度云
百度云 (Baidu Cloud) 的 Access Key 开头标识一般是 "AK"。
^AK[A-Za-z0-9]{10,40}$
京东云
京东云 (JD Cloud) 的 Access Key 开头标识一般是 "JDC_"。
^JDC_[A-Z0-9]{28,32}
字节跳动火山引擎
字节跳动火山引擎 (Volcengine) 的 Access Key 开头标识一般是 "AKLT",长度小于256位。
^AKLT[a-zA-Z0-9-_]{0,252}
UCloud
UCloud (UCloud) 的 Access Key 开头标识一般是 "UC"
^UC[A-Za-z0-9]{10,40}$
青云
青云 (QingCloud) 的 Access Key 开头标识一般是 "QY"。
^QY[A-Za-z0-9]{10,40}$
金山云
金山云 (Kingsoft Cloud) 的 Access Key 开头标识一般是 "AKLT"。
^AKLT[a-zA-Z0-9-_]{16,28}
联通云
联通云 (China Unicom Cloud) 的 Access Key 开头标识一般是 "LTC"。
^LTC[A-Za-z0-9]{10,60}$
移动云
移动云 (China Mobile Cloud) 的 Access Key 开头标识一般是 "YD"。
^YD[A-Za-z0-9]{10,60}$
电信云
中国电信云 (China Telecom Cloud) 的 Access Key 开头标识一般是 "CTC"。
^CTC[A-Za-z0-9]{10,60}$
一云通
一云通 (YiYunTong Cloud) 的 Access Key 开头标识一般是 "YYT"。
^YYT[A-Za-z0-9]{10,60}$
用友云
用友云 (Yonyou Cloud) 的 Access Key 开头标识一般是 "YY"。
^YY[A-Za-z0-9]{10,40}$
南大通用云
南大通用云 (OUCDC) 的 Access Key 开头标识一般是 "CI"。
^CI[A-Za-z0-9]{10,40}$
G-Core Labs
G-Core Labs 的 Access Key 开头标识一般是 "gcore"
^gcore[A-Za-z0-9]{10,30}$

浙公网安备 33010602011771号