Communitygithub.com

Cobalt Strike 비콘 설정 분석

PE 파일에서 Cobalt Strike 비콘 설정을 추출하고 분석합니다.

Cobalt Strike 비콘 설정 분석란 무엇인가요?

이 스킬은 PE 파일, 셸코드 또는 메모리 덤프에서 Cobalt Strike 비콘 설정을 추출하고 분석하는 방법을 제공합니다. Cobalt Strike 비콘은 C2 서버 주소, 통신 프로토콜, 슬립 간격, 지터 값, Malleable C2 프로필 설정, 워터마크 식별자 및 암호화 키와 같은 포함된 구성 데이터를 포함합니다. 이 스킬은 SentinelOne의 CobaltStrikeParser, dissect.cobaltstrike 라이브러리, YARA 규칙, 그리고 수동 XOR 복호화 기술을 사용하여 구성 정보를 추출하고 분석하는 포괄적인 워크플로우를 제공합니다. 이는 침해 사고 대응자가 공격자 인프라를 매핑하고 캠페인을 귀속시키는 데 중요하며, 탐지 규칙 구축, 위협 헌팅 및 보안 모니터링 검증에 유용합니다. 스킬은 Python 기반 도구를 지원하며, Windows 및 Linux 플랫폼 모두에서 사용할 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/analyzing-cobalt-strike-beacon-configuration

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Cobalt Strike 비콘 설정 분석은(는) 무엇을 하나요?

개요

Cobalt Strike는 위협 행위자들이 사후 침해 작업에 널리 악용하는 상용 적대적 시뮬레이션 도구입니다. 비콘 페이로드에는 C2 서버 주소, 통신 프로토콜, 슬립 간격, 지터 값, Malleable C2 프로필 설정, 워터마크 식별자 및 암호화 키를 나타내는 포함된 구성 데이터가 들어 있습니다. PE 파일, 셸코드 또는 메모리 덤프에서 이 구성을 추출하는 것은 침해 사고 대응자가 공격자 인프라를 매핑하고 캠페인을 귀속시키는 데 중요합니다. 비콘 구성은 단일 바이트(버전 3의 경우 0x69, 버전 4의 경우 0x2e)를 사용하여 XOR 인코딩되며 .data 섹션 내에 TLV(Type-Length-Value) 형식으로 저장됩니다.

사용 시기

  • Cobalt Strike 비콘 구성을 분석해야 하는 보안 사고를 조사할 때
  • 이 도메인에 대한 탐지 규칙 또는 위협 헌팅 쿼리를 구축할 때
  • SOC 분석가가 이 분석 유형에 대한 체계적인 절차가 필요할 때
  • 관련 공격 기술에 대한 보안 모니터링 범위를 검증할 때

전제 조건

  • Python 3.9+ 및 dissect.cobaltstrike, pefile, yara-python
  • SentinelOne CobaltStrikeParser (parse_beacon_config.py)
  • 16진수 편집기(010 Editor, HxD) 수동 검사용
  • PE 파일 형식 및 XOR 인코딩 이해
  • 메모리 덤프 획득 도구(Volatility3, WinDbg)
  • C2 트래픽 상관 분석을 위한 네트워크 분석 도구(Wireshark)

주요 개념

비콘 구성 구조

Cobalt Strike 비콘은 PE의 .data 섹션 내에 TLV 항목의 blob으로 구성을 저장합니다. Stageless 비콘은 4바이트 키로 전체 비콘 코드를 XOR합니다. 구성 blob 자체는 단일 바이트 XOR 키를 사용합니다. 각 TLV 항목에는 2바이트 유형 식별자(예: BeaconType의 경우 0x0001, C2Server의 경우 0x0008), 2바이트 길이 및 가변 길이 데이터가 포함됩니다.

Malleable C2 프로필

비콘 구성은 HTTP 요청/응답 변환을 규정하는 Malleable C2 프로필을 인코딩합니다. 여기에는 URI 경로, 헤더, 메타데이터 인코딩(Base64, NetBIOS) 및 데이터 변환이 포함됩니다. 이러한 설정을 분석하면 비콘이 정상 웹 트래픽과 혼합되도록 트래픽을 위장하는 방법이 드러납니다.

