基本信息
AWS Nitro 是一套创新技术 ,构成了 AWS EC2 实例的基础平台。由 Amazon 推出以增强安全性、性能和可靠性 ,Nitro 利用定制的硬件组件和轻量级的 hypervisor 。它将传统虚拟化功能的大部分抽象到专用硬件和软件中,最小化攻击面 并提高资源效率。通过卸载虚拟化功能,Nitro 使 EC2 实例能够提供接近裸机的性能 ,这对资源密集型应用特别有利。此外,Nitro 安全芯片专门确保硬件和固件的安全性 ,进一步巩固其强大的架构。
Nitro Enclaves
AWS Nitro Enclaves 提供一个安全的、隔离的计算环境 ,位于 Amazon EC2 实例内,专为处理高度敏感的数据而设计。利用 AWS Nitro 系统,这些 enclaves 确保了强大的隔离和安全性 ,非常适合处理机密信息 ,如 PII 或财务记录。它们具有极简环境,显著降低了数据暴露的风险。此外,Nitro Enclaves 支持加密认证,允许用户验证只有授权代码在运行,这对于保持严格的合规性和数据保护标准至关重要。
Nitro Enclave 镜像从 EC2 实例内部运行 ,你无法从 AWS web 控制台看到 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
枚举 Enclaves
如果你攻破了一个 EC2 主机,可以使用以下命令获取正在运行的 enclave 镜像列表:
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}
Terminate Enclaves
如果攻击者默认情况下攻陷了一个EC2实例,他将无法在其中获取shell,但他将能够终止它们 ,使用以下命令:
Copy nitro-cli terminate-enclave --enclave-id ${ENCLAVE_ID}
Vsocks
与运行中的enclave 镜像通信的唯一方式是使用vsocks 。
Virtual Socket (vsock) 是 Linux 中专门设计用于促进虚拟机(VMs )与其hypervisors 之间或虚拟机之间 通信的套接字家族。Vsock 使得在不依赖主机网络堆栈的情况下实现高效的双向通信 成为可能。这使得即使没有网络配置,虚拟机也可以通信,使用 32 位上下文 ID (CID) 和端口号 来识别和管理连接。Vsock API 支持流和数据报套接字类型,类似于 TCP 和 UDP,为虚拟环境中的用户级应用程序提供了多功能工具。
因此,vsock 地址看起来像这样:<CID>:<Port>
要查找运行中的 enclave 镜像的 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 Server/Listener
这里有几个示例:
Simple Python Listener```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 Client
示例: