Cobalt Strike 반사 로더 정의

길거리에서 노트북을 사용하는 검은 후드티를 입은 남성을 해커를 묘사한 모습

보안 솔루션의 차세대 AI 및 머신 러닝 구성 요소는 행동 기반 탐지 기능을 지속적으로 개선하고 있지만, 그 핵심은 여전히 시그니처 기반 탐지에 의존하고 있습니다. Cobalt Strike는 출시 이후 위협 행위자와 레드팀 모두가 사용하는 인기 있는 레드팀 지휘 및 통제(C2) 프레임워크로, 여전히 보안 솔루션의 집중적인 시그니처 탐지 대상입니다.

과거의 Cobalt Strikes 운영 사용을 계속하기 위해 IBM X-Force Red Adversary Simulation 팀은 상당한 연구 개발 노력을 투자하여 내부 툴로 Cobalt Strike를 맞춤화했습니다. 일부 Cobalt Strike 전용 내부 도구에는 'InlineExecute-Assembly', 'CredBandit', 'BokuLoader' 같은 공개 버전이 있습니다. 지난 2년간 Cobalt Strike에 대한 과도한 시그니처 탐지로 인해, 저희는 이를 덜 정교한 위협 행위자 시뮬레이션에만 사용하도록 제한하고, 보다 진보된 레드팀 훈련 수행 시에는 다른 제3자 및 자체 개발 C2를 활용합니다.

연구 개발 노력을 통해 저희는 다음과 같은 고급 레드 팀 훈련에서 더 나은 운영 성공을 거두었습니다.

  • 맞춤형 내부 툴링.
  • 맞춤형 내부 로더.
  • 맞춤형 내부 C2 프레임워크.
  • 대체 제3자 C2 프레임워크의 능력 및 은밀성을 확대하기 위한 투자를 지속합니다.

그러나 여전히 많은 수의 위협 행위자가 Cobalt Strike의 해적판 사본을 악용하고 있으며, 이러한 위협 행위자를 시뮬레이션할 수 있는 능력은 여전히 중요합니다. 연구 및 개발 노력을 기울이려는 레드 팀의 경우 이러한 적들을 시뮬레이션하는 동시에 Cobalt Strike를 사용하여 운영상의 성공을 거둘 수 있습니다. 또한 Cobalt Strike는 훌륭한 학습 도구로, 초보자가 레드 팀 교육 과정을 통해 C2 프레임워크를 직접 사용해 볼 수 있는 데 활용할 수 있습니다.

C2 기능을 지속적으로 확장하면서, 특히 맞춤형 반사 로더를 개발하여 과거에 Cobalt Strike 프레임워크를 구축한 방법에 대한 인사이트를 공유하고자 합니다. 또한 방어자가 Cobalt Strike가 어떻게 작동하여 보다 강력한 탐지를 생성하는지 이해할 수 있도록 하기 위한 것입니다.

반사 로더로 프레임워크 기반 구축

이 블로그 게시물은 Cobalt Strike 반사 로더 개발의 기본 사항을 다루는 입문서 역할을 하는 시리즈의 첫 번째 게시물입니다. 이 시리즈를 진행하면서 이 기반을 바탕으로 이 게시물을 참조할 것입니다.

이 시리즈가 끝날 무렵에는 Cobalt Strike의 기존 회피 기능과 통합되고 현재 도구에 없는 고급 기술로 이를 개선하는 반사 로더를 만드는 것을 목표로 하고 있습니다. 향후 게시물에서는 특정 회피 기능의 개발과 이를 Cobalt Strike 반사 로더에 구현하는 방법에 대해 더 자세히 알아볼 것입니다.

시작하기에 앞서 이 게시물이 다루는 내용은 다음과 같습니다.

  • Windows DLL 로더를 사용하여 디스크에서 C2 임플란트를 로드할 때 발생하는 문제.
  • Cobalt Strike의 반사 로딩 프로세스의 개념과 메커니즘.
  • 효과적인 반사식 로더를 제작하는 데 필요한 설계 요구 사항.
  • 반사 로딩 프로세스와 관련된 단계.

공격형 보안 도구 개발자의 관점에서 Cobalt Strike의 반사 로딩을 살펴보며 탐지 및 회피 기회를 중점적으로 살펴보겠습니다. 일부 개발 측면은 생략되거나 간소화되므로 기존 반사 로더 프로젝트를 디버깅하거나, 처음부터 다시 빌드하거나, 교육을 통해 격차를 메우는 것이 좋습니다.

비콘 DLL 로드

Cobalt Strike C2 임플란트인 비콘은 Windows 동적 링크 라이브러리(DLL)이며, Cobalt Strike에서 자체 DLL 로더를 사용하는 모듈식 기능은 사용자 정의 반사 로더(UDRL) 로 알려져 있습니다.

기본 제공 Windows DLL 로더

일반적으로 기본 제공 Windows DLL 로더는 DLL을 프로세스의 가상 메모리 공간에 로드하는 역할을 합니다. Windows DLL 로더는 주로 사용자 공간 내에 존재하지만, 디스크에서 DLL을 매핑할 때 커널 공간으로 넘어가기도 합니다.

Windows DLL 로더를 사용하면 적대적 시뮬레이션 중에 사용할 때 다음과 같은 몇 가지 단점이 있습니다.

  • 원시 DLL은 파일 시스템에 있어야 합니다.
  • 원시 DLL에는 난독화가 없어야 합니다.
  • 커널 이미지 로드 이벤트는 Windows DLL 로더에 의해 트리거됩니다.

따라서 Windows DLL 로더를 사용하여 비콘 DLL을 로드하는 것은 이상적인 해결책이 아닙니다. 이러한 문제를 극복하기 위해 저희는 반사 로더를 사용하여 메모리에서 Beacon DLL을 로드합니다.

반사 로딩이 회피하는 세 가지 주요 탐지 지점은 다음과 같습니다.

  1. 파일 시스템에서 서명된 멀웨어를 방지합니다.
  2. 보안 솔루션에서 모니터링할 수 있는 커널 이미지 로드 이벤트를 방지합니다.
  3. 프로세스 환경 블록(PEB)에 나열된 C2 임플란트 DLL을 사용하지 않습니다.

반사 로더와 Windows DLL 로더 비교

반사 로딩은 파일 시스템에서 DLL을 로드하는 것과는 달리 메모리에서 직접 DLL을 로드하는 것으로 생각할 수 있습니다.

반사 로딩과 Windows에 내장된 DLL 로더는 모두 원시 파일 형식에서 프로세스의 가상 메모리 공간으로 DLL을 로드하는 동일한 목적을 수행합니다. 하지만 반사 로딩은 Windows DLL 로더에 비해 DLL 파일이 파일 시스템에 존재할 필요가 없다는 중요한 장점을 가지고 있습니다. 이 인메모리 로딩을 통해 C2 임플란트 DLL이 프로세스 메모리 내의 암호화 및 인코딩 계층 내에 숨겨질 수 있으므로 체인 로딩 단계를 무제한으로 수행할 수 있습니다.

