ServerLess Aws Lambda 攻击与横向方法研究

前言
1、这篇文章讲了什么?
文本围绕三个问题
1、lambda 会遇到什么攻击场景
2、什么情况下,在 lambda 中读取到的 env 环境变量密钥可以让我们接管服务器甚至整个账号
3、什么情况下,可以通过 lambda 权限去横向到其他的 EC2 服务器
本文会对这三个问题进行解答,并且进行演示
2、什么是 ServerLess 和 Lambda
Serverless,即无服务器计算。然而 Serverless 不是不再需要服务器,而是公司或开发者不用过多考虑服务器的问题,计算资源仅作为一种服务而不再以物理硬件的形式出现。

为什么使用 ServerLess
Serverless 免除公司和开发者对服务器维护的麻烦,因此也不用考虑 DevOps 了。公司和开发者只需关注应用的开发和运维即可,因此 Serverless 可以在更大程度上节约运维的成本。
Serverless 的优势
可用性冗余,以便单个机器故障不会导致服务中断
冗余副本的地理分布,以便在发生灾难时保留服务
负载平衡和请求路由以有效利用资源
响应负载变化进行自动缩放以扩展或缩小系统
监控以确保服务仍然运行良好
记录以记录调试或性能调整所需的消息
系统升级,包括安全修补
迁移到新实例时可用
选自阿里云
https://www.alibabacloud.com/zh/knowledge/what-is-serverless
一、场景搭建与实践
https://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/create/function
1、创建一个 lambda 函数

这里都是用默认的设置

并且我们对执行的角色也是用默认的选项

在高级设置中,我们也保持默认
2、为 lambda 函数添加触发器
在编写函数代码之前,我们需要添加触发器

为了演示方便,我们不去考虑这个函数在业务中的具体作用,只需在意这个函数在什么时候触发即可首先我们创建一个 S3 存储桶

并且我们在刚刚创建的函数添加触发器,并且选择这个存储桶,触发的事件类型也选择所有对象创建事件


在我们开始编写函数前,我们需要知道,在 S3 上传对象时,所获取到的内容是什么样子的上传一个文件,触发一下日志

随后在 cloud watch 中就可以看到上传的日志

这里可以看到 object 中的 key 是上传的文件名,那假设函数获取的文件名并且当成命令执行,那么在上传文件时如果未对文件进行重命名就会造成问题,或者更加直接一些,我们直接获取文件的内容,将内容当做命令执行,或者写一个 flask 或者 django 的服务来接收参数然后执行命令
这里看上去会比较鸡肋,因为毕竟太刻意了,黑盒模式下也不太好遇上,这里的举例只做研究使用
我们将这里的 Json 数据取出来,然后丢到 lambda 测试,这样更加方便


这里我们主要关注这个 event,对 event 的数据进行处理
这样可以单独把文件名取出来

开始对这个文件名进行处理,直接使用 Split 函数对文件名进行.号分割,取下标值即可取到文件名
为了方便测试 手动把测试数据的 KEY 改为 whoami.jpeg

点击 Test 函数,查看返回结果

3、执行命令
3.1、反弹 shell
那么此时尝试反弹 Shell,看看是否能弹回来
代码需要改成下面这样
为什么要用 rsplit 而不用 split 呢?因为只需要取最后一个.点开始分割,如果使用 split,会把 IP 地址也进行分割
将这个代码更新到 lambda 函数中,随后运行 Test

NC 监听发现,这里会显示有连接过来,但是会超时,导致连不上,我一开始以为是国内服务器的问题,换了一台香港服务器也还是如此
既然反弹 Shell 失败的话,我们先暂且不去研究到底是为什么导致无法连接,那么能不能读 env 信息呢?答案是可以的
3.2、读取 env 信息
用 DNSLOG 外带平台,或者 NC 监听都行
https://app.interactsh.com/#/
这里使用服务器来 NC 监听,然后使用 curl 来进行请求

从图片中可以看到,将 env 信息带了出来,那么此时有 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY,可以进行利用吗?
首先我们看一这个 Key 能做一些什么?
3.2.1、黑盒盲猜 Key 的权限
这里肯定会遇到一个问题,将 ID 和 KEY 配置到 aws cli 中会出现下面的情况

An error occurred (AuthFailure) when calling the DescribeInstances operation: AWS was not able to validate the provided access credentials
这里提示我们,AWS 无法验证所提供的的凭证,那么是写错了吗?其实还需要提供上面的 token,如何添加?
加上 aws_session_token = xxxx

在执行列 EC2 的命令,就会提示没有权限
但是这里有这么多的 API,怎么知道这个 KEY 有什么权限呢?这就需要切换到白盒的方式,因为创建 lambda 函数的时候,所有的配置都是用的默认的,这个时候,只需要确定默认配置创建的 IAM 给的权限是多少即可
来到 IAM,查看这个系统创建的角色有哪些权限

点击策略名称

进去之后可以发现,只有三个权限
1、CreateLogGroup-创建日志组
https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
2、CreateLogStream-创建日志流
https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html
3、PutLogEvents-将日志事件上传到指定的日志流
https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html


二、🤔提出问题
那么至此,我们需要考虑两个问题
1、在什么情况下,这里的 IAM 密钥,能让我们控制 EC2 服务器,甚至接管整个账号?
2、在 lambda 函数中,就算是打穿了,那也是在云厂商提供的环境中,与企业的服务器还是有隔离的,那么什么情况下,会影响到企业的服务器?,也就是我们如何横向去攻击其他的服务器?
三、什么情况下,读取到的 env 密钥可以让我们接管服务器甚至整个账号?
从这里的 IAM 来看,env 里面的密钥权限肯定来自于我们创建 lambda 函数时,让我们选择是自动新建角色,还是使用现有角色这里

