基本信息
AWS Nitro 是一套 创新技术 ,构成了 AWS EC2 实例的基础平台。由亚马逊推出以 增强安全性、性能和可靠性 ,Nitro 利用定制的 硬件组件和轻量级虚拟机监控程序 。它将传统虚拟化功能抽象到专用硬件和软件上,最小化攻击面 并提高资源效率。通过卸载虚拟化功能,Nitro 使 EC2 实例能够提供 接近裸金属的性能 ,这对资源密集型应用特别有利。此外,Nitro 安全芯片专门确保 硬件和固件的安全性 ,进一步巩固其强大的架构。
Nitro Enclaves
AWS Nitro Enclaves 提供一个安全的、隔离的计算环境,位于 Amazon EC2 实例内 ,专门设计用于处理高度敏感的数据。利用 AWS Nitro 系统,这些隔离区确保强大的 隔离和安全性 ,非常适合 处理机密信息 ,如个人身份信息或财务记录。它们具有极简的环境,显著降低数据暴露的风险。此外,Nitro Enclaves 支持加密证明,允许用户验证只有授权代码在运行,这对维护严格的合规性和数据保护标准至关重要。
Nitro Enclave 镜像是 从 EC2 实例内部运行的 ,您无法从 AWS 网络控制台查看 EC2 实例是否在运行 Nitro Enclave 镜像。
Nitro Enclave CLI 安装
按照 文档中的所有说明 。然而,以下是最重要的几点:
Copy # Install tools
sudo amazon-linux-extras install aws-nitro-enclaves-cli -y
sudo yum install aws-nitro-enclaves-cli-devel -y
# Config perms
sudo usermod -aG ne $USER
sudo usermod -aG docker $USER
# Check installation
nitro-cli --version
# Start and enable the Nitro Enclaves allocator service.
sudo systemctl start nitro-enclaves-allocator.service && sudo systemctl enable nitro-enclaves-allocator.service
Nitro Enclave Images
您可以在 Nitro Enclave 中运行的镜像基于 docker 镜像,因此您可以从 docker 镜像创建您的 Nitro Enclave 镜像,例如:
Copy # You need to have the docker image accesible in your running local registry
# Or indicate the full docker image URL to access the image
nitro-cli build-enclave --docker-uri < docker-im g > : < ta g > --output-file nitro-img.eif
如您所见,Nitro Enclave 镜像使用扩展名 eif
(Enclave Image File)。
输出将类似于:
Copy Using the locally available Docker image...
Enclave Image successfully created.
{
"Measurements": {
"HashAlgorithm": "Sha384 { ... }",
"PCR0": "e199261541a944a93129a52a8909d29435dd89e31299b59c371158fc9ab3017d9c450b0a580a487e330b4ac691943284",
"PCR1": "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f",
"PCR2": "2e1fca1dbb84622ec141557dfa971b4f8ea2127031b264136a20278c43d1bba6c75fea286cd4de9f00450b6a8db0e6d3"
}
}
运行映像
根据 文档 ,为了运行一个 enclave 映像,您需要分配 至少是 eif
文件大小的 4 倍的内存 。可以在文件中配置要分配给它的默认资源。
Copy /etc/nitro_enclaves/allocator.yaml
始终记住,您还需要为父 EC2 实例保留一些资源 !
在知道要分配给映像的资源并且甚至修改了配置文件后,可以使用以下命令运行一个 enclave 映像:
Copy # Restart the service so the new default values apply
sudo systemctl start nitro-enclaves-allocator.service && sudo systemctl enable nitro-enclaves-allocator.service
# Indicate the CPUs and memory to give
nitro-cli run-enclave --cpu-count 2 --memory 3072 --eif-path hello.eif --debug-mode --enclave-cid 16
枚举隔离区
如果您攻陷了一个 EC2 主机,可以使用以下命令获取正在运行的隔离区映像列表:
Copy nitro-cli describe-enclaves
不可能在运行的 enclave 镜像内获取 shell,因为这正是 enclave 的主要目的。然而,如果您使用参数 --debug-mode
,则可以通过以下方式获取其 stdout :
Copy ENCLAVE_ID = $( nitro-cli describe-enclaves | jq -r ".[0].EnclaveID" )
nitro-cli console --enclave-id ${ENCLAVE_ID}
终止隔离区
如果攻击者通过默认方式攻陷一个 EC2 实例,他将无法在其中获得 shell,但他将能够通过以下方式终止它们 :
Copy nitro-cli terminate-enclave --enclave-id ${ENCLAVE_ID}
Vsocks
与运行图像的 enclave 进行通信的唯一方式是使用 vsocks 。
虚拟套接字 (vsock) 是 Linux 中的一种套接字系列,专门设计用于促进虚拟机 (VMs ) 与其 hypervisors 之间,或虚拟机 之间 的 通信 。Vsock 使得高效的 双向通信 成为可能,而无需依赖主机的网络堆栈。这使得虚拟机即使在没有网络配置的情况下也能进行通信,使用 32 位上下文 ID (CID) 和端口号 来识别和管理连接。vsock API 支持流和数据报套接字类型,类似于 TCP 和 UDP,为虚拟环境中的用户级应用程序提供了多功能的工具。
因此,vsock 地址看起来像这样:<CID>:<Port>
要找到运行图像的 CIDs ,您可以执行以下命令并获取 EnclaveCID
:
Copy nitro-cli describe-enclaves
[
{
"EnclaveName" : "secure-channel-example" ,
"EnclaveID" : "i-0bc274f83ade02a62-enc18ef3d09c886748" ,
"ProcessID" : 10131,
"EnclaveCID" : 16,
"NumberOfCPUs" : 2,
"CPUIDs" : [
1,
3
],
"MemoryMiB" : 1024,
"State" : "RUNNING" ,
"Flags" : "DEBUG_MODE" ,
"Measurements" : {
"HashAlgorithm" : "Sha384 { ... }" ,
"PCR0" : "e199261541a944a93129a52a8909d29435dd89e31299b59c371158fc9ab3017d9c450b0a580a487e330b4ac691943284" ,
"PCR1" : "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f" ,
"PCR2" : "2e1fca1dbb84622ec141557dfa971b4f8ea2127031b264136a20278c43d1bba6c75fea286cd4de9f00450b6a8db0e6d3"
}
}
]
Vsock 服务器/监听器
这里有几个示例:
简单的 Python 监听器```python #!/usr/bin/env python3
From
https://medium.com/@F.DL/understanding-vsock-684016cf0eb0
import socket
CID = socket.VMADDR_CID_HOST PORT = 9999
s = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) s.bind((CID, PORT)) s.listen() (conn, (remote_cid, remote_port)) = s.accept()
print(f"Connection opened by cid={remote_cid} port={remote_port}")
while True: buf = conn.recv(64) if not buf: break
print(f"Received bytes: {buf}")
Copy </details>
```bash
# Using socat
socat VSOCK-LISTEN:<port>,fork EXEC:"echo Hello from server!"
Vsock 客户端
示例: