红队视角下的公有云基础组件安全
前言
“公有云是为广大用户、个人或企业提供的云基础设施。公有云就是第三方公有云供应商为用户提供可通过互联网访问的虚拟环境中的服务器空间。然后,用户可以通过购买云服务器、数据存储和其他与云相关的服务等公有云服务来访问这些服务器。虽然用户可通过互联网访问公有云,但数据将通过虚拟化与其他用户的数据隔离,以提高安全性。公有云供应商还主动确保其服务器不受漏洞影响,并使用最新的软件补丁进行更新。但最终还是由使用者负责数据在云中的使用,包括访问、身份验证、加密和应用程序配置。”
随着越来越多的企业将应用、存储上云,各大公有云提供了各种 IaaS、PaaS、SaaS 服务,针对公有云各组件的攻击面也伴随而生。公有云厂商在尽可能保证组件安全的前提下,由于各种基础配置还是由用户决定,因此仍然存在很多安全风险。
本文主要从红队视角讲述公有云基本服务中一些因配置问题产生的安全风险。
编者注:以下所有内容仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责。
目录
● 云存储
● 云计算
● 容器集群
● 中间件
云存储
至于为什么一上来就讲述云存储,是因为目前很多云厂商使用自己原生的云存储去操作其他基本组件,很多功能都是基于对象存储完成的,所以,首先讲述云存储的安全问题,为以下攻击面做准备。
在对象存储中,用户所上传的文件都是以对象形式存储在云端,以对象形式形式存在的文件不具备可执行权限,再加上提供无层次结构的分布式存储产品,为用户提供单价较低且快速可靠的数据存储方案,所以现在的大趋势下很多企业选择将自己所有的静态文件(图片、网站静态文件、视频等)搬迁至对象存储上,由于对象存储一般都是托管在第三方,企业在自身安全建设时往往会忽视掉这一点,殊不知不安全的配置,也会带来很多安全问题。
国内常见的几家云厂商的对象存储如下:
腾讯COS:
https://cloud.tencent.com/product/cos
阿里OSS:
https://www.aliyun.com/product/oss
百度BOS:
https://cloud.baidu.com/product/bos.html
华为OBS:
https://www.huaweicloud.com/product/obs.html
七牛Kodo:
https://www.qiniu.com/products/kodo
又拍云USS:
https://www.upyun.com/products/file-storage
访问控制
创建空间时,可设置为公开空间或私有空间。
●公开空间:可通过文件对象的 URL 直接访问。
●私有空间:文件对象的访问则必须获得拥有者的授权才能访问。
如果设置为公开空间,则任何知道URL链接的人都能访问,此类空间适合存放公共文件,如网站静态资源、用户头像等公开资源(理论上你的文件名设置得足够复杂,在一定程度上也能保证安全性,但还是不建议这样做),针对敏感文件,尽量还是选择私有空间,私有空间在访问时一般要加上签名信息才能访问。
目前大部分云厂商会提供类似https://bucket.s3-china-region.cloud.com/?ak=xxxx&sgin=xxxx&time=16xxxx的类似AWS S3 签名URL形式,或者直接兼容S3协议,以提供下载、上传、管理API,具体参数意义如下:
● AK用于控制用户权限
● Sign用于验证签名,一般的云厂商都会把AK、domain、URI、Query、Header等请求特征、身份特征以及时间戳拼接在一起,然后使用SK做为盐值进行hash,来生成最后的Sgin,用于校验此数据包是否合法。
● time是时间戳,用户标识此URL过期时间
上传风险
通过查阅相关文件,我们可以知道使用表单上传文件到 OSS的技术方案里,有三种实现方式:
1、在客户端通过JavaScript代码完成签名,然后通过表单直传数据到OSS。
2、在服务端完成签名,然后通过表单直传数据到OSS。
3、在服务端完成签名,并且服务端设置了上传后回调,然后通过表单直传数据到OSS。OSS回调完成后,再将应用服务器响应结果返回给客户端。
密钥泄露
在对象存储的SDK中,一般都会存在JavaScript的SDK,也就是支持用户前端上传的组件。
https://github.com/ali-sdk/ali-oss
一般来说,在安全的配置下,前端上传会使用子用户、或者临时密钥(STS token)的方式来进行,但是由于不严谨的开发,前端js文件、APK文件硬编码AK / SK的情况还是司空见惯,一般来说只需要在burpsuite里面搜索对应云AK的名字,例如AccessKey、SecretKey等。
拿到了AccessKey、SecretKey就可以实现对OSS的完全控制,常见的方法有利用官网提供的API或者开源工具等对OSS进行管理操作。
任意文件覆盖
在某些业务场景下,可能会存在如下流程:
1、首先结合时间戳生成一个随机文件名
2、通过此文件名信息在后端获取该文件的上传签名
3、最后通过PUT或者POST上传
这个时候,由于上传的路径是我们控制,所以我们可以通过修改签名路径的形式,来进⾏签名,从⽽去覆盖此存储桶下的任意⽂件:
我们可以看到已经成功上传了⼀个新⽂件覆盖原来的⽂件。
能达到⽂件覆盖的⽬的后,就可以对储存桶资⾥原有的资源进⾏修改,可能会带来XSS⻛险,严重还可能造成供应链投毒攻击。
1XSS风险
在文件覆写条件成立后,先假设一个场景,某企业主站里面的静态js文件均放在OSS的云储存配合CDN进行加速,现在已知js文件的路径和名称,那么我们就可以在原有js里插入一段恶意js代码进行文件覆盖,从而达到xss甚至长期信息窃取的风险。
2供应链投毒
在文件覆写条件成立后,先假设一个场景,某企业为软件提供商,为了节省服务器带宽,将软件/源码上传到OSS进行分发,因为配置不当正好存在任意文件覆盖,导致软件或源码中被插入恶意代码。
任意文件上传
部分公有云厂商默认配置了已存在的文件禁止覆盖,这种情况下文件覆盖是没办法了,但是可以控制文件的key进行任意文件上传。
一般来说国内各大云厂商的OSS都支持html解析,当OSS配置了企业域名后,再配合任意文件上传,也相当于控制了一个子域名的权限,可以用来XSS和钓鱼。
上传时将⽂件路径从upload更改为attack,获取此次上传的STS(Security Token Service),将拿到的STS带⼊上传,修改key(⽂件名),即可实现任意⽂件/任意⽬录上传。
STS Token
由于前端使用SDK上传,会减少很多前后端交互API的编写,所以很多开发总是会选择前端上传,所以云厂商开发了STS(Security Token Service)的模式,有关STS的介绍如下:
由于STS token是对针对API接口而不是大范围的云产品的,有的时候在存在AK、SK、STS都返回以后,上传有限制,只允许在特定目录下传文件的时候,不妨试一试带上STS访问ECS、SLB等其他同样支持STS的服务,对于AWS S3标准的STS,我们还可以通过BASE64解码来获取对应的权限。
PUT ACL接管存储桶
这是某云厂商关于PUT ACL的说明:
即然能覆盖原ACL,那就说明如果配置不当,就可能存在一定的安全问题。
如果是前端请求签名,并且前端上传的话,如果后端对路径没有做限制,我们就可以通过请求SDK获得根目录的写入权限,接着配合PUT ACL进行覆盖。
GET /get_put_sgin?uri=/ HTTP/1.1
Host: 192.168.20.31:80
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
详细文档参考:
https://cloud.tencent.com/document/product/436/7737来对根目录进行ACL的写入,但是要注意的是PUT bucket写入是一个覆盖操作,会覆盖原有业务的ACL导致业务无此bucket权限,导致业务中断,所以如果发现此问题不要贸然测试。
下载时产生的安全问题
对象存储为什么可以保证存储文件的安全?在私有读的存储桶里,读取任意文件都需要授权签名,签名过期后就无法读取,这样就会导致一张图片必须每次读的时候都去请求权限,在请求权限时,业务最常用的接口就是:
GET /download?uri=file HTTP/1.1
Host: 192.168.20.31
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
发送这个请求就会返回一个加参数的url,但是如果我们的url设置为空,例如这样。
GET /download?uri= HTTP/1.1
Host: 192.168.20.31
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
那么就会访问到对象存储的管理节点信息,从而获取整个桶里的文件信息,再拿得到的key去构造访问链接,从而造成储存桶的文件遍历。
MinIO的安全问题
目前可选的资源服务器挺多,比如FastDFS,MinIO,AWS/S3等,云服务器供应商也提供资源服务器OSS租用,某些企业为了数据安全的考虑,可能会选择用MinIO在企业内部自建一个OSS服务。
数据泄露
简单说,就是如果你想要提供永久性的资源下载链接,就需要把Bucket(桶)的BP设置为Read&Write。
当你用 http://minio_out_url/bucket_path/ 访问时,会得到一个超大的XML,里面就会出现这样的情况,其中key字段就是文件名。
MinIO的桶有一个listObjects的功能,默认最多1000条记录,这就意味着如果你打开永久下载链接模式,那么任何人可以通过桶路径来获取你保存的所有资源的信息,从而造成桶遍历。
CVE-2021-21287
参见PHITHON的文章,这里就不多介绍了。
云计算
云服务器
目前,基本上所有公有云都支持使用自定义镜像,并且镜像导入的方式比较统一,基本上都使用由对象存储导入,输入 oss-key 地址,然后公有云服务进行下载导入。所以,可以考虑劫持用于导入镜像的 oss-bucket,直接污染镜像,实现“供应链攻击”。
此外,一些公有云还支持由其他服务器创建的镜像,新建的服务器会与原服务器完全相同。从攻击者视角来看,相同系统环境以及应用意味着相同的攻击方式。
批量计算
一些公有云厂商都提供了批量计算的服务,该服务为 SaaS 服务,只需配置参数,即可调用服务器资源进行计算,大多云厂商目前都选择使用 oss 去控制输入以及输出参数。从攻击者视角来看,同以上所说的服务镜像一样,若该 oss-bucket 可控,则可直接控制批量计算的服务命令等。
容器集群
不同公有云在容器集群服务方面出入较大:
阿里云针对不同的需求提供了 5 种不同版本的集群:ACK 托管版、ACK 专有版、ASK 集群、ACK 边缘托管版、注册集群等;
腾讯云针对资源类型分为TKE容器集群、EKS弹性容器集群与边缘集群;
华为云区分为容器引擎CCE 与实例CCI。
每个厂商的容器服务不同,所以从攻击者视角来看,攻击利用某一厂商的容器服务需对其进行特殊处理。
容器集群服务
敏感目录被挂载
某厂商在创建容器集群服务时提供了一个接口,可以修改容器存储路径。
若此处被运维人员修改,如改为 /root,那新建容器另外的运维人员挂在了 /root 进容器中,则该节点的所有容器都会被控制。
复现过程
创建集群时修改容器目录为 /docker
开启外网访问
新建 pod,并挂载 /docker 目录
进入 pod 内部 /mount/docker 目录,可控制所有容器。
所有节点使用相同 kube-config
所有的节点使用了相同的 kube-config,皆为 k8s master 权限,若有容器存在逃逸问题,则在任意节点都可控制整个 k8s 集群。
该云厂商 k8s 配置自动解决了组件未授权等问题,但是 docker 用户逃逸问题未能避免,若容器发生逃逸或 /root/.kube/config 泄露,则可控制整个容器集群。
以下演示挂载 /root 导致整个集群被控制的过程:
新建pod,挂载 root
获取 kube-config
上传 kubectl,控制整个集群
容器镜像服务
所有提供容器服务的公有云皆提供了容器镜像服务。
存储劫持
有些云厂商为了方便操作,直接使用对象存储,创建镜像仓库时会自动创建 Bucket,镜像的资源都会储存在对象存储中。此时镜像服务相当于一个中间件,封装了 sdk,对镜像的所有操作相当于调用 sdk 去操作 oss。
● Bucket 默认为私有读写,若配置为公有读写/公有读,则也可对镜像仓库进行读取/控制。
● 若控制了 Bucket,则相当于控制了镜像仓库,可通过设置回源造成镜像仓库控制服务器 SSRF。
Token 泄露
大多数云厂商使用两种认证方式登录仓库,永久访问凭证或者临时访问凭证。
若访问凭证泄露,则可对仓库进行增删改查,完成“供应链攻击”。
中间件
是为应用提供通用服务和功能的软件。数据管理、应用服务、消息传递、身份验证和 API 管理通常都要通过中间件。我们这里中间件只说API网关和消息队列的内容。
消息队列
当前主流的消息队列有RocketMQ、Kafka、Pulsar、RabbitMQ等。
● RocketMQ是阿里巴巴研发的一款低延迟、高可靠、可伸缩、易于使用的消息中间件。
● Kafka是由 LinkedIn 公司开发的一个高吞吐量的分布式消息系统, 开发它的目标是为处理实时数据提供一个统一、高通量、低等待的平台。
● Pulsar是由Yahoo开发的 Pub-Sub 模式的分布式消息平台,在 2016 年开源,并于2018年9月毕业成为 Apache 基金会的顶级项目。
● RabbitMQ是一个基于高级消息队列协议实现的消息系统,其服务器端用 Erlang 语言编写,支持多种客户端,如 Python、.NET、PHP、 Java、JMS 等。
某些云厂商在启动消费者订阅普通消息时需要设置相关参数其中包括AccessKey等云身份验证的参数需要注意防止泄露。
某云厂商的一款应用中在准备配置阶段明确说明了使用Log4j,这里需要注意下。
角色密钥
有些产品的消息队列需要配置角色,每个角色的建立都会有密钥的生成,这个密钥是作为管理员身份的认证,如果角色的密钥泄露那么绑定这个角色队列数据存在泄露的风险。
消息队列开通需要进行一些配置新建集群会显示接入点
在其中新建命名空间,并新建Topic
针对空间进行权限配置,需要提前新建一个角色
角色建立时会配置权限
消息队列中每个集群可以建立多个命令空间,接入地址可以选择开放公网,但是打开之后就不能再关闭
每个空间需要绑定角色,并且多个空间可以绑定一个角色,如果这一个角色的密钥泄露那所有空间的队列数据可读
API网关
API 网关将各系统对外提供服务的微服务聚合起来,所有要调用这些服务的请求都需要通过 API 网关进行,基于这种方式网关可以对API进行统一管控,例如:认证、鉴权、流量控制、协议转换、 监控等等。
鉴权
API的鉴权设置不当的话会让任意用户调用相关API
API创建的时候,会有鉴权的类型选择,如果不选默认为免认证,意味着谁都可以调用
鉴权选择应用认证,这个涉及到调用API的凭证,密钥类似于登录密码,密钥泄露他人可以任意调用API
应用密钥也是一种签名方式,可以对请求内容签名计算
鉴权为密钥对是只有使用正确密钥发起的访问才能够通过API网关的校验,不携带或者错误都不能通过鉴权,这种方式是历史功能官方会提示不建议使用,密钥的泄露一样会造成任意调用
云原生网关
某厂商有个产品叫云原生网关是基于Kong网关的,我们可以借助这个达到隐藏ip的目的。
利用的前提是需要开通云原生网关(目前白嫖)、并且有一台和网关属于同一个地区、同一VPC下的云服务器
通过配置安全组添加规则放通VPC的网段10.0.0.0/8 、192.168.0.0/16、172.16.0.0/12三个VPC内网网段
访问创建的云原生网关可以看到网关的详细信息包括Kong 管理控制台的地址和管理员账号、密码
第一次进入需要启用连接,使用默认的就好
在左侧进入服务列表并新建一个服务,创建时在url中填写云服务器在VPC的地址
创建成功点击服务进入详情创建一个路由,在Paths中填写/,回车确定,然后点击最下面的提交
cs马配置为kong提供的公网代理地址,需要使用无阶段的马
目标成功通过kong上线
总结
根据以上分析,本文涉及到的公有云基础组件安全风险总结如下:
-
从云存储角度看,包括访问控制风险,文件上传中的密钥泄露、任意文件覆盖风险,STS Token的未授权访问风险,PUT ACL接管存储桶配置不当,以及文件下载、MinIO等资源服务器也容易出现安全问题。
-
从云计算角度看,云服务器易出现镜像污染和因服务器环境相同带来连环攻击的风险;批量计算服务命令遭恶意控制等。
-
从容器集群角度看,容器集群服务易发生敏感目录被挂载的情况;容器镜像服务存在存储劫持、Token泄露等风险。
-
从中间件角度看,消息队列可能存在角色密钥、云身份验证参数泄露等问题;API网关存在鉴权配置不当引起恶意调用、密钥泄露风险,云原生网关权限泄露等问题。