这里选择使用现有的角色,然后去 IAM 创建一个

这里选择 Lambda,因为是给 Lambda 这个服务使用的

这里可以看到这一条策略
Provides full access to Amazon EC2 via the AWS Management Console.
也就代表着可以通过控制台访问所有的 EC2 服务

创建完成后,分配给 Lambda
Tips
这里的可信实体一定要是 AWS 服务:lambda,不然在 lambda 函数中是选不到这个角色的

随后回到 lambda,点击一下刷新,就可以看到新建的角色了

创建函数,再尝试把 env 信息读出来

虽然这个函数执行失败了,但是收到了请求,无伤大雅,现在尝试对这里的 AK/KEY 进行利用
在此之前,使用尊贵的 AWS12 月免费账户启动一个 EC2


写入刚刚获取到的 AK/ID 还有 token
列出账号下的 EC2

这里返回为空,可能有人会认为是不是执行失败了,其实是成功了,证明我们获取到的 AK/ID 是有 EC2 权限的,因为如果执行失败的话会返回 AccessDenid,那么我们刚刚启动了一个 EC2,但是这里不显示是为什么呢?这就是 AWS 地区的问题了,使用下面的命令,换一个地区尝试一下

这里的地区目前是显示在首尔,但是我们的服务器是在弗吉尼亚北部 us-east-1,切换一下地区即可

再执行列出 EC2 的命令,就可以了

现在已经是有权限的,那么能否在 EC2 中执行命令呢?
这里的命令,我就照搬 TeamsSix 的文章了: https://zone.huoxian.cn/d/1022-aws-ec2
1、列出目标实例的 ID

2、在指定的 EC2 上执行命令

但是此时会提示我们并没有权限执行命令,会 IAM 看一下

我们这里使用的是 SSM,所以需要附加 SSM 的权限,也就是 Aws Systems Manager
https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/what-is-systems-manager.html
但是已经不重要了,我们可以现在对 EC2 进行增加,停止,删除了,用下面的命令可以停止指定的 EC2

此时可以看到我们的 EC2 已经被停止了

那么就是想执行命令,能执行吗?答案是可以的,只需要在角色中添加 SSM 即可

将这个权限附加到 UzJuFullEC2 的角色中,然后需要重新获取 Token,因为这里改了之后,在 env 中的 AK 和 KEY 就变了

然后我们再执行命令会发现提示无效,原因是因为服务器的 agent 未在线

这个时候就需要去 EC2 中添加 IAM
右键 EC2 选择安全-修改 IAM



然后再执行命令
获取输出

四、什么情况下,可以通过获取 lambda 权限横向到其他服务器?
这里就要说到,在创建 Lambda 函数的时候,有一个高级选项,可以分配 VPC

创建成功后,现在 lambda 函数就与 EC2 服务器在同一个 VPC 中


随后首先使用证书登录到服务器

验证一下现在 lambda 函数是否能访问到这个 EC2,只需要在这个 EC2 中开启一个 HTTP 服务即可
PS
这里有个比较小丑的事情。。。

我在 EC2 中开启监听,然后 lambda 访问 EC2 的内网地址,按道理来说应该是能访问到的,可以把 VPC 理解为局域网,但是就是访问不到,然后 lambda 函数执行超时,气急败坏上了 fscan

后来才发现,是因为 EC2 的安全组只放了 22。。所以才访问不到的,现在改成全开的情况

放通安全组之后,lambda 可以成功访问到我的 EC2 了

这里插一个小插曲,在上面我们没解决公网没办法反弹 shell 的问题,那么内网可以吗?尝试了一下,还是不可以

跟公网一个情况,会自动断开,那么回到正题

把 lambda 函数的 VPC 取消,那么还能访问吗?

可以看到,如果将 VPC 取消之后,lambda 函数就没有办法访问 EC2
现在再考虑一个问题,能不能反向查找,现在的情况是,我们控制了 EC2,可以用 fscan 等扫描工具来判断内网存在哪些机器,那么能不能反过来,在 lambda 函数上装一个 kscan 来判断 VPC 中有多少个 EC2
这里不能直接存,因为是只读的
这里的图片是 fscan,因为边做边写的时候图片没换,就懒得重新弄了
为什么不用 fscan,因为没有 root 权限,icmp 没权限

但是可以存在 tmp 目录下,用 curl -小写的 o


下载成功,给一下权限
这里直接运行是不行的,需要给权限

然后再次运行
这里执行的时候有个小 Tips

这里会一直转圈圈,因为这里有个超时限制,正常是 3 秒,如果设置是默认 3 秒的话,这里就会执行失败,因为等待太久了,在扫描,所以需要配置一下超时时间,我这里配置成了 10 分钟


现在可以看到里面有数据了,cat 看一下内容

可以看到这里所探测到的就是我们创建的 EC2

然后可以利用 CURL 带出来

五、总结
1、lambda 的攻击方式
与常见的漏洞利用方式类似,对外部输入并不可控造成的
2、什么情况下获取的 env 密钥可以接管服务器或者账号?
lambda 必须拥有自定义的 IAM 角色
3、什么情况下获取到的 env 密钥可以执行命令?
lambda 的 IAM 角色必须拥有
4、什么情况下可以通过 lambda 去横向到其他服务器?
lambda 必须绑定 VPC
即在同一个 VPC 内网中即可扫描探测到存活的服务器内网地址
5、云安全靶场-TerraformGoat
https://github.com/HuoCorp/TerraformGoat

文章首发于火线 Zone:https://zone.huoxian.cn/作者:UzJu
评论