원시 파일 형식과 가상 주소 형식 비교

DLL을 로드할 때 이해해야 할 핵심 개념은 DLL이 디스크에서 포맷될 때와 인메모리에서 포맷될 때 다르게 포맷된다는 점입니다. 원시 파일 형식의 DLL과 가상 주소 형식의 주요 차이점은 다음과 같습니다.

원본 파일 형식:

  • 파일 시스템에 존재하는 DLL의 형식입니다.
  • DLL의 섹션은 빽빽하게 배치되어 있습니다.
  • 오프셋은 디스크에 존재하는 원시 DLL 파일의 시작을 기준으로 합니다.
  • 이 형식은 메모리 공간을 덜 차지합니다.

가상 주소 형식:

  • 프로세스의 가상 메모리 공간에 존재하는 DLL의 형식입니다.
  • 세션이 간격을 두고 배치되어 있습니다.
  • 오프셋은 상대 가상 주소(RVA)입니다.
  • 프로세스에서 실행될 때 DLL 및 기타 모듈은 RVA를 통해 위치를 결정합니다.
  • 이 형식은 더 많은 메모리 공간을 차지합니다.

원시 비콘과 가상 비콘 비교

Aleksandra Doniec의 PE-Bear 도구에서 HTTP 비콘 DLL을 살펴봄으로써 DLL의 각 섹션에 대한 원시 주소와 가상 주소의 차이점을 확인할 수 있습니다.

Beacon DLL의 각 섹션에 대한 원시 주소와 가상 주소를 나열한 테이블.

Beacon DLL의 각 섹션에 대한 원시 주소와 가상 주소를 나열한 테이블.

이 HTTP/S 비콘 DLL은 프로세스의 가상 메모리 공간에 로드될 때 크기가 0x52000  바이트 (327KB )입니다. 이는 파일 시스템에 존재하는 크기인 0x44000  바이트로 채워져 있습니다(272KB )와 동일합니다. 이러한 크기 차이는 원시 파일 형식으로 빽빽하게 모여 있는 것이 아니라 가상 주소 형식으로 섹션이 간격을 띄고 있기 때문입니다.

PE-Bear는 원시 파일 형식과 가상 주소 공간 형식으로 존재하는 비콘 DLL의 시각적 표현을 제공합니다.

비콘 DLL의 원시 형식과 가상 형식의 시각적 표현 비교

비콘 DLL의 원시 형식(왼쪽)과 가상 형식(오른쪽)의 시각적 표현

Windows DLL 로더를 사용하여 비콘 로드

적대적 시뮬레이션 중에 수행하는 것이 가장 현명한 방법은 아니지만, 난독화가 없는 원시 비콘 DLL을 디스크에 배치하고 Windows DLL 로더로 로드하는 것은 비콘과 DLL 로딩을 모두 이해할 수 있는 좋은 방법입니다. 본질적으로 비콘은 그냥 DLL일 뿐입니다. Windows DLL 로더와 반사 로더는 DLL을 프로세스에 로드하기만 하면 됩니다.

Windows DLL 로더를 사용하여 비콘 DLL을 로드하려면 다음 단계를 수행합니다.

  1. 난독화 없이 원시 비콘 DLL을 생성합니다.
  2. 다음을 수행하는 프로그램을 생성합니다.
    1. 디스크에서 비콘 DLL을 로드하기 위해 LoadLibrary API를 사용합니다.
    2. 가상 비콘을 DLL의 진입 지점으로 호출하여 우리의 비콘을 실행합니다.
  3. 실행 프로그램과 비콘 DLL을 같은 폴더에 넣습니다.
  4. 프로그램을 실행합니다.

난독화 없는 원시 비콘 DLL 생성

먼저, Windows DLL 로더에서 비콘 DLL을 불러올 수 없게 하는 모든 Malleable PE 옵션을 비활성화합니다. 이를 위해 Malleable C2 프로파일을 수정하고 스테이지 블록에 있는 Malleable PE 회피 옵션을 비활성화합니다.

Cobalt Strike 회피 기능을 비활성화하도록 수정된 Malleable C2 프로파일 스테이지 블록.

Cobalt Strike 회피 기능을 비활성화하도록 수정된 Malleable C2 프로파일 스테이지 블록.

프로파일을 수정한 후 Cobalt Strike Team Server를 다시 시작하여 no_evasion.profile  프로파일을 인수로 제공합니다.

블로그 게시물용으로 만든 스크린샷

Cobalt Strike 클라이언트를 사용하여 Team Server에 연결합니다. 그런 다음, 아웃풋 옵션으로Windows Stageless Payload  를 생성합니다. 아웃풋 옵션은 Raw로 설정되고 리스너는 https 로 설정됩니다. 페이로드를 다음으로 저장합니다: beacon.dll .

Cobalt Strike Client에서 '원시 스테이지리스(raw stageless)' 비콘 DLL을 생성하는 스크린샷

Cobalt Strike Client에서 '원시 스테이지리스(raw stageless)' 비콘 DLL을 생성하는 스크린샷

비콘 DLL 로더 프로그램 만들기

아래 코드를 사용하여 loadBeaconDLL.c  라는 이름의 C 프로그램을 만들고 컴파일합니다.

Windows DLL 로더를 사용하여 디스크에서 비콘 DLL을 로드하는 Windows C 코드입니다.

Windows DLL 로더를 사용하여 디스크에서 비콘 DLL을 로드하는 Windows C 코드입니다.

저희는 Kernel32.LoadLibraryA  API를 사용하여 원시 비콘 DLL을 디스크에서 로드합니다. 이 API는 디스크에서 호스트 프로세스의 가상 메모리 공간으로 비콘 DLL을 로드하는 내장 Windows DLL 로더를 호출합니다.

로딩 프로세스의 일부로, Windows DLL 로더는 비콘 DLL의 진입점을 호출합니다. 이때 DLL_PROCESS_ATTACH (1)  를 인수로 사용합니다.

Windows DLL 로더가 비콘 DLL을 프로세스의 가상 메모리 공간에 로드하고 초기화한 후에는 다음 인수를 사용하여 가상 비콘 DLL의 진입점을 다시 호출해야 합니다. 0x4.

저희 프로그램은 가상 비콘 DLL을 실행하기 위해 가상 비콘 DLL의 진입점을 알아야 합니다. 이는 진입점 상대 가상 주소(RVA)에 대한 가상 비콘 DLL의 헤더를 구문 분석하여 프로그램 내에서 동적으로 수행하거나, 정의를 빠르게 살펴보고 값을 하드코딩할 수 있습니다.

개념 증명을 위해 저희는 비콘 DLL의 진입점 RVA를 수동으로 발견하고 프로그램에 하드코딩합니다. PE-Bear를 사용하여 RVA에서 비콘으로의 진입점은 다음과 같다는 것을 발견했습니다. 0x1D840 :

