# Detecting Compromised Cloud Credentials

> 通过分析异常 API 活动、不可能旅行模式、未授权资源配置以及凭据滥用指标，使用 GuardDuty、Defender for Identity 和 SCC 事件威胁检测，检测 AWS、Azure 和 GCP 中被盗用的云凭据。

- Skill: `killvxk/detecting-compromised-cloud-credentials` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add killvxk/detecting-compromised-cloud-credentials`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/detecting-compromised-cloud-credentials/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/detecting-compromised-cloud-credentials

---


# 检测被入侵的云凭据

## 适用场景

- 调查来自陌生位置的异常云 API 活动告警时
- 为跨云环境的凭据窃取和滥用构建检测规则时
- 响应云提供商发出的凭据泄露通知时
- 监控针对云身份的凭据填充（Credential Stuffing）或暴力破解攻击时
- 在初始检测后评估凭据入侵的影响范围时

**不适用于**：防止凭据入侵（使用 MFA、凭据轮换和密钥管理）、检测应用层级的凭据窃取（使用应用安全监控），或检测终端凭据收集（使用 EDR 工具）。

## 前置条件

- 跨所有账户和区域启用的 AWS GuardDuty
- 配置 Azure Defender for Identity 和 Entra ID Protection
- 启用事件威胁检测的 GCP Security Command Center
- 集中归集 CloudTrail、Azure Activity Log 和 GCP Audit Log 用于分析
- 配置 SIEM 集成，用于跨云关联凭据滥用指标
- 已知恶意 IP 段的威胁情报订阅源

## 工作流程

### 步骤 1：在 AWS 中检测凭据入侵指标

监控表示凭据滥用的 GuardDuty 发现和 CloudTrail 异常。

```bash
# 列出 GuardDuty 中与凭据相关的发现
aws guardduty list-findings \
  --detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) \
  --finding-criteria '{
    "Criterion": {
      "type": {
        "Eq": [
          "UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS",
          "UnauthorizedAccess:IAMUser/MaliciousIPCaller",
          "UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom",
          "UnauthorizedAccess:IAMUser/TorIPCaller",
          "UnauthorizedAccess:IAMUser/ConsoleLoginSuccess.B",
          "Recon:IAMUser/MaliciousIPCaller",
          "Recon:IAMUser/MaliciousIPCaller.Custom",
          "InitialAccess:IAMUser/AnomalousBehavior",
          "CredentialAccess:IAMUser/AnomalousBehavior",
          "Persistence:IAMUser/AnomalousBehavior"
        ]
      },
      "service.archived": {"Eq": ["false"]}
    }
  }' --output json

# 检查来自新位置的控制台登录
aws logs start-query \
  --log-group-name cloudtrail-logs \
  --start-time $(date -d "7 days ago" +%s) \
  --end-time $(date +%s) \
  --query-string '
    fields @timestamp, userIdentity.userName, sourceIPAddress, responseElements.ConsoleLogin
    | filter eventName = "ConsoleLogin"
    | filter responseElements.ConsoleLogin = "Success"
    | stats count() by userIdentity.userName, sourceIPAddress
    | sort count desc
  '

# 检测不可能旅行（同一用户在短时间内从地理位置相距较远的 IP 访问）
aws logs start-query \
  --log-group-name cloudtrail-logs \
  --start-time $(date -d "24 hours ago" +%s) \
  --end-time $(date +%s) \
  --query-string '
    fields @timestamp, userIdentity.arn, sourceIPAddress, eventName
    | filter userIdentity.type = "IAMUser"
    | stats earliest(@timestamp) as first_seen, latest(@timestamp) as last_seen,
            count_distinct(sourceIPAddress) as unique_ips by userIdentity.arn
    | filter unique_ips > 3
  '
```

### 步骤 2：在 Azure 中检测凭据滥用

监控 Entra ID 登录日志和 Defender for Identity 告警，以发现被入侵的凭据。

```bash
# 检查高风险登录
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=riskLevelDuringSignIn ne 'none' and createdDateTime ge 2026-02-16T00:00:00Z&\$top=50" \
  --query "value[*].{User:userPrincipalName,Risk:riskLevelDuringSignIn,IP:ipAddress,Location:location.city,App:appDisplayName,Status:status.errorCode}" \
  -o table

# 检查来自匿名或 Tor IP 的登录
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=riskEventTypes_v2/any(r:r eq 'anonymizedIPAddress') and createdDateTime ge 2026-02-22T00:00:00Z" \
  --query "value[*].{User:userPrincipalName,IP:ipAddress,Location:location.city}" \
  -o table

# 列出被 Identity Protection 标记为已入侵的用户
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/identityProtection/riskyUsers?\$filter=riskLevel eq 'high'" \
  --query "value[*].{User:userPrincipalName,RiskLevel:riskLevel,RiskState:riskState,LastDetected:riskLastUpdatedDateTime}" \
  -o table

