mcpField
A
analyzing-cobalt-strike-beacon-configuration

analyzing-cobalt-strike-beacon-configuration

github.com/mukul975安全35.2k404 次安装8 周前更新
代码仓库

关于 analyzing-cobalt-strike-beacon-configuration

用于从 PE 文件、shellcode 或内存转储中提取并解读 Cobalt Strike Beacon 配置的安全分析技能。帮助事件响应人员识别 C2 设置、流量配置和水印,以支持检测与基础设施关联分析。

主要功能

  1. 01提取 Beacon 配置
  2. 02解析 C2 地址与协议
  3. 03检查 Malleable C2 配置
  4. 04获取水印与通信间隔参数
  5. 05关联配置与网络流量

适用场景

  1. 01调查 Cobalt Strike 安全事件
  2. 02关联攻击者基础设施
  3. 03编写 YARA 和网络检测规则
  4. 04比对 Beacon 配置与实测通信间隔

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill analyzing-cobalt-strike-beacon-configuration

安装后在 Claude Code 中输入/analyzing-cobalt-strike-beacon-configuration确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LICENSE
assets/
template.md
references/
api-reference.md
standards.md
workflows.md
scripts/
agent.py
process.py

详细介绍

分析 Cobalt Strike Beacon 配置

概述

Cobalt Strike 是一款商业化对手模拟工具,常被威胁行为者滥用于后渗透行动。Beacon 载荷中嵌入的配置数据会揭示 C2 服务地址、通信协议、休眠间隔、抖动值、可塑性 C2 配置文件设置、水印标识符和加密密钥。从 PE 文件、Shellcode 或内存转储中提取这些配置,对于事件响应人员绘制攻击者基础设施并归因攻击活动至关重要。Beacon 配置使用单字节(版本 3 为 0x69,版本 4 为 0x2e)进行 XOR 编码,并以类型-长度-值(TLV)格式存储在 .data 节中。

适用场景

  • 调查需要分析 Cobalt Strike Beacon 配置的安全事件时
  • 为此领域构建检测规则或威胁狩猎查询时
  • SOC 分析师需要此类分析的结构化流程时
  • 验证针对相关攻击技术的安全监控覆盖情况时

前提条件

  • Python 3.9+,以及 dissect.cobaltstrike、pefile、yara-python
  • SentinelOne CobaltStrikeParser(parse_beacon_config.py)
  • 用于手动检查的十六进制编辑器(010 Editor、HxD)
  • 了解 PE 文件格式和 XOR 编码
  • 内存转储采集工具(Volatility3、WinDbg)
  • 用于关联 C2 流量的网络分析工具(Wireshark)

关键概念

Beacon 配置结构

Cobalt Strike Beacon 会将配置存储为 TLV(类型-长度-值)条目组成的数据块,位于 PE 的 .data 节中。无阶段 Beacon 会使用 4 字节密钥对整个 Beacon 代码进行 XOR 运算。配置数据块本身使用单字节 XOR 密钥。每个 TLV 条目包含一个 2 字节类型标识符(例如,BeaconType 为 0x0001,C2Server 为 0x0008)、一个 2 字节长度字段和长度可变的数据。

可塑性 C2 配置文件

Beacon 配置中编码了可塑性 C2 配置文件,用于规定 HTTP 请求/响应转换方式,包括 URI 路径、标头、元数据编码(Base64、NetBIOS)和数据转换。分析这些设置可以揭示 Beacon 如何伪装流量,使其融入合法的 Web 流量。

水印与许可证识别

每个 Cobalt Strike 许可证都会在生成的 Beacon 中嵌入一个唯一水印(4 字节整数)。提取水印可以将多个 Beacon 关联到同一操作人员或破解的许可证。威胁情报提供商维护的已知水印数据库,可将水印映射到特定威胁行为者或泄露的许可证密钥。

工作流

步骤 1:使用 CobaltStrikeParser 提取配置
#!/usr/bin/env python3
"""Extract Cobalt Strike beacon config from PE or memory dump."""
import sys
import json

# Using SentinelOne's CobaltStrikeParser
# pip install dissect.cobaltstrike
from dissect.cobaltstrike.beacon import BeaconConfig