PE-Bear를 사용하여 비콘 DLL 진입점 RVA를 찾는 스크린샷

PE-Bear를 사용하여 비콘 DLL 진입점 RVA를 찾는 스크린샷

그리고 LoadLibraryA  API는 가상 비콘 DLL의 기본 주소를 반환합니다. 이를 진입점 RVA에 추가하여 진입점을 결정하기만 하면 됩니다.

코드가 준비되면 C 프로그램을 Windows 실행 파일로 컴파일합니다.

프로그램을 컴파일하는 데 사용되는 명령.

프로그램을 컴파일하는 데 사용되는 명령.

파일 시스템에 프로그램 및 비콘 DLL 배치

비콘 DLL과 실행 가능한 비콘 로더 프로그램을 동일한 디렉토리에 배치함으로써 Windows DLL 로더는 로딩 루틴을 수행할 때 DLL을 검색할 수 있습니다.

저희는 beacon.dll  및 loadBeaconDLL.exe  둘 다를 파일 시스템 내 같은 디렉터리에 배치했습니다.

비콘 DLL과 로더 프로그램은 같은 디렉터리에 배치되어 있습니다.

비콘 DLL과 로더 프로그램은 같은 디렉터리에 배치되어 있습니다.

프로그램 실행

Windows 바탕 화면에서 loadBeaconDLL.exe 프로그램을 두 번 클릭하고 저희 팀 서버에 활성 비콘 연결을 설정합니다.

Windows DLL 로더를 사용하여 로드된 비콘 DLL에서 C2 Team Server에 성공적으로 연결되었습니다.

Windows DLL 로더를 사용하여 로드된 비콘 DLL에서 C2 Team Server에 성공적으로 연결되었습니다.

Cobalt Strike 반사 로딩

Cobalt Strike는 Stephen Fewer의 Reflective Loader 프로젝트를 수정하여 사용합니다. 이 전설적인 인메모리 DLL 로더는 10년이 넘었으며 Metasploit 및 기타 유명한 공격용 보안 도구에 사용되었습니다.

UDRL 사용 시 고려 사항

수년에 걸쳐 Cobalt Strike 반사 로더는 Cobalt Strike가 제공하는 모든 Malleable PE 회피 기능을 처리하도록 개선되었습니다. 사용자 정의 사용자 정의 반사 로더(UDRL)를 사용할 때의 가장 큰 단점은 Malleable PE 회피 기능이 즉시 지원되거나 지원되지 않을 수 있다는 것입니다.

일부 회피 기능은 UDRL을 사용할 때 완전히 구현되며, 비콘 페이로드 생성 시 Cobalt Strikes Malleable PE 엔진에 의해 비콘 DLL에 패치됩니다. 그러나 현재 obfuscate 같은 기능을 UDRL에서 처리해야 하지만, sleepmask cleanup 같은 다른 기능들은 적절한 UDRL 통합을 통해 비콘에서 처리할 수 있습니다.

반사 로딩 방식

원래 반사 로더 방식

원래 반사 로더 프로젝트는 ReflectiveLoader  을 DLL 프로젝트로 컴파일하고 C2 임플란트 DLL 내에서 내보내야 합니다.

그러면 다른 프로젝트가 다음 단계를 담당합니다.

  1. 먼저 ReflectiveLoader  내보내기의 가상 주소를 찾습니다.
  2. 그 다음, ReflectiveLoader  내보내기를 실행하여 로드된 DLL의 진입 지점을 반환합니다.
  3. 반사적으로 로드된 DLL의 진입점을 호출합니다.
가상 메모리에 DLL을 로드하는 원본 반사 로더의 다이어그램.

가상 메모리에 DLL을 로드하는 원본 반사 로더의 다이어그램.

반사 로더 메서드 앞에 붙이기

다른 방법은 DLL에 반사 로더를 미리 추가하는 것입니다. 이렇게 하면 관리되지 않는 모든 DLL을 로드할 수 있으며 소스 코드에서 DLL을 컴파일할 필요가 없습니다. 이는 강력한 반사 로딩 방식으로, 모든 PE 파일(EXE 또는 DLL)을 로드할 수 있습니다.

DLL에 추가된 반사형 로더가 가상 메모리에 DLL을 로드하는 다이어그램.

DLL에 추가된 반사형 로더가 가상 메모리에 DLL을 로드하는 다이어그램.

Cobalt Strike의 반사 로더 메서드

Cobalt Strike의 반사 로딩 구현은 위의 두 가지 방법을 혼합하여 사용합니다. 이 반사 로딩 방법은 Metasploit의 Meterpreter가 반사 로딩을 수행하는 방법에 대한 지식이 있는 사람들에게 익숙할 수 있습니다.

원래 반사 로더 방식과 마찬가지로, ReflectiveLoader  함수는 컴파일 되어 원래 비콘 DLL 내에서 내보내집니다. 운영자가 Cobalt Strike 클라이언트에서 비콘 페이로드를 생성하면 Cobalt Strike의 Malleable PE 엔진은 원시 비콘 DLL을 패치하여 반사 로더에 사용할 Malleable PE 옵션을 알립니다. 비콘의 DOS 헤더가 패치되어 하드코딩된 오프셋에서 ReflectiveLoader 내보내기를 호출합니다. 비콘의 DOS 헤더의 초기 패치된 바이트( ReflectiveLoader 내보내기 호출)는 블로그에서 '호출 반사 로더 스텁'로 지칭됩니다.

UDRL이 Cobalt Strike에 로드되고 운영자가 Cobalt Strike 클라이언트에서 비콘 페이로드를 생성하면, Cobalt Strike의 Malleable PE 엔진은 다음의 원시 파일 오프셋에 있는 반사 로더 셸코드에서 패치를 진행합니다: ReflectiveLoader  내보내기.

Malleable PE 엔진이 원시 비콘 DLL의 패치를 완료하면, 원시 비콘 DLL은 실행 가능한 셸코드와 유사한 형식으로 운영자에게 제공됩니다.

비콘 DLL을 가상 메모리에 로드하는 Cobalt Strike 반사 로더의 다이어그램.

비콘 DLL을 가상 메모리에 로드하는 Cobalt Strike 반사 로더의 다이어그램.

비콘의 호출 반사 로더 스텁

PE-Bear 디스어셈블러의 초기 바이트를 살펴보면 비콘 DLL 자체가 실행 가능하다는 것을 알 수 있습니다.

실행 가능한 어셈블리 작업 코드로 표시되는 호출 반사 로더 스텁.

실행 가능한 어셈블리 작업 코드로 표시되는 호출 반사 로더 스텁.

초기 바이트 MZAR  은 Cobalt Strikes C2 프로파일의 Malleable PE 옵션을 통해 사용자 지정할 수 있습니다. 이러한 바이트는 실행 가능해야 하며 아무 연산도 수행하지 않아야 합니다(nop ).