워터마크 및 라이선스 식별

각 Cobalt Strike 라이선스는 생성된 비콘에 고유한 워터마크(4바이트 정수)를 포함합니다. 워터마크를 추출하면 여러 비콘을 동일한 운영자 또는 크랙된 라이선스에 연결할 수 있습니다. 위협 인텔리전스 제공업체가 관리하는 알려진 워터마크 데이터베이스는 워터마크를 특정 위협 행위자 또는 유출된 라이선스 키에 매핑합니다.

워크플로우

1단계: CobaltStrikeParser로 구성 추출

#!/usr/bin/env python3
"""PE 또는 메모리 덤프에서 Cobalt Strike 비콘 구성을 추출합니다."""
import sys
import json

# SentinelOne의 CobaltStrikeParser 사용
# pip install dissect.cobaltstrike
from dissect.cobaltstrike.beacon import BeaconConfig

def extract_beacon_config(filepath):
    """파일에서 비콘 구성을 파싱합니다."""
    configs = list(BeaconConfig.from_path(filepath))

    if not configs:
        print(f"[-] {filepath}에서 비콘 구성을 찾을 수 없습니다")
        return None

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

        settings = config.as_dict()

        # 침해 사고 대응에 중요한 필드
        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):
    """비콘 구성에서 실행 가능한 C2 지표를 추출합니다."""
    indicators = {
        "c2_domains": [],
        "c2_ips": [],
        "c2_urls": [],
        "user_agent": "",
        "named_pipes": [],
        "spawn_processes": [],
        "watermark": "",
    }

    if not config:
        return indicators

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

    # 사용자 에이전트 추출
    indicators["user_agent"] = str(config.get("SETTING_USERAGENT", ""))

    # 명명된 파이프 추출
    pipe = config.get("SETTING_PIPENAME", "")
    if pipe:
        indicators["named_pipes"].append(str(pipe))

    # Spawn-to 프로세스 추출
    for arch in ["SETTING_SPAWNTO_X86", "SETTING_SPAWNTO_X64"]:
        proc = config.get(arch, "")
        if proc:
            indicators["spawn_processes"].append(str(proc))

    # 워터마크 추출
    indicators["watermark"] = str(config.get("SETTING_WATERMARK", ""))

    return indicators


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"사용법: {sys.argv[0]} <비콘_파일_또는_덤프>")
        sys.exit(1)

    config = extract_beacon_config(sys.argv[1])
    if config:
        indicators = extract_c2_indicators(config)
        print(f"\n[+] 추출된 C2 지표:")
        print(json.dumps(indicators, indent=2))

2단계: 비콘 구성 수동 XOR 복호화

import struct

def find_and_decrypt_config(data):
    """비콘 구성을 수동으로 찾아 복호화합니다."""
    # Cobalt Strike 4.x는 XOR 키로 0x2e를 사용
    xor_keys = [0x2e, 0x69]  # v4, v3

    for xor_key in xor_keys:
        # XOR 후 구성 매직 바이트 검색
        # 구성은 XOR 키로 XOR된 0x0001(BeaconType)로 시작
        magic = bytes([0x00 ^ xor_key, 0x01 ^ xor_key,
                       0x00 ^ xor_key, 0x02 ^ xor_key])

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

        print(f"[+] 오프셋 0x{offset:x}에서 구성 발견 (XOR 키: 0x{xor_key:02x})")

        # 구성 blob 복호화(보통 4096바이트)
        config_size = 4096
        encrypted = data[offset:offset + config_size]
        decrypted = bytes([b ^ xor_key for b in encrypted])

        # TLV 항목 파싱
        entries = parse_tlv(decrypted)
        return entries

    return None


def parse_tlv(data):
    """TLV 구성 항목을 파싱합니다."""
    entries = {}
    offset = 0

    # TLV 필드 유형 매핑
    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단계: 비콘 탐지를 위한 YARA 규칙

import yara