# 检查可疑的应用授权同意
az rest --method GET \
  --url "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDisplayName eq 'Consent to application' and activityDateTime ge 2026-02-16T00:00:00Z" \
  --query "value[*].{Activity:activityDisplayName,User:initiatedBy.user.userPrincipalName,App:targetResources[0].displayName}" \
  -o table
```

### 步骤 3：在 GCP 中检测凭据滥用

查询 GCP 审计日志和 SCC 发现，识别凭据入侵指标。

```bash
# 检查 SCC 事件威胁检测发现
gcloud scc findings list ORG_ID \
  --filter="state=\"ACTIVE\" AND (category=\"ANOMALOUS_CALLER_LOCATION\" OR category=\"SUSPICIOUS_LOGIN\" OR category=\"CREDENTIAL_ACCESS\")" \
  --format="table(finding.category, finding.severity, finding.resourceName, finding.eventTime)"

# 查询来自异常 IP 的服务账户密钥使用记录
gcloud logging read '
  protoPayload.authenticationInfo.principalEmail:*@*.iam.gserviceaccount.com
  AND protoPayload.requestMetadata.callerIp!=("10." OR "172." OR "192.168.")
  AND timestamp>="2026-02-22T00:00:00Z"
' --limit=100 --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.requestMetadata.callerIp, protoPayload.methodName)"

# 检测来自 Tor 出口节点的 API 调用
gcloud logging read '
  protoPayload.requestMetadata.callerIp:("185." OR "198." OR "45.")
  AND protoPayload.authenticationInfo.principalEmail:*@company.com
  AND timestamp>="2026-02-22T00:00:00Z"
' --limit=50 --format=json

# 检查新创建的服务账户密钥（持久化指标）
gcloud logging read '
  protoPayload.methodName="google.iam.admin.v1.CreateServiceAccountKey"
  AND timestamp>="2026-02-16T00:00:00Z"
' --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.request.name)"
```

### 步骤 4：构建跨云关联规则

在 SIEM 中创建规则，关联跨云提供商的凭据滥用指标。

```python
# siem_correlation.py - 跨云凭据滥用检测
import json
from datetime import datetime, timedelta

def detect_impossible_travel(events):
    """检测同一身份在短时间内从地理位置相距较远的位置使用。"""
    user_events = {}
    for event in events:
        user = event.get('principal', '')
        ip = event.get('source_ip', '')
        ts = event.get('timestamp', '')
        cloud = event.get('cloud_provider', '')

        key = f"{user}_{cloud}"
        if key not in user_events:
            user_events[key] = []
        user_events[key].append({'ip': ip, 'timestamp': ts, 'cloud': cloud})

    alerts = []
    for user_key, accesses in user_events.items():
        accesses.sort(key=lambda x: x['timestamp'])
        for i in range(1, len(accesses)):
            time_diff = (datetime.fromisoformat(accesses[i]['timestamp']) -
                        datetime.fromisoformat(accesses[i-1]['timestamp']))
            if time_diff < timedelta(hours=1) and accesses[i]['ip'] != accesses[i-1]['ip']:
                alerts.append({
                    'type': 'IMPOSSIBLE_TRAVEL',
                    'user': user_key,
                    'ip_1': accesses[i-1]['ip'],
                    'ip_2': accesses[i]['ip'],
                    'time_gap_minutes': time_diff.total_seconds() / 60,
                    'severity': 'HIGH'
                })
    return alerts

def detect_credential_stuffing(events, threshold=10):
    """检测多次登录失败后成功的凭据填充攻击。"""
    user_attempts = {}
    for event in events:
        user = event.get('principal', '')
        success = event.get('success', False)
        key = user
        if key not in user_attempts:
            user_attempts[key] = {'failures': 0, 'success_after_failures': False}
        if not success:
            user_attempts[key]['failures'] += 1
        elif user_attempts[key]['failures'] >= threshold:
            user_attempts[key]['success_after_failures'] = True

    return [{'user': u, 'failures': d['failures'], 'severity': 'CRITICAL'}
            for u, d in user_attempts.items() if d['success_after_failures']]
```

### 步骤 5：响应已确认的凭据入侵

确认凭据入侵后，执行遏制操作。

```bash
# AWS: 立即停用访问密钥
aws iam update-access-key --user-name COMPROMISED_USER \
  --access-key-id AKIA_COMPROMISED --status Inactive

# AWS: 通过更新角色信任策略使临时角色凭据失效
aws iam update-assume-role-policy --role-name COMPROMISED_ROLE \
  --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Principal":"*","Action":"sts:AssumeRole"}]}'

# AWS: 撤销 IAM 用户的所有会话
aws iam put-user-policy --user-name COMPROMISED_USER \
  --policy-name RevokeOldSessions \
  --policy-document '{
    "Version":"2012-10-17",
    "Statement":[{
      "Effect":"Deny",
      "Action":"*",
      "Resource":"*",
      "Condition":{"DateLessThan":{"aws:TokenIssueTime":"2026-02-23T10:00:00Z"}}
    }]
  }'