선택적으로 앞에 추가된 nops  와 매직 바이트를 실행한 후 호출 반사 로더 스텁은 다음을 수행합니다.

  • 스택 프레임을 생성합니다.
  • RIP 상대 주소 지정을 사용하여 원시 비콘 DLL의 기본 주소를 결정합니다.
  • 내보내기 ReflectiveLoader  을 호출합니다(위치: 0x16E3C  원시 파일 오프셋).
  • 로드된 비콘 DLL의 진입점을 호출합니다.

원시 파일 오프셋( ReflectiveLoader  내보내기)이 다음 값인지 확인합니다: 0x16E3C  이를 위해 비콘 DLL 내보내기 디렉터리를 살펴봅니다.

PE-bear를 사용하여 ReflectiveLoader 내보내기의 원시 파일 오프셋을 결정하는 스크린샷.

PE-bear를 사용하여 ReflectiveLoader 내보내기의 원시 파일 오프셋을 결정하는 스크린샷.

내보내기 디렉터리 내에 존재하므로 다음에 대한 주소는 ReflectiveLoader 내보내기는 가상 상태의 비콘 DLL을 참조하는 RVA 형식입니다. 따라서 ReflectiveLoader  내보내기는 실행 가능하며, 다음 내부에 존재한다는 것을 알고 있습니다:.text 원시 및 가상 주소.

원시 파일 오프셋( ReflectiveLoader  내보내기)을 검색하려면 먼저 .text  가상 및 원시 주소 섹션 간의 차이를 알아야 합니다. 차이를 알았으면 ReflectiveLoader  내보내기의 RVA에서 차이를 빼면 됩니다. ReflectiveLoader  내보내기의 원시 파일 오프셋.

가상 및 원시 주소( .text  섹션)는 비콘 DLL의 섹션 헤더 내에 나열되어 있습니다.

비콘 DLL의 .text 섹션의 원시 및 가상 주소.

비콘 DLL의 .text 섹션의 원시 및 가상 주소.

이 둘의 차이점은 0xC00  바이트입니다. 다음을 차감하여 ReflectiveLoader  내보내기의 RVA 0x17A3C  원시 파일 오프셋이 다음과 같다는 것을 알 수 있습니다. 0x16E3C .

이를 PE-Bear에서ReflectiveLoader  내보내기의 함수 RVA를 우측 클릭하고 다음을 클릭하여 확인할 수 있습니다: Follow RVA:17A3C 위 위젯의 16진수 뷰어를 클릭하면 해당 값을 볼 수 있는 화면으로 이동합니다. ReflectiveLoader  원시 파일 오프셋에 있는 내보내기.

요약하자면, Cobalt Strike 반사 로딩 프로세스 흐름은 다음과 같습니다.

  • 스레드는 원시 비콘 DLL을 실행합니다.
  • 호출 반사 로더 스텁은 알려진 원시 파일 오프셋에서 ReflectiveLoader  내보내기를 호출합니다.
  • 반사 로더는 원시 비콘 DLL을 호스트 프로세스의 가상 메모리에 로드합니다.
  • 로딩이 완료되면 반사 로더는 가상 비콘 DLL의 진입점을 호출 반사 로더 스텁에 반환합니다.
  • 호출 반사 로더 스텁은 가상 비콘 DLL의 진입점을 호출합니다.
Cobalt Strike가 비콘 DLL의 반사 로딩을 수행하는 방법의 주요 단계를 보여주는 다이어그램입니다.

Cobalt Strike가 비콘 DLL의 반사 로딩을 수행하는 방법의 주요 단계를 보여주는 다이어그램입니다.

반사 로더 설계 요구 사항

위치 독립 코드

반사 로더는 비콘 DLL이 로드되기 전에 실행되므로 반사 로더 코드는 순수한 셸코드여야 합니다.

복잡한 셸 코드를 만드는 가장 쉬운 방법은 외부 종속성 없이 C로 작성하는 것입니다. 그런 다음 C 파일이 오브젝트 파일로 컴파일됩니다. 모든 것이 반드시 개체 파일의 text 섹션에 포함되어야 합니다. 마지막으로, 저희는 다음을 제거합니다:.text 섹션에서 반사 로더 셸코드를 가져옵니다.

Cobalt Strike가 UDRL을 삽입하는 방법

Cobalt Strike의 Malleable PE 엔진은 반사 로더 오브젝트 파일에서 셸코드를 가져와서 원시 파일 오프셋의 원시 비콘 DLL에 패치하는 작업을 처리합니다. ReflectiveLoader  내보내기. 이 작업은 아래와 같이 UDRL Aggressor 스크립트에서 수행됩니다.

Cobalt Strike를 활용하여 반사 로더 셸코드를 원시 비콘 DLL에 삽입하는 공격자 스크립트.

Cobalt Strike를 활용하여 반사 로더 셸코드를 원시 비콘 DLL에 삽입하는 공격자 스크립트.

UDRL Aggressor 스크립트는 다음 단계를 수행하여 Cobalt Strike가 반사 로더 셸코드를 작성하도록 합니다.

  • 다음을 엽니다$handle UDRL 오브젝트 파일openf 함수가 사용됩니다.
  • 파일$handle 바이트 스트림을 읽어 다음에 저장$data 바이트 배열 변수.
  • 그런 다음 파일을 닫습니다$handle 다음을 사용:closef 함수가 사용됩니다.
  • 내장된
    <a href="https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics_aggressor-scripts/as-resources_functions.htm#extract_reflective_loader">extract_reflective_loader</a>
    
    Cobalt Strike Aggressor 함수가 UDRL 개체 파일을$data 바이트 배열에서 구문 분석하고,.text 를 UDRL 오브젝트 파일의 섹션에서 찾아 .text 섹션을 추출하고, 다음에 저장합니다:$loader 바이트 배열 변수.
  • 내장된
    <a href="https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics_aggressor-scripts/as-resources_functions.htm#setup_reflective_loader">setup_reflective_loader</a>
    
    Cobalt Strike Aggressor 함수는 Malleable PE 엔진을 사용하여ReflectiveLoader 내보내기의 원시 파일 오프셋을 찾고 UDRL 셸코드를 다음에서 패치합니다:$loader 바이트 배열 변수.
  • 마지막으로 수정된 비콘 DLL을 Cobalt Strike로 반환하고 클라이언트에서 파일을 저장합니다.

반사 로딩 단계

Cobalt Strike는 반사적 로더 개체 파일에서 .text 섹션을 추출하고, 반사적 로더 셸코드를 패치하고, 비콘 DLL 헤더에 위치한 반사적 로더 스텁을 호출하여 반사적 로더를 실행하는 작업을 대신 수행해 주었습니다.

다음은 비콘을 반사적으로 로드하기 위해 개발해야 하는 단계입니다.

  1. 원시 비콘 DLL 찾기
  2. 비콘 DLL 헤더 구문 분석
  3. 가상 비콘 DLL에 대한 메모리 할당
  4. 가상 메모리 공간에 섹션 로드
  5. DLL 종속성 로드
  6. 주소 테이블 가져오기 확인
  7. 재배치 확인
  8. 비콘 실행