def extract_beacon_config(filepath):
    """Parse beacon configuration from file."""
    configs = list(BeaconConfig.from_path(filepath))

    if not configs:
        print(f"[-] No beacon configuration found in {filepath}")
        return None

    for i, config in enumerate(configs):
        print(f"\n[+] Beacon Configuration #{i+1}")
        print(f"{'='*60}")

        settings = config.as_dict()

        # Critical fields for incident response
        critical_fields = [
            "SETTING_C2_REQUEST",
            "SETTING_C2_RECOVER",
            "SETTING_PUBKEY",
            "SETTING_DOMAINS",
            "SETTING_BEACONTYPE",
            "SETTING_PORT",
            "SETTING_SLEEPTIME",
            "SETTING_JITTER",
            "SETTING_MAXGET",
            "SETTING_SPAWNTO_X86",
            "SETTING_SPAWNTO_X64",
            "SETTING_PIPENAME",
            "SETTING_WATERMARK",
            "SETTING_C2_VERB_GET",
            "SETTING_C2_VERB_POST",
            "SETTING_USERAGENT",
            "SETTING_PROTOCOL",
        ]

        for field in critical_fields:
            value = settings.get(field, "N/A")
            print(f"  {field}: {value}")

        return settings

    return None


def extract_c2_indicators(config):
    """Extract actionable C2 indicators from beacon config."""
    indicators = {
        "c2_domains": [],
        "c2_ips": [],
        "c2_urls": [],
        "user_agent": "",
        "named_pipes": [],
        "spawn_processes": [],
        "watermark": "",
    }

    if not config:
        return indicators

    # Extract C2 domains
    domains = config.get("SETTING_DOMAINS", "")
    if domains:
        for domain in str(domains).split(","):
            domain = domain.strip().rstrip("/")
            if domain:
                indicators["c2_domains"].append(domain)

    # Extract user agent
    indicators["user_agent"] = str(config.get("SETTING_USERAGENT", ""))

    # Extract named pipes
    pipe = config.get("SETTING_PIPENAME", "")
    if pipe:
        indicators["named_pipes"].append(str(pipe))

    # Extract spawn-to processes
    for arch in ["SETTING_SPAWNTO_X86", "SETTING_SPAWNTO_X64"]:
        proc = config.get(arch, "")
        if proc:
            indicators["spawn_processes"].append(str(proc))

    # Extract watermark
    indicators["watermark"] = str(config.get("SETTING_WATERMARK", ""))

    return indicators


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <beacon_file_or_dump>")
        sys.exit(1)

    config = extract_beacon_config(sys.argv[1])
    if config:
        indicators = extract_c2_indicators(config)
        print(f"\n[+] Extracted C2 Indicators:")
        print(json.dumps(indicators, indent=2))
步骤 2:手动 XOR 解密 Beacon 配置
import struct

def find_and_decrypt_config(data):
    """Manually locate and decrypt beacon configuration."""
    # Cobalt Strike 4.x uses 0x2e as XOR key
    xor_keys = [0x2e, 0x69]  # v4, v3

    for xor_key in xor_keys:
        # Search for the config magic bytes after XOR
        # Config starts with 0x0001 (BeaconType) XOR'd with key
        magic = bytes([0x00 ^ xor_key, 0x01 ^ xor_key,
                       0x00 ^ xor_key, 0x02 ^ xor_key])

        offset = data.find(magic)
        if offset == -1:
            continue

        print(f"[+] Found config at offset 0x{offset:x} (XOR key: 0x{xor_key:02x})")

        # Decrypt the config blob (typically 4096 bytes)
        config_size = 4096
        encrypted = data[offset:offset + config_size]
        decrypted = bytes([b ^ xor_key for b in encrypted])

        # Parse TLV entries
        entries = parse_tlv(decrypted)
        return entries

    return None


def parse_tlv(data):
    """Parse Type-Length-Value configuration entries."""
    entries = {}
    offset = 0

    # TLV field type mapping
    field_names = {
        0x0001: "BeaconType",
        0x0002: "Port",
        0x0003: "SleepTime",
        0x0004: "MaxGetSize",
        0x0005: "Jitter",
        0x0006: "MaxDNS",
        0x0007: "Deprecated_PublicKey",
        0x0008: "C2Server",
        0x0009: "UserAgent",
        0x000a: "PostURI",
        0x000b: "Malleable_C2_Instructions",
        0x000c: "Deprecated_HttpGet_Metadata",
        0x000d: "SpawnTo_x86",
        0x000e: "SpawnTo_x64",
        0x000f: "CryptoScheme",
        0x001a: "Watermark",
        0x001d: "C2_HostHeader",
        0x0024: "PipeName",
        0x0025: "Year",
        0x0026: "Month",
        0x0027: "Day",
        0x0036: "ProxyHostname",
    }

    while offset + 6 <= len(data):
        entry_type = struct.unpack(">H", data[offset:offset+2])[0]
        entry_len_type = struct.unpack(">H", data[offset+2:offset+4])[0]
        entry_len = struct.unpack(">H", data[offset+4:offset+6])[0]

        if entry_type == 0:
            break

        value_start = offset + 6
        value_end = value_start + entry_len
        value_data = data[value_start:value_end]

        field_name = field_names.get(entry_type, f"Unknown_0x{entry_type:04x}")

        if entry_len_type == 1:  # Short
            value = struct.unpack(">H", value_data[:2])[0]
        elif entry_len_type == 2:  # Int
            value = struct.unpack(">I", value_data[:4])[0]
        elif entry_len_type == 3:  # String/Blob
            value = value_data.rstrip(b'\x00').decode('utf-8', errors='replace')
        else:
            value = value_data.hex()

        entries[field_name] = value
        print(f"  {field_name}: {value}")

        offset = value_end

    return entries
