SOC Prime Bias: Critical

20 Oct 2026 12:39 UTC

ConnectWise SkyKick厂商凭证在Microsoft 365攻击中被滥用

Author Photo
SOC Prime Team linkedin icon 关注
ConnectWise SkyKick厂商凭证在Microsoft 365攻击中被滥用
shield icon

Detection stack

  • AIDR
  • Alert
  • ETL
  • Query

总结

与ConnectWise Cloud Backup(前称SkyKick)关联的微软365 API密钥被威胁行为者利用,非法访问客户的M365环境。攻击者利用该应用程序的广泛权限访问Exchange Online、微软Teams和SharePoint Online。该活动包括自动令牌请求和人工后期利用操作。

调查

Huntress通过微软365登录日志识别出对ConnectWise服务主体的滥用,包括从托管服务商IP地址144.172.64.128和私有Azure IPv6空间的未经授权访问。调查发现,攻击者利用被盗凭证分配目录角色如全局管理员,并向其他受信任应用程序添加新的客户端密钥以保持持久性。活动还显示了按GUID顺序在租户之间的脚本化移动和独特的User-Agent模式。

缓解措施

各组织应立即在其微软365租户中禁用受影响的ConnectWise Cloud Backup和ConnectWise Cloud Management应用ID。禁用而非删除应用程序对于保留同意管理很重要。安全团队还应审核所有服务主体登录,并查看自10月13日以来创建的意外应用程序凭证。

响应

当发现可疑活动时,组织应检查Entra审核日志以 添加成员到角色, 更新应用程序,和 添加服务主体凭证 事件。安全团队应验证相关的User-Agent字符串并区分合法的供应商活动,如kiota-dotnet,与攻击者工具如Python-urllib和curl。最后,审查所有企业应用程序中的客户端密钥和证书,并移除任何未经授权的凭证。

攻击流程

我们仍在更新这一部分。

检测

将用户添加到管理员角色(通过office365)

SOC Prime团队
2026年10月19日

服务主体账户凭证更新(通过azuread)

微软,SOC Prime团队
2026年10月19日

分配了高权限角色(通过azuread)

SOC Prime团队
2026年10月19日

IOC(源IP)检测:M365攻击中被滥用的ConnectWise(SkyKick)供应商凭证

SOC Prime AI规则
2026年10月19日

IOC(目标IP)检测:M365攻击中被滥用的ConnectWise(SkyKick)供应商凭证

SOC Prime AI规则
2026年10月19日

通过Python-urllib检测M365中的未经授权修改[Azure活动日志]

SOC Prime AI规则
2026年10月19日

通过ConnectWise应用在M365中未经授权使用微软Graph令牌[Azure审核日志]

SOC Prime AI规则
2026年10月19日

模拟执行

  • 攻击叙述与命令: 对手已成功访问具有有限权限的服务主体。为了实现持久性和完全环境控制,攻击者执行了一个Python脚本。该脚本针对Microsoft Graph API以:1)将被盗服务主体添加到高权限目录角色(例如,全局管理员或特权角色管理员),并2)向服务主体添加新的客户端密钥。攻击者使用 urllib 库在Python 3.12中,这默认提供了所需的 Python-urllib/3.12 User-Agent,提供检测规则所需的特定遥测钩子。

  • 回归测试脚本:

    import urllib.request
    import json
    
    # NOTE: This script is a simulation of the API call structure. 
    # In a real environment, a valid OAuth2 Bearer token would be required.
    # This script is designed to trigger the 'UserAgent' and 'OperationName' detection logic.
    
    target_url = "https://graph.microsoft.com/v1.0/directoryRoles"
    access_token = "SIMULATED_TOKEN"
    
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }
    
    # This specific User-Agent is the trigger for the detection rule
    user_agent = "Python-urllib/3.12"
    
    # Simulate "Add member to role"
    payload = {
        "roleId": "target-role-guid",
        "principalId": "attacker-service-principal-guid"
    }
    
    print(f"[*] Simulating unauthorized role modification using {user_agent}...")
    
    try:
        req = urllib.request.Request(
            target_url, 
            data=json.dumps(payload).encode('utf-8'), 
            headers=headers, 
            method='POST'
        )
        req.add_header('User-Agent', user_agent)
    
        # In a real test, this would call the actual API. 
        # For simulation purposes, we assume the API call is successful to generate the log.
        print("[+] Request sent. Check Azure Audit Logs for 'Add member to role' with User-Agent: Python-urllib/3.12")
    except Exception as e:
        print(f"[-] Simulation failed: {e}")
  • 清理命令:

    # 手动清理在M365中是必要的,因为这些是身份级别的更改。
    # 1. 移除添加的角色分配:
    # Remove-MgDirectoryRoleMemberByRef -DirectoryRoleId <ID> -DirectoryRoleMemberId <ID>
    
    # 2. 移除添加的服务主体凭证:
    # Remove-MgServicePrincipalPassword -ServicePrincipalId <ID> -PasswordId <ID>