1단계: 원시 비콘 DLL 기본 주소 찾기

메모리에서 원시 비콘 DLL의 주소를 찾는 데 사용할 수 있는 방법은 여러 가지가 있습니다. 몇 가지 방법은 다음과 같습니다.

  • MZ 및 PE 헤더 역방향 추적
  • 에그 역방향 추적
  • 반사 로더의 호출자 스텁에서 원시 비콘 DLL 기본 주소 얻기

메모리에서 위치 찾기

역방향으로 추적하는 메서드를 사용할 때는 먼저 스레드의 명령어 포인터(RIP )의 현재 주소를 얻어야 합니다. 이 간단한 트릭을 다음에 사용할 수 있습니다. getRip :

  1. UDRL에서 다음 이름의 함수를 만듭니다: getRip .
  2. 다음을 호출합니다: getRip  그러면 "call getRip " 뒤의 주소를 스택 맨 위에 표시합니다. 이 주소는 반환 주소입니다.
  3. 그런 다음 getRip  함수에서 호출자의 반환 주소를 스택 맨 위에서 복사하기만 하면 됩니다.
  4. x64 윈도우 C 코딩에서 함수는 값을 반환할 수 있습니다. 이 반환된 값은 RAX  레지스터를 통해 호출자에게 반환됩니다. 발신자의 반환 주소를RAX  레지스터에 등록하면 발신자의 반환 주소를 발신자에게 반환합니다.
Intel x64 어셈블리 코드를 사용하여 RDI 레지스터에서 원시 비콘 DLL 기본 주소를 가져옵니다.

Intel x64 어셈블리 코드를 사용하여 RDI 레지스터에서 원시 비콘 DLL 기본 주소를 가져옵니다.

MZ & PE 헤더에 대한 역방향 추적

원래의 반사 로더 프로젝트는 MZ 및 PE 헤더를 역방향으로 추적합니다. 이러한 헤더는 탐지 지점이 됩니다. 이를 극복하기 위해 Cobalt Strike는 magic_mz  및 magic_pe  Malleable PE 회피 기능을 추가했습니다.

The Cobalt Strike 문서 에는 magic_mz  다음의 옵션이 명시되어 있습니다.

  • "비콘의 반사 DLL의 첫 번째 바이트(MZ 헤더 포함)를 재정의하세요. 유효한 지침이 있어야 합니다. CPU 상태를 변경하는 지침을 따르고 변경을 실행 취소하는 지침을 따르세요."

다음을 구성 시 MZ--  원시 파일 오프셋의 바이트 0x00  detectors 라는 사전을 전달하여 Guardian 클래스의 인스턴스를PE00  원시 파일 오프셋의 바이트 0x80  반사 로더에 알려져 있습니다. Malleable PE 엔진에 의해 비콘 DLL에 패치됩니다.

이 바이트들은 어느 정도 고유해야 합니다. 그렇지 않으면 반사 로더가 해당 바이트를 찾을 수 없습니다. 또한 MZ 헤더의 바이트는 무작동 및 실행 가능 바이트여야 합니다. 다음과 같은 값은 사용할 수 없습니다. 0x00  비콘이 충돌할 수 있습니다. 이것이 잠재적인 탐지 지점일 수 있습니다.

에그에 대한 역방향 추적

이 잠재적 탐지 지점을 발견한 후 저는 원시 비콘 DLL의 기본 주소를 찾는 다르지만 유사한 방법을 개발했습니다. 이 방법은 다음에서 역방향으로 탐색할 수 있는 에그 헌터를 사용합니다: RIP . 이는 알려진 다음 위치에서 64비트 에그의 두 개의 반복된 인스턴스를 추적합니다: beacon.dll+0x50  원시 파일 오프셋.

주소 beacon.dll+0x50  은 이 위치가 '이 프로그램은 DOS 모드에서 실행할 수 없습니다' 배너의 위치이기 때문에 선택되었으며, 비콘을 반사적으로 로드할 때는 필요하지 않습니다.

Java Malleable PE 엔진에 쉽게 액세스할 수 없기 때문에 BokuLoader.cna  UDRL Aggressor 스크립트를 사용하여 0xB0C0ACDC  에그를 신호로 작성합니다. 아래 코드는 원시 비콘 DLL을 수정하여 에그를 포함시키는 방법을 보여줍니다.

원시 비콘 DLL에 에그를 작성하고 Cobalt Strike 스크립트 콘솔에 변경 사항을 표시하는 Aggressor 스크립트입니다.

원시 비콘 DLL에 에그를 작성하고 Cobalt Strike 스크립트 콘솔에 변경 사항을 표시하는 Aggressor 스크립트입니다.

UDRL 코드는 UDRL 스크립트에 의해 원시 비콘 DLL에 기록된 에그 값을 알고 있어야 합니다. 에그가 알려진 상태에서 에그 헌터는 아래 코드와 같이 에그의 두 인스턴스를 역방향으로 검색합니다.

64비트 에그의 두 인스턴스를 거꾸로 검색하는 에그 헌터를 위한 Intel x64 어셈블리 코드입니다.

64비트 에그의 두 인스턴스를 거꾸로 검색하는 에그 헌터를 위한 Intel x64 어셈블리 코드입니다.

  • UDRL 어그레서 스크립트와 UDRL C 코드 모두 다른 에그를 사용하도록 수정할 수 있습니다.

이제 MZ 및 PE 헤더가 더 이상 사용되지 않으므로 UDRL Aggressor 스크립트에서 이를 제거할 수 있습니다.

원시 비콘 DLL의 헤더에 있는 DOS 배너의 MZ, PE 및 사용되지 않는 바이트를 마스킹하는 공격자 스크립트입니다.

원시 비콘 DLL의 헤더에 있는 DOS 배너의 MZ, PE 및 사용되지 않는 바이트를 마스킹하는 공격자 스크립트입니다.

호출 반사 로더 스텁에서 원시 비콘 DLL 기본 주소 얻기

원시 비콘 DLL의 기본 주소를 검색하는 또 다른 Cobalt Strike 전용 방법도 있습니다. 위에서 살펴본 바와 같이, 호출 반사 로더 스텁의 초기 바이트는 원시 비콘 DLL의 기본 주소를 RDI  레지스터에 저장한 후 반사 로더를 호출합니다. 일부 에그의 경우 RIP 에서 역추적하는 것이 아닌, 반사 로더 코드의 시작 부분에 있는 RDI  레지스터에서 간단히 값을 얻을 수 있습니다.

디버거에서 이를 더 자세히 살펴보기 위해 비콘을 생성하고 중단점(0xCC )을 앞에 추가하고 x64dbg에서 비콘을 엽니다. 중단점이 앞에 붙었으므로 원시 비콘의 기본 주소는 할당된 메모리의 +1  입니다. 위에서 보았듯이, 호출 반사 로더 스텁은RIP 원시 비콘 DLL의 기본 주소를 얻기 위해 상대 주소를 사용합니다.