# Azure: 撤销所有登录会话
az rest --method POST \
  --url "https://graph.microsoft.com/v1.0/users/COMPROMISED_USER_ID/revokeSignInSessions"

# Azure: 强制密码重置
az ad user update --id COMPROMISED_USER_ID --force-change-password-next-sign-in true

# GCP: 禁用服务账户
gcloud iam service-accounts disable COMPROMISED_SA_EMAIL

# GCP: 删除服务账户密钥
gcloud iam service-accounts keys delete KEY_ID --iam-account=COMPROMISED_SA_EMAIL
```

## 核心概念

| 术语 | 定义 |
|------|------|
| 不可能旅行（Impossible Travel） | 检测同一凭据在物理上不可能完成的时间段内从地理位置相距较远的地点使用 |
| 凭据填充（Credential Stuffing） | 利用数据泄露中获取的用户名/密码组合，尝试登录多个云服务的攻击 |
| 实例凭据泄露（Instance Credential Exfiltration） | GuardDuty 发现，表明 EC2 实例角色凭据正在从预期 AWS 网络之外使用 |
| 异常行为（Anomalous Behavior） | 基于机器学习的检测，识别与主体已建立基线存在显著偏差的 API 调用模式 |
| 会话撤销（Session Revocation） | 使被入侵主体的所有活跃身份验证会话失效，强制使用新凭据重新认证 |
| 持久化指标（Persistence Indicator） | 攻击者在初始入侵后维持访问权限的行为，例如创建新访问密钥或服务账户密钥 |

## 工具与系统

- **AWS GuardDuty**：基于 ML 的威胁检测，包含针对凭据入侵和未授权访问的专用发现类型
- **Microsoft Entra ID Protection**：用于登录异常、凭据入侵和高风险用户行为的身份风险检测
- **GCP Event Threat Detection**：SCC 组件，检测 GCP 环境中的异常 API 使用和凭据滥用
- **CloudTrail / Activity Log / Audit Log**：提供凭据入侵调查原始数据的 API 审计日志
- **SIEM（Splunk、Elastic、Sentinel）**：用于跨云关联凭据滥用指标的集中化平台

## 常见场景

### 场景：通过钓鱼攻击检测被入侵的访问密钥

**场景背景**：一名开发者收到钓鱼邮件，其 AWS 控制台凭据被窃取。攻击者从境外 IP 登录，创建新访问密钥，并开始枚举账户。

**方法**：
1. GuardDuty 触发 `UnauthorizedAccess:IAMUser/ConsoleLoginSuccess.B`，显示来自异常国家的登录
2. SOC 审查发现，并与邮件安全团队的钓鱼报告进行关联
3. 查询 CloudTrail 中被入侵用户在攻击者 IP 下的所有操作
4. 发现攻击者创建了新访问密钥并运行了 IAM 枚举命令
5. 立即停用用户所有访问密钥并撤销活跃会话
6. 强制密码重置并重新注册 MFA
7. 检查持久化痕迹：创建的新 IAM 用户、角色、Lambda 函数或 EC2 实例
8. 删除所有持久化痕迹并记录事件时间线

**常见陷阱**：仅更改密码不会使现有访问密钥或活跃会话失效。必须轮换所有访问密钥，并通过添加拒绝所有令牌（颁发时间早于检测时间的令牌）的策略来撤销临时凭据。攻击者可能在初始凭据被撤销前创建新的 IAM 用户或角色以维持持久化访问。

## 输出格式

```
云凭据入侵检测报告
===============================================
检测日期: 2026-02-23
范围: 多云（AWS、Azure、GCP）
时间段: 2026-02-16 至 2026-02-23

活跃入侵指标:
[CRED-001] AWS 控制台从异常位置登录
  用户: developer@company.com
  来源 IP: 185.x.x.x（俄罗斯）
  正常位置: 美国东部
  GuardDuty 发现: UnauthorizedAccess:IAMUser/ConsoleLoginSuccess.B
  严重级别: 高
  状态: 凭据已停用

[CRED-002] Azure 不可能旅行检测
  用户: admin@company.onmicrosoft.com
  位置 1: 美国纽约（09:00 UTC）
  位置 2: 中国北京（09:15 UTC）
  风险级别: 高
  状态: 会话已撤销，正在调查

检测指标（过去 7 天）:
  不可能旅行检测:           5 次
  异常 API 活动告警:        12 次
  失败登录超过阈值:          3 次
  来自异常 IP 的新凭据:      2 次
  已确认入侵总数:            2 次

已执行遏制操作:
  AWS 访问密钥已停用:    3 个
  Azure 会话已撤销:      2 个
  GCP 服务账户已禁用:    1 个
  密码强制重置:          4 个
  MFA 重新注册:          4 个
```

