AWS - Nitro Enum

支持 HackTricks

基本信息

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 安装

按照文档中的所有说明进行操作。然而,以下是最重要的部分:

# 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 镜像,如:

# 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-img>:<tag> --output-file nitro-img.eif

如你所见,Nitro Enclave 镜像使用扩展名 eif(Enclave Image File)。

输出将类似于:

Using the locally available Docker image...
Enclave Image successfully created.
{
"Measurements": {
"HashAlgorithm": "Sha384 { ... }",
"PCR0": "e199261541a944a93129a52a8909d29435dd89e31299b59c371158fc9ab3017d9c450b0a580a487e330b4ac691943284",
"PCR1": "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f",
"PCR2": "2e1fca1dbb84622ec141557dfa971b4f8ea2127031b264136a20278c43d1bba6c75fea286cd4de9f00450b6a8db0e6d3"
}
}

运行一个镜像

根据文档,为了运行一个enclave镜像,你需要分配至少是eif文件大小4倍的内存。可以在文件中配置默认资源给它

/etc/nitro_enclaves/allocator.yaml

请务必记住,您还需要为父 EC2 实例保留一些资源

在了解了要分配给镜像的资源并修改了配置文件后,可以运行一个 enclave 镜像:

# 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 镜像列表:

nitro-cli describe-enclaves

在运行的enclave镜像中无法获取shell,因为这是enclave的主要目的,但是,如果你使用了参数**--debug-mode,可以通过以下方式获取它的stdout**:

ENCLAVE_ID=$(nitro-cli describe-enclaves | jq -r ".[0].EnclaveID")
nitro-cli console --enclave-id ${ENCLAVE_ID}

Terminate Enclaves

如果攻击者默认情况下攻陷了一个EC2实例,他将无法在其中获取shell,但他将能够终止它们,使用以下命令:

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

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"
}
}
]

请注意,从主机上无法知道 CID 是否暴露了任何端口!除非使用一些vsock 端口扫描器,如 https://github.com/carlospolop/Vsock-scanner

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}")

</details>
```bash
# Using socat
socat VSOCK-LISTEN:<port>,fork EXEC:"echo Hello from server!"

Vsock Client

示例:

Last updated