반사 로더를 호출하기 전에 원시 비콘 DLL 기본 주소가 RDI 레지스터에 저장되어 있는지 확인하기 위해 호출 반사 로더 스텁을 단계별로 실행하는 스크린샷.

반사 로더를 호출하기 전에 원시 비콘 DLL 기본 주소가 RDI 레지스터에 저장되어 있는지 확인하기 위해 호출 반사 로더 스텁을 단계별로 실행하는 스크린샷.

다음은 호출 반사 로더 스텁에서 원시 비콘 DLL의 기본 주소를 가져오는 방법을 보여주는 작동 예시입니다.

RDI 레지스터에서 원시 비콘 DLL 기본 주소를 가져오기 위한 인라인 어셈블리 C 코드입니다.

RDI 레지스터에서 원시 비콘 DLL 기본 주소를 가져오기 위한 인라인 어셈블리 C 코드입니다.

2단계: 비콘 DLL의 헤더 구문 분석

원시 비콘 DLL의 기본 주소를 사용하면 이제 비콘을 프로세스의 가상 주소 공간에 로드하는 데 필요한 값을 가져올 수 있습니다.

아래 표에는 원시 비콘 DLL의 헤더에서 필요한 값, 찾을 위치 및 유형이 나열되어 있습니다.

비콘 DLL을 로드하는 데 유용한 원시 비콘 DLL 헤더의 값을 나열하는 테이블.

비콘 DLL을 로드하는 데 유용한 원시 비콘 DLL 헤더의 값을 나열하는 테이블.

회피

비콘 DLL을 로드하는 데 헤더의 모든 내용이 필요한 것은 아닙니다. 필수 값은 재포장하거나 난독화할 수 있습니다. 필요하지 않은 값은 제거하거나 무작위로 지정할 수 있습니다.

3단계: 가상 비콘에 메모리 할당

원시 비콘 DLL의 헤더에서SizeOfImagef 을 파악하면 이 크기의 메모리를 할당해야 합니다. 이 메모리 공간에는 가상 비콘 DLL이 저장됩니다.

가상 비콘 DLL의 메모리를 할당하는 데 다양한 방법을 사용할 수 있습니다. 방법에 따라 다양한 유형의 메모리를 사용합니다. Cobalt Strike의 기본 반사 로더가 지원하는 다양한 방법은 다음과 같습니다.

가상 비콘 DLL에 대한 Cobalt Strike 메모리 할당 옵션을 보여주는 테이블.

가상 비콘 DLL에 대한 Cobalt Strike 메모리 할당 옵션을 보여주는 테이블.

회피

이는 UDRL을 통해 한 걸음 더 나아갈 수 있습니다. 대신 이러한 함수의 NTAPI 버전을 사용할 수 있습니다. 또한 NTAPI 함수는 직간접적인 시스템 호출을 통해 호출될 수 있으며, 이는 회피 기능을 강화하는 데 도움이 될 수도 있고 도움이 되지 않을 수도 있습니다.

Cobalt Strike Malleable C2 프로파일에서 할당자 메서드가 VirtualAlloc  으로 설정되면 현재 BokuLoader 프로젝트가 NtAllocateVirtualMemory  에 대한 시스템에 직접 호출을 사용하여 가상 비콘 DLL에 대한 메모리를 할당합니다.

직접 시스템 호출을 보여주는 BokuLoader 프로젝트의 코드 샘플은 가상 비콘 DLL에 대한 메모리를 할당하는 데 사용됩니다.

직접 시스템 호출을 보여주는 BokuLoader 프로젝트의 코드 샘플은 가상 비콘 DLL에 대한 메모리를 할당하는 데 사용됩니다.

  • 시스템 호출 번호는 HellsGate 메서드를 사용하여 검색합니다.
  • 시스템 호출 스텁에 userland hook이 존재하면 HalosGate 메서드가 사용됩니다.

아래 이미지는 HellsGate 및 HalosGate 메서드를 사용하여 시스템 호출 번호를 결정하는 코드 예제를 보여줍니다.

프로세스에서 시스템 호출을 검색하는 방법을 보여주는 BokuLoader 프로젝트의 코드 샘플입니다.

프로세스에서 시스템 호출을 검색하는 방법을 보여주는 BokuLoader 프로젝트의 코드 샘플입니다.

4단계: 가상 메모리 공간에 섹션 로드하기

이제 가상 비콘 DLL에 대한 메모리를 할당했으므로 원시 비콘 DLL에 있는 비콘의 섹션을 원시 파일 오프셋에서 상대적 가상 오프셋에 있는 할당된 메모리로 복사해야 합니다.

다음을 사용하여 메모리를 할당하면READWRITE 섹션 .text 의 주소와 해당 크기를 추적해야 합니다. 가상 비콘 DLL의 진입점을 호출하기 전에 .text 섹션의 메모리 보호를 실행 가능으로 변경해야 합니다.

또한 READWRITE_EXECUTE 로 메모리를 할당하면 반사 로딩 프로세스가 간소화되지만, 보안 솔루션의 탐지 가능성이 높아집니다.

다음은 BokuLoader 프로젝트의 간소화된 코드 예시로, 이를 보여줍니다.

원시 비콘 DLL에서 가상 비콘 DLL로 복사된 섹션을 보여주는 BokuLoader 프로젝트의 코드 샘플.

원시 비콘 DLL에서 가상 비콘 DLL로 복사된 섹션을 보여주는 BokuLoader 프로젝트의 코드 샘플.

회피

로딩 섹션과 관련된 몇 가지 회피 기능은 다음과 같습니다.

  • 비콘 헤더를 가상 비콘 DLL에 복사하지 않습니다.
  • 가상 비콘 DLL에서 헤더 파일이 저장될 메모리 공간을 해제합니다.

공개 BokuLoader 프로젝트에서 비콘 DLL의 헤더는 원시 비콘 DLL에서 가상 비콘 DLL로 복사되지 않습니다. 현재 가상 비콘 DLL의 첫 번째 0x1000  바이트는 null입니다(0x00‘s ). 테스트 결과, 비콘이 가상 메모리에 제대로 로드된 후에는 비콘이 헤더에 의존하지 않습니다. 헤더 복사를 피하면 인메모리 스캐너를 회피하는 데 도움이 될 수 있지만, 이러한 null 바이트는 잠재적인 탐지 지점이 될 수도 있습니다.

또 다른 회피 기회는 UDRL Aggressor 스크립트가 섹션을 암호화하도록 하는 것입니다. 섹션은 UDRL과 UDRL Aggressor 스크립트 간에 공유되는 키를 사용하여 UDRL에 의해 메모리에서 해독될 수 있습니다.

5단계: DLL 종속성 로드