cobalt_strike_rule = """
rule CobaltStrike_Beacon_Config {
    meta:
        description = "Cobalt Strike 비콘 구성 탐지"
        author = "악성코드 분석 팀"
        date = "2025-01-01"

    strings:
        // CS 4.x의 XOR된 구성 마커 (키 0x2e)
        $config_v4 = { 2e 2f 2e 2c }

        // CS 3.x의 XOR된 구성 마커 (키 0x69)
        $config_v3 = { 69 68 69 6b }

        // 일반적인 비콘 문자열
        $str_pipe = "\\\\.\\pipe\\" ascii wide
        $str_beacon = "beacon" ascii nocase
        $str_sleeptime = "sleeptime" ascii nocase

        // 반사형 로더 패턴
        $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):
    """YARA 규칙을 사용하여 Cobalt Strike 비콘 파일을 스캔합니다."""
    rules = yara.compile(source=cobalt_strike_rule)
    matches = rules.match(filepath)

    for match in matches:
        print(f"[+] YARA 일치: {match.rule}")
        for string_match in match.strings:
            offset = string_match.instances[0].offset
            print(f"    문자열: {string_match.identifier} (오프셋 0x{offset:x})")

    return matches

4단계: 네트워크 트래픽 상관 분석

from dissect.cobaltstrike.c2 import HttpC2Config

def analyze_c2_profile(beacon_config):
    """비콘 구성에서 Malleable C2 프로필을 분석합니다."""
    print("\n[+] Malleable C2 프로필 분석")
    print("=" * 60)

    # HTTP GET 구성
    get_verb = beacon_config.get("SETTING_C2_VERB_GET", "GET")
    get_uri = beacon_config.get("SETTING_C2_REQUEST", "")
    print(f"\n  HTTP GET 요청:")
    print(f"    동사: {get_verb}")
    print(f"    URI: {get_uri}")

    # HTTP POST 구성
    post_verb = beacon_config.get("SETTING_C2_VERB_POST", "POST")
    post_uri = beacon_config.get("SETTING_C2_POSTREQ", "")
    print(f"\n  HTTP POST 요청:")
    print(f"    동사: {post_verb}")
    print(f"    URI: {post_uri}")

    # 사용자 에이전트
    ua = beacon_config.get("SETTING_USERAGENT", "")
    print(f"\n  User-Agent: {ua}")

    # 호스트 헤더
    host = beacon_config.get("SETTING_C2_HOSTHEADER", "")
    print(f"  Host 헤더: {host}")

    # 트래픽 패턴을 위한 슬립 및 지터
    sleep_ms = beacon_config.get("SETTING_SLEEPTIME", 60000)
    jitter = beacon_config.get("SETTING_JITTER", 0)
    print(f"\n  슬립 시간: {sleep_ms}ms")
    print(f"  지터: {jitter}%")

    # Suricata/Snort 시그니처 생성
    print(f"\n[+] 제안된 네트워크 시그니처:")
    if ua:
        print(f'  alert http any any -> any any (msg:"CS 비콘 UA"; '
              f'content:"{ua}"; http_user_agent; sid:1000001; rev:1;)')
    if get_uri:
        print(f'  alert http any any -> any any (msg:"CS 비콘 URI"; '
              f'content:"{get_uri}"; http_uri; sid:1000002; rev:1;)')

검증 기준

  • PE 파일 또는 메모리 덤프에서 비콘 구성이 성공적으로 추출됨
  • C2 서버 도메인/IP가 포트 및 프로토콜과 함께 올바르게 식별됨
  • Malleable C2 프로필 매개변수가 복호화되어 HTTP 변환을 보여줌
  • 귀속 상관 분석을 위해 워터마크 값이 추출됨
  • 슬립 시간 및 지터 값이 관찰된 네트워크 비콘 간격과 일치함
  • YARA 규칙이 패킹 및 언패킹 샘플 모두에서 비콘을 탐지함
  • 추출된 C2 프로필에서 네트워크 시그니처가 생성됨

참고 자료

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

abusing-dpapi-for-credential-access

Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys) online or offline using SharpDPAPI, SharpChrome, Mimikatz, or Impacket

abusing-shadow-credentials-for-privesc

Take over Active Directory accounts by writing attacker-controlled public keys to msDS-KeyCredentialLink (Shadow Credentials) with pyWhisker, Whisker, or Certipy, then authenticate via PKINIT to recover the target

achieving-cmmc-level-2-compliance

>-

acquiring-disk-image-with-dd-and-dcfldd

Create forensically sound bit-for-bit disk images with dd or dcfldd on a Linux forensic workstation, preserving evidence integrity through hash verification (MD5/SHA) during acquisition. Use when imaging a suspect drive, USB device, or memory card for investigation, preserving volatile disk evidence during incident response, or producing a verified copy for legal or law-enforcement proceedings before any destructive analysis.

analyzing-active-directory-acl-abuse

Detect dangerous ACL misconfigurations in Active Directory using ldap3

analyzing-android-malware-with-apktool

Perform static analysis of Android APK malware using apktool for resource decompilation, jadx for Java source recovery, and androguard for manifest inspection, dangerous permission-combination detection, and identification of obfuscated code, dynamic code loading, and reflection-based API calls. Use to statically triage a suspicious APK without executing it or to build mobile malware detection rules.

analyzing-api-gateway-access-logs

Parses API Gateway access logs (AWS API Gateway, Kong, Nginx) to detect

analyzing-apt-group-with-mitre-navigator

Query ATT&CK data with attackcti, mitreattack-python, and stix2, then build MITRE ATT&CK Navigator layers and multi-layer heatmap overlays mapping one or more APT groups

analyzing-azure-activity-logs-for-threats

Queries Azure Monitor activity logs and sign-in logs via azure-monitor-query

analyzing-bootkit-and-rootkit-samples

Analyzes bootkit and advanced rootkit malware infecting the Master

analyzing-browser-forensics-with-hindsight

Parse Chromium-based browser databases with Hindsight to extract and correlate browsing history, downloads, cookies, cached content, autofill data, saved passwords, and extensions from Chrome, Edge, Brave, Opera, and Vivaldi into a unified timeline (XLSX, JSON, or SQLite output). Use during incident response, insider-threat investigations, or criminal cases when you need to reconstruct a user

analyzing-campaign-attribution-evidence

Systematically evaluate cyber-campaign evidence to attribute an operation to a threat actor, using the Diamond Model and Analysis of Competing Hypotheses (ACH) to weigh infrastructure overlaps, TTP consistency, malware code similarity, and timing/language artifacts into confidence-weighted attribution assessments. Use when an incident investigation needs a defensible attribution confidence level.

analyzing-certificate-transparency-for-phishing

Monitor Certificate Transparency logs using crt.sh and Certstream to

analyzing-cloud-storage-access-patterns

Detect abnormal access in AWS S3, GCS, and Azure Blob Storage by analyzing CloudTrail Data Events, GCS audit logs, and Azure Storage Analytics for after-hours bulk downloads, new-IP access, and API-call spikes (e.g. GetObject) via statistical baselines and time-series anomaly detection. Use when investigating suspected cloud data exfiltration or building related detection rules.

analyzing-cobaltstrike-malleable-c2-profiles

Parse and analyze Cobalt Strike Malleable C2 profiles with dissect.cobaltstrike (profiles and beacon-payload configs) and pyMalleableC2 (AST parsing) to extract HTTP/DNS transforms, URIs, headers, sleep/jitter, and injection behavior, then generate network detection signatures. Use when reverse-engineering a captured malleable profile or building detections against Cobalt Strike Beacon traffic.

analyzing-command-and-control-communication

Analyzes malware C2 communication over HTTP, HTTPS, DNS, and custom

analyzing-cyber-kill-chain

Analyzes intrusion activity against the Lockheed Martin Cyber Kill Chain

analyzing-disk-image-with-autopsy

Perform comprehensive forensic analysis of raw (dd), E01, or AFF disk images with Autopsy and The Sleuth Kit, recovering deleted files, examining metadata and embedded artifacts, keyword searching, and building investigation timelines with visual reports. Use for structured analysis of a forensic disk image or when stakeholders need visual reports from evidence.

analyzing-dns-logs-for-exfiltration

Analyzes DNS query logs to detect data exfiltration via DNS tunneling,

analyzing-docker-container-forensics

Investigate compromised Docker containers by analyzing images, layers,

관련 스킬