
x86, x64, 또는 AMD64+x86 포지션 독립적 셸코드를 생성하여, 메모리에서 .NET 어셈블리, PE 파일 및 기타 Windows 페이로드를 로드하고 매개변수와 함께 실행합니다.

현재 버전: v1.1
Donut은 VBScript, JScript, EXE, DLL 파일 및 dotNET 어셈블리를 메모리에서 실행할 수 있게 해주는 위치 독립적 코드입니다. Donut으로 생성된 모듈은 HTTP 서버에서 스테이징하거나 로더 자체에 직접 포함시킬 수 있습니다. 모듈은 선택적으로 Chaskey 블록 암호와 128비트 무작위 생성 키를 사용하여 암호화됩니다. 파일이 메모리에 로드되어 실행된 후에는 원본 참조가 지워져 메모리 스캐너를 탐지하기 어렵게 합니다. 생성기와 로더는 다음 기능을 지원합니다:
Linux 및 Windows용 동적 및 정적 라이브러리가 있으며, 이를 자신의 프로젝트에 통합할 수 있습니다. 또한 Python 확장 빌드 및 사용에 대한 자세한 내용을 확인할 수 있는 Python 모듈도 있습니다.
Donut은 지원되는 각 파일 유형에 대한 개별 로더를 포함합니다. dotNET EXE/DLL 어셈블리의 경우, Donut은 Unmanaged CLR Hosting API를 사용하여 공용 언어 런타임(CLR)을 로드합니다. CLR이 호스트 프로세스에 로드되면 새 애플리케이션 도메인이 생성되어 폐기 가능한 AppDomain에서 어셈블리를 실행할 수 있습니다. AppDomain이 준비되면 dotNET 어셈블리는 AppDomain.Load_3 메서드를 통해 로드됩니다. 마지막으로, EXE의 진입점 또는 사용자가 지정한 DLL의 public 메서드가 추가 매개변수와 함께 호출됩니다. Unmanaged CLR Hosting API에 대한 자세한 내용은 MSDN 문서를 참조하세요. CLR 호스트의 독립 실행형 예제는 여기 코드를 참조하세요.
VBScript 및 JScript 파일은 IActiveScript 인터페이스를 사용하여 실행됩니다. Windows Script Host(wscript/cscript)가 제공하는 일부 메서드에 대한 최소한의 지원도 있습니다. 독립 실행형 예제는 여기 코드를 참조하세요. 더 자세한 설명은 JavaScript, VBScript, JScript 및 XSL의 메모리 내 실행을 읽어보세요.
관리되지 않는 또는 네이티브 EXE/DLL 파일은 지연 가져오기, TLS 및 명령줄 패치를 지원하는 사용자 정의 PE 로더를 사용하여 실행됩니다. 재배치 정보가 있는 파일만 지원됩니다. 자세한 내용은 DLL의 메모리 내 실행을 읽어보세요.
로더는 AMSI 및 WLDP를 비활성화하여 메모리에서 실행되는 악성 파일 탐지를 회피하는 데 도움을 줄 수 있습니다. 자세한 내용은 레드 팀이 .NET 동적 코드에 대해 AMSI 및 WLDP를 우회하는 방법을 읽어보세요. 또한 aPLib 또는 RtlDecompressBuffer API를 사용하여 메모리에서 파일 압축 해제를 지원합니다. 자세한 내용은 데이터 압축을 읽어보세요.
v1.0부터 ETW도 우회됩니다. AMSI/WLDP와 마찬가지로, 기본 우회를 자신의 것으로 교체할 수 있는 모듈식 시스템입니다. 기본 우회는 XPN의 연구에서 파생되었습니다. 자세한 내용은 .NET 숨기기 - ETW를 읽어보세요.
기본적으로 로더는 관리되지 않는 PE의 PE 헤더(기본 주소부터 `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`까지)를 덮어씁니다. 디코이 모듈이 사용되지 않으면(모듈 오버로딩) PE 헤더는 0으로 설정됩니다. 디코이 모듈이 사용되면 디코이 모듈의 PE 헤더가 페이로드 모듈의 헤더를 덮어쓰는 데 사용됩니다. 이는 메모리 내 모듈의 PE 헤더와 디스크에 있는 파일을 비교하는 탐지를 방지하기 위함입니다. 사용자는 모든 PE 헤더를 원래 상태로 유지하도록 요청할 수 있습니다. 이는 페이로드 모듈이 포함된 PE 리소스 조회와 같이 PE 헤더에 접근해야 하는 시나리오에서 유용합니다.
생성기 사용 및 Donut이 전술에 미치는 영향에 대한 자세한 설명은 Donut - .NET 어셈블리를 셸코드로 삽입을 읽어보세요. 로더에 대한 자세한 내용은 메모리에서 .NET 어셈블리 로드를 읽어보세요.
내부 구조에 대해 더 알고 싶은 분들은 개발자 노트를 참조하세요.
두 가지 유형의 빌드가 있습니다. Donut을 디버깅하려면 여기 문서를 참조하세요. 그렇지 않다면 릴리스 빌드를 위해 계속 읽으세요.
Windows 명령 프롬프트 또는 Linux 터미널에서 저장소를 클론합니다.
git clone http://github.com/thewover/donut.git
다음 단계는 운영 체제와 사용할 컴파일러에 따라 다릅니다. 현재 Donut의 생성기 및 로더 템플릿은 Microsoft Visual Studio 2019 및 MingGW-64 모두에서 성공적으로 컴파일할 수 있습니다. 자신의 C/C++ 프로젝트에서 라이브러리를 사용하려면 여기 제공된 예제를 참조하세요.
로더 템플릿, 동적 라이브러리 donut.dll, 정적 라이브러리 donut.lib 및 생성기 donut.exe를 생성하려면 x64 Microsoft Visual Studio 개발자 명령 프롬프트를 시작하고 Donut 저장소를 클론한 디렉터리로 변경한 후 다음을 입력하세요:
nmake -f Makefile.msvc
Windows 또는 Linux에서 MinGW-64를 사용하여 동일한 작업을 수행하려면 Donut 저장소를 클론한 디렉터리로 변경한 후 다음을 입력하세요:
make -f Makefile.mingw
동적 라이브러리 donut.so, 정적 라이브러리 donut.a 및 생성기 donut을 생성하려면 Donut 저장소를 클론한 디렉터리로 변경하고 간단히 make를 입력하세요.
Donut은 Python 모듈로 설치 및 사용할 수 있습니다. 소스에서 설치하려면 Python3용 pip가 필요합니다. 먼저, Linux 터미널 또는 Microsoft Visual Studio 명령 프롬프트에서 다음 명령을 실행하여 이전 버전의 donut-shellcode가 설치되지 않았는지 확인하세요.
pip3 uninstall donut-shellcode
이전 버전이 더 이상 설치되지 않았음을 확인한 후 다음 명령을 실행하세요.
pip3 install .
PyPi 저장소에서 가져와 Donut을 Python 모듈로 설치할 수도 있습니다.
pip3 install donut-shellcode
자세한 내용은 Python 확장 빌드 및 사용을 참조하세요.
Docker 컨테이너 빌드.
docker build -t donut .
Donut 실행.
docker run -it --rm -v "${PWD}:/workdir" donut -h
Donut에는 별도로 빌드할 수 있는 몇 가지 다른 실행 파일이 포함되어 있습니다. 여기에는 "hash.exe", "encrypt.exe", "inject.exe", "inject_local.exe"가 있습니다. 처음 두 개는 셸코드 생성에 사용됩니다. 나머지 두 개는 Donut 셸코드 테스트를 지원하기 위해 제공됩니다. "inject.exe"는 원시 바이너리 파일(loader.bin)을 PID 또는 프로세스 이름으로 프로세스에 주입합니다. "inject_local.exe"는 원시 바이너리 파일을 자신의 프로세스에 주입합니다.
이러한 지원 실행 파일을 별도로 빌드하려면 MSVC makefile을 사용할 수 있습니다. 예를 들어, Donut 셸코드를 테스트하기 위해 "inject_local.exe"를 빌드하려면 다음을 실행할 수 있습니다.
nmake inject_local -f Makefile.msvc
Donut의 각 릴리스 버전에 대해 컴파일된 실행 파일이 포함된 태그가 제공되었습니다.
현재 사용 가능한 다른 생성기가 두 개 더 있습니다.
다음 표는 명령줄 생성기에서 지원하는 스위치를 나열합니다.
Donut이 페이로드를 성공적으로 로드하려면 충족해야 하는 몇 가지 특정 요구 사항이 있습니다.
Cygwin 실행 파일은 호스트 프로세스가 디스크에서 실행 중이라고 가정하는 초기화 루틴을 사용합니다. 메모리에서 실행하는 경우 호스트 프로세스가 충돌할 가능성이 높습니다.
Donut과 함께 제공되는 네 가지 동반 프로젝트가 있습니다:
더 많은 유형의 페이로드에 대한 지원을 추가하거나, 기능 세트를 변경하거나, Donut을 기존 도구에 통합하고 싶을 수 있습니다. 개발자 문서를 제공했습니다. 추가 기능은 독자의 연습 과제로 남깁니다. 제안 사항:
Donut에 대한 질문이나 의견이 있으면 BloodHound Gang Slack의 #Donut 채널에 참여하세요.
당사는 이 소프트웨어나 기술의 오용에 대해 책임을 지지 않습니다. Donut은 레드 팀이 적을 모방하고 방어자가 분석 및 완화 조치를 구축할 수 있는 참조 프레임워크를 제공하기 위해 셸코드를 통한 CLR 주입 및 메모리 내 로딩의 데모로 제공됩니다. 이는 필연적으로 맬웨어 작성자와 위협 행위자가 이를 오용할 위험이 있습니다. 그러나 순 이익이 위험보다 크다고 생각합니다. 이것이 올바르길 바랍니다. EDR 또는 AV 제품이 서명 또는 동작 패턴을 통해 Donut을 탐지할 수 있는 경우, 서명이나 탐지 방법에 대응하기 위해 Donut을 업데이트하지 않습니다. 기분이 상하지 않도록 요청하지 마십시오.
| 스위치 | 인수 | 설명 |
|---|---|---|
| -a | arch | 로더 대상 아키텍처: 1=x86, 2=amd64, 3=x86+amd64(기본값). |
| -b | level | AMSI/WLDP 우회 동작: 1=없음, 2=실패 시 중단, 3=실패 시 계속.(기본값) |
| -k | headers | PE 헤더 보존: 1=덮어쓰기(기본값), 2=모두 유지 |
| -j | decoy | 모듈 오버로딩을 위한 디코이 모듈의 선택적 경로. |
| -c | class | 선택적 클래스 이름 (.NET DLL에 필요). 네임스페이스 포함 가능: 예 namespace.class |
| -d | name | .NET용 AppDomain 이름. 엔트로피가 활성화되면 무작위로 생성됩니다. |
| -e | level | 엔트로피 수준: 1=없음, 2=무작위 이름 생성, 3=무작위 이름 생성 + 대칭 암호화 사용(기본값) |
| -f | format | 파일로 저장되는 로더의 출력 형식: 1=바이너리(기본값), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=16진수 |
| -m | name | DLL의 선택적 메서드 또는 함수 (.NET DLL에는 메서드 필요) |
| -n | name | HTTP 스테이징용 모듈 이름. 엔트로피가 활성화되면 무작위로 생성됩니다. |
| -o | path | Donut이 로더를 저장할 위치를 지정합니다. 기본값은 현재 디렉터리의 "loader.bin"입니다. |
| -p | parameters | 따옴표 안의 DLL 메서드/함수 또는 EXE에 대한 선택적 매개변수/명령줄. |
| -r | version | CLR 런타임 버전. 기본적으로 MetaHeader가 사용되며, 사용 가능한 버전이 없으면 v4.0.30319가 사용됩니다. |
| -s | server | Donut 모듈을 호스팅할 HTTP 서버의 URL. 다음 형식으로 자격 증명을 제공할 수 있습니다: https://username:[email protected]/ |
| -t | 관리되지 않는/네이티브 EXE의 진입점을 스레드로 실행하고 스레드가 종료될 때까지 기다립니다. | |
| -w | 명령줄이 UNICODE 형식으로 관리되지 않는 DLL 함수에 전달됩니다. (기본값은 ANSI) | |
| -x | option | 로더가 종료되는 방식을 결정합니다: 1=스레드 종료(기본값), 2=프로세스 종료, 3=종료 또는 정리하지 않고 무기한 차단 |
| -y | addr | 로더에 대한 새 스레드를 생성하고 호스트 프로세스의 실행 파일에 대한 상대 오프셋 주소에서 계속 실행합니다. 제공된 값이 오프셋입니다. 이 옵션은 donut 실행 완료 후 호스트 프로세스의 실행을 재개하려는 로더를 지원합니다. |
| -z | engine | 입력 파일 팩/압축: 1=없음, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman. 현재 마지막 세 가지는 Windows에서만 지원됩니다. |
| 도구 | 설명 |
|---|---|
| DemoCreateProcess | 테스트에 사용할 샘플 .NET 어셈블리. 각각 실행할 프로그램을 지정하는 두 개의 명령줄 매개변수를 받습니다. |
| DonutTest | Donut 테스트에 사용할 간단한 C# 셸코드 인젝터. 셸코드는 base64로 인코딩되어 문자열로 복사되어야 합니다. |
| ModuleMonitor | Donut 및 Cobalt Strike의 execute-assembly와 같은 도구에서 수행하는 CLR 주입을 탐지하는 개념 증명 도구. |
| ProcessManager | 공격적 운영자가 무엇에 주입할지 결정하고 방어적 운영자가 어떤 프로세스가 실행 중인지, 해당 프로세스의 속성 및 CLR 로드 여부를 확인하는 데 사용할 수 있는 프로세스 검색 도구. |