x64 HTTP/S 비콘이 제대로 작동하려면 4개의 DLL이 필요합니다. 이러한 DLL이 현재 프로세스에 로드되지 않은 경우 반사 로더가 이를 로드해야 합니다.

네 개의 DLL은 HTTP/S 비콘 DLL의 가져오기 디렉터리에 나열됩니다.

비콘 DLL의 가져오기 디렉터리에 있는 DLL을 나열하는 PE-Bear의 스크린샷.

비콘 DLL의 가져오기 디렉터리에 있는 DLL을 나열하는 PE-Bear의 스크린샷.

내장된 Cobalt Strike 반사 로더는 DLL 로딩을 위해 kernel32.LoadLibraryA API를 사용합니다.

회피

DLL 로딩은 다양한 운영 보안 고려 사항과 함께 다양한 방법으로 달성할 수 있습니다. 몇 가지 방법은 다음과 같습니다.

프로세스에 DLL이 이미 있는 경우에도 위의 Windows API를 사용하여 DLL 기본 주소를 가져올 수 있지만, 이로 인해 원치 않는 탐지 경고가 트리거될 수 있습니다.

또는 PEB는 

<a title="https://learn.microsoft.com/kr-ko/windows/win32/api/winternl/ns-winternl-peb_ldr_data" href="https://learn.microsoft.com/kr-ko/windows/win32/api/winternl/ns-winternl-peb_ldr_data">_PEB_LDR_DATA</a>

구조체에 대한 포인터를 가집니다. 내부에는 프로세스에 로드된 모든 DLL과 그 관련 정보의 연결된 목록이 있습니다(

InMemoryOrderModuleList

). BokuLoader는 이를 활용하여 DLL 정보를 검색하여 불필요한 API 호출을 피할 수 있습니다.

DLL이InMemoryOrderModuleList 에 존재하지 않는 경우 현재 BokuLoader는 NTDLL.LdrLoadDll  API를 사용하여 내장된 Windows DLL 로더를 활용하여 DLL 종속성을 메모리에 로드합니다.

중첩된 반사 로딩은 반사 로더가 일반적으로 DLL을 프로세스에 등록하지 않기 때문에 DLL 종속성을 로드하는 데 쉽게 사용할 수 없습니다. DLL 외부의 코드는 반사적으로 로드된 DLL을 제대로 사용할 수 없습니다. DarkLoadLibrary 프로젝트는 커널 이미지 로드 이벤트를 트리거하지 않고 DLL을 메모리에 제대로 로드할 수 있을 수 있습니다.

InMemoryOrderModuleList를 탐색하여 로드된 DLL의 기본 주소를 확인하는 방법을 보여주는 BokuLoader 프로젝트의 코드 샘플.

InMemoryOrderModuleList를 탐색하여 로드된 DLL의 기본 주소를 확인하는 방법을 보여주는 BokuLoader 프로젝트의 코드 샘플.

6단계: 가져오기 주소 테이블 확인

필요한 DLL이 프로세스에 로드되면 가져오기 디렉터리에 나열된 API를 확인해야 합니다. 그런 다음, API 주소를 가상 비콘 DLL의 IAT(주소 가져오기 테이블)에 기록해야 합니다. 이렇게 하면 비콘이 다음과 같은 API를 호출해야 할 때 어떤 주소로 이동할지 알 수 있습니다. WININET.HttpSendRequest

가져오기 항목은 서수 또는 이름 문자열을 통해 확인해야 합니다.

아래 이미지에서 Cobalt Strike 비콘 DLL이 가져오기 항목에 서수와 이름 문자열의 조합을 사용하는 것을 볼 수 있습니다.

비콘 DLL에 대한 일부 가져오기 항목을 보여주는 PE 베어의 스크린샷은 서수로 해결해야 합니다.

비콘 DLL에 대한 일부 가져오기 항목을 보여주는 PE 베어의 스크린샷은 서수로 해결해야 합니다.

내장된 Cobalt Strike 반사 로더는 Kernel32.GetProcAddress  API를 사용하여 가져오기 항목에 대한 가상 주소를 확인합니다.

회피

API 주소를 확인하는 몇 가지 회피 방법은 다음과 같습니다.

  • 다음에 대한 사용자 정의 코드 구현: GetProcAddress
  • NTDLL.LdrGetProcedureAddress

BokuLoader는GetProcAddress 의 사용자 정의 코드 구현을 사용하여 가져오기 항목의 주소를 확인하고 이름 문자열과 서수 모두를 처리합니다.

그리고 NTDLL.LdrGetProcedureAddress 는 이름 문자열과 서수를 모두 처리할 수 있습니다. 가져오기 항목에 대해 반환된 주소가 다른 DLL에 대한 전달자인 경우 BokuLoader는 NTDLL.LdrGetProcedureAddress 로 기본 설정되어 전달자를 확인합니다.

IAT를 작성할 때 의도한 API 가상 주소가 아닌 구현한 후크 함수의 가상 주소를 작성하여 후킹을 구현할 수 있습니다. IAT의 주소가 호출될 때 예상 출력이 비콘으로 반환되는 한, 비콘으로 돌아오기 전에 추가 코드를 실행할 수 있습니다. 미래 게시물과 공개 BokuLoader 릴리스에서는 고급 회피 기능을 위해 IAT 후킹을 활용하는 방법을 보여줍니다.

최근 릴리스를 통해 공개 BokuLoader 프로젝트는 사용자 정의 구현이 있는 Cobalt Strike C2 프로파일의 obfuscate Malleable PE 기능을 지원합니다. 다음에 위치한 마스킹 키를 수정함으로써BokuLoader.cna UDRL Aggressor 스크립트를 사용하는 경우, 자체 싱글바이트 XOR 키를 선택하여 난독화를 개선할 수 있습니다.

운영 보안과 관련하여 패턴 매칭 엔진이 싱글바이트 XOR 마스크를 무차별 대입할 수 있다는 점을 아는 것이 중요합니다. 향후 게시물에서는 패턴 매칭을 극복하기 위해 비콘을 난독화하는 Cobalt Strikes Aggressor 스크립팅 기능을 사용하여 자체적인 Malleable PE 엔진을 만드는 방법을 보여줄 것입니다.

7단계: 재배치 확인

비콘 DLL에는 실행 전에 해결하고 가상 비콘 DLL의 기본 재배치 테이블에 기록해야 하는 많은 재배치 정보가 있습니다.

PE-Bear에서 볼 수 있듯이, 비콘 DLL은 기본적으로 다음과 같은 이미지 기본 주소를 가집니다: 0x180000000 :

비콘 DLL의 이미지 기본 주소를 보여주는 PE-Bear의 스크린샷.

비콘 DLL의 이미지 기본 주소를 보여주는 PE-Bear의 스크린샷.

재배치를 작성하기 전에, 가상 비콘 DLL의 기본 주소와 하드코딩된 기본 주소 간의 델타를 계산해야 합니다.