步骤 3:用于检测 Beacon 的 YARA 规则
import yara

cobalt_strike_rule = """
rule CobaltStrike_Beacon_Config {
    meta:
        description = "Detects Cobalt Strike beacon configuration"
        author = "Malware Analysis Team"
        date = "2025-01-01"

    strings:
        // XOR'd config marker for CS 4.x (key 0x2e)
        $config_v4 = { 2e 2f 2e 2c }

        // XOR'd config marker for CS 3.x (key 0x69)
        $config_v3 = { 69 68 69 6b }

        // Common beacon strings
        $str_pipe = "\\\\.\\pipe\\" ascii wide
        $str_beacon = "beacon" ascii nocase
        $str_sleeptime = "sleeptime" ascii nocase

        // Reflective loader pattern
        $reflective = { 4D 5A 41 52 55 48 89 E5 }

    condition:
        ($config_v4 or $config_v3) or
        (2 of ($str_*) and $reflective)
}
"""

def scan_for_beacons(filepath):
    """Scan file with YARA rules for Cobalt Strike beacons."""
    rules = yara.compile(source=cobalt_strike_rule)
    matches = rules.match(filepath)

    for match in matches:
        print(f"[+] YARA Match: {match.rule}")
        for string_match in match.strings:
            offset = string_match.instances[0].offset
            print(f"    String: {string_match.identifier} at offset 0x{offset:x}")

    return matches
步骤 4:关联网络流量
from dissect.cobaltstrike.c2 import HttpC2Config

def analyze_c2_profile(beacon_config):
    """Analyze malleable C2 profile from beacon configuration."""
    print("\n[+] Malleable C2 Profile Analysis")
    print("=" * 60)

    # HTTP GET configuration
    get_verb = beacon_config.get("SETTING_C2_VERB_GET", "GET")
    get_uri = beacon_config.get("SETTING_C2_REQUEST", "")
    print(f"\n  HTTP GET Request:")
    print(f"    Verb: {get_verb}")
    print(f"    URI: {get_uri}")

    # HTTP POST configuration
    post_verb = beacon_config.get("SETTING_C2_VERB_POST", "POST")
    post_uri = beacon_config.get("SETTING_C2_POSTREQ", "")
    print(f"\n  HTTP POST Request:")
    print(f"    Verb: {post_verb}")
    print(f"    URI: {post_uri}")

    # User Agent
    ua = beacon_config.get("SETTING_USERAGENT", "")
    print(f"\n  User-Agent: {ua}")

    # Host header
    host = beacon_config.get("SETTING_C2_HOSTHEADER", "")
    print(f"  Host Header: {host}")

    # Sleep and jitter for traffic pattern
    sleep_ms = beacon_config.get("SETTING_SLEEPTIME", 60000)
    jitter = beacon_config.get("SETTING_JITTER", 0)
    print(f"\n  Sleep Time: {sleep_ms}ms")
    print(f"  Jitter: {jitter}%")

    # Generate Suricata/Snort signatures
    print(f"\n[+] Suggested Network Signatures:")
    if ua:
        print(f'  alert http any any -> any any (msg:"CS Beacon UA"; '
              f'content:"{ua}"; http_user_agent; sid:1000001; rev:1;)')
    if get_uri:
        print(f'  alert http any any -> any any (msg:"CS Beacon URI"; '
              f'content:"{get_uri}"; http_uri; sid:1000002; rev:1;)')

验证标准

  • 成功从 PE 文件或内存转储中提取 Beacon 配置
  • 正确识别 C2 服务域名/IP、端口和协议
  • 解码可塑性 C2 配置文件参数,显示 HTTP 转换方式
  • 提取水印值以便进行归因关联
  • 休眠时间和抖动值与观察到的网络 Beacon 间隔相符
  • YARA 规则能够检测加壳和未加壳样本中的 Beacon
  • 根据提取的 C2 配置文件生成网络特征

参考资料

评论

支持 Markdown