예를 들어 가상 비콘 DLL의 기본 주소가 0x7FFC44FE0000 이라고 가정해 보겠습니다. 가상 비콘 DLL의 기본 주소에서 하드코딩된 기본 주소를 빼서 다음의 기본 주소 델타를 구합니다.

기본 주소 델타를 가져오는 스크린샷

다음으로, 기본 재배치 테이블의 각 재배치 항목에 대한 가상 주소를 결정하기 위해 하드코딩된 재배치 항목 주소에 기본 주소 델타를 추가하여 가상 비콘 DLL 내의 재배치를 결정합니다.

아래 이미지에서 비콘 재배치 항목이 리틀 엔디안 형식으로 거꾸로 작성된 것을 볼 수 있습니다.

일부 재배치 항목이 리틀 엔디안 형식으로 존재함을 보여주는 PE-bear의 스크린샷.

일부 재배치 항목이 리틀 엔디안 형식으로 존재함을 보여주는 PE-bear의 스크린샷.

이 재배치 항목의 하드코딩된 주소는 다음과 같습니다: 0x1800341C8 .

이 주소를 기본 주소 델타에 추가하여 가상 비콘 DLL에 존재하는 재배치를 위한 다음의 가상 주소를 얻습니다.

기본 주소 델타에 주소를 추가하여 가상 비콘 DLL에 있는 위치 변경을 위한 가상 주소를 가져오는 스크린샷:

각 재배치 항목에 대해 유형이 다음인지 확인해야 합니다

<a title="https://learn.microsoft.com/kr-ko/windows/win32/debug/pe-format" href= " https://learn.microsoft.com/kr-ko/windows/win32/debug/pe-format" > IMAGE_REL_BASED_DIR64 (0xA)</a>

. false인 경우 재배치 작성을 건너뜁니다.

가상 비콘 DLL 내에 존재하는 재배치의 가상 주소를 결정한 후에는 이를 하드코딩된 재배치 항목 주소가 있는 메모리 공간에 기록합니다.

PE 재배치 방법에 대해 자세히 알아보려면 공개 BokuLoader 프로젝트의 doRelocations 함수 코드를 확인하세요. 이 블로그 게시물을 공개하기 전에 기술적인 세부 사항을 알고 싶어하는 다른 사람들을 돕기 위해 어셈블리 코드였던 재배치 코드를 사람이 읽기 쉬운 C 코드로 변경했습니다.

8단계: 비콘 실행

비콘 실행은 세 단계로 나눌 수 있습니다.

  • 가상 비콘 DLL 섹션에 올바른 메모리 권한이 있는지 확인합니다.
  • 가상 비콘 DLL을 초기화합니다.
  • 가상 비콘 DLL의 진입점을 호출합니다.

가상 비콘을 실행 가능으로 설정

가상 비콘 DLL에 할당한 메모리가 READWRITE_EXECUTE 인 경우 비콘이 충돌 없이 제대로 작동하도록 메모리 보호 기능을 변경할 필요가 없습니다.

가상 비콘 메모리를 실행 불가능으로 할당한 경우 (READWRITE ) 가상 비콘 DLL의 .text  섹션을 실행 가능으로 변경해야 합니다. 또한 .text  섹션의 위치와 가상 크기가 UDRL 기본 함수 내에 변수로 이전에 저장되어 있어야 합니다.

공개 BokuLoader 프로젝트에서 메모리 보호 변경은 NTProtectVirtualMemory 에 대한 직접 시스템 호출에서 수행됩니다(아래 코드 예시 참조).

가상 비콘 DLL의 .text 섹션을 실행 가능으로 변경하는 것을 보여주는 BokuLoader의 코드 샘플.

가상 비콘 DLL의 .text 섹션을 실행 가능으로 변경하는 것을 보여주는 BokuLoader의 코드 샘플.

이러한 .data  섹션(가상 비콘 DLL 내)에 다음 권한이 있어야 합니다: READWRITE . 섹션에 쓸 수 없는 경우 비콘 DLL이 실행 중에 충돌할 수 있습니다.

가상 비콘 DLL 초기화

가상 비콘 DLL이 제대로 작동하려면 먼저 가상 비콘 DLL의 진입 지점을 호출하여 초기화해야 합니다. 첫 번째 인수는 가상 비콘 DLL의 기본 주소입니다. 두 번째 인수는 fwdReason  이며, 다음으로 설정되어야 합니다: DLL_PROCESS_ATTACH (1) .

가상 비콘 DLL을 초기화하는 BokuLoader 프로젝트의 코드 샘플.

가상 비콘 DLL을 초기화하는 BokuLoader 프로젝트의 코드 샘플.

가상 비콘 DLL 실행

가상 비콘 DLL을 초기화한 후 가상 비콘의 진입점을 호출 반사 로더 스텁으로 반환하거나 다음을 사용하여 UDRL에서 가상 비콘 DLL의 진입점을 호출할 수 있습니다. 이때 fwdReason  이 다음으로 설정됩니다: 0x4 .

일반적인 DLL( hinstDLL 을(를) 다음으로 설정했습니다.

<a href="https://learn.microsoft.com/kr-ko/windows/win32/dlls/dllmain">DLLMAIN</a>

에 대한 첫 번째 인수가 가상 DLL의 기본 주소임)과 달리, 비콘은 원시 비콘 DLL의 기본 주소를 기대합니다. 이 기본 주소가 제공되지 않으면 일부 Malleable PE 회피 기능이 작동하지 않을 수 있습니다.

가상 비콘 DLL을 실행하는 두 가지 방법을 보여주는 BokuLoader 프로젝트의 코드 샘플입니다.

가상 비콘 DLL을 실행하는 두 가지 방법을 보여주는 BokuLoader 프로젝트의 코드 샘플입니다.

마무리 생각

이 블로그 게시물이 레드팀과 블루팀 모두 Cobalt Strike와 반사 로딩 프로세스를 더 잘 이해하는 데 도움이 되기를 바랍니다. 반사적 로딩을 통해 활용할 수 있는 회피 기회는 여전히 많이 있습니다. 이러한 개념에 대한 더 깊은 이해로 조직은 사이버 위협에 대한 성공적인 방어를 위해 더 잘 준비할 수 있습니다.

이 시리즈의 향후 게시물에서는 UDRL을 현재 Cobalt Strike 회피 기능과 통합하고, 공개 BokuLoader에 이미 존재하는 문서화되지 않은 회피 기능 및 아직 대중에게 공개되지 않은 고급 기능에 대해 자세히 설명합니다. UDRL 개발을 통해 Cobalt Strike 게임을 한 단계 끌어올리는 방법을 배울 수 있는 더 자세한 정보와 기술을 기대해주세요!

Mixture of Experts | 12월 12일, 에피소드 85

AI 디코딩: 주간 뉴스 요약

세계적인 수준의 엔지니어, 연구원, 제품 리더 등으로 구성된 패널과 함께 불필요한 AI 잡음을 차단하고 실질적인 AI 최신 소식과 인사이트를 확인해 보세요.