DSCourier BOF
이것은 Dylan Davis와 Matthew Schramm의 DSCourier 프로젝트의 BOF 구현입니다. WinGet의 COM 인터페이스를 사용하여 Microsoft에서 서명하고 신뢰하는 프로세스에서 임의의 powershell 코드를 실행합니다. 전체 연구 블로그는 여기에서 확인할 수 있습니다.
내가 출시하는 대부분의 프로젝트와 달리, 이 도구는 운영 준비가 된 도구가 아니라 오히려 POC에 가깝습니다. 이 BOF를 쉽게 배포할 수 있도록 하는 데 방해가 되는 여러 문제를 발견한 후 더 이상 추진하지 않기로 결정했습니다. 코드는 거의 전부 엉성하게 작성되었습니다. 몇 가지 문제가 해결되지 않은 채 남아 있으며 아래에서 논의됩니다.
사용법
임의의 powershell 코드를 dist/rev.yml 파일에 넣으십시오. 기본적으로 원래 저장소의 간단한 powershell 역방향 셸이 포함되어 있습니다. 이를 사용하려면 기존 예제 내의 IP를 원하는 IP로 바꾸십시오.
powershell 역방향 셸 사용 예:


작동 방식 / 제한 사항
특별한 순서 없이, 이 도구와 관련된 몇 가지 문제/제한 사항입니다.
- COM 호출이 성공하려면 Microsoft.Management.Configuration.winmd 파일이 COM 호출을 수행하는 실행 파일과 동일한 디렉터리에 있어야 합니다. 이는 예를 들어 System32 프로세스를 속이기 위해 비워낸(hollowed-out) 프로세스에서 Beacon을 실행할 때 일반 사용자에게 쓰기 권한이 없기 때문에 즉각적인 문제를 발생시킵니다. 이를 해결하기 위해 파일 대신 %APPDATA%\temp에 드롭하고, winmd 파일 경로를 검색하는 WinTypes!RoGetMetaDataFile 함수를 인라인 후크로 연결하여 temp 경로 위치를 제공할 수 있도록 합니다. 이를 통해 winmd 파일을 읽고 COM 호출이 성공할 수 있지만, VirtualProtect 호출과 DLL 메모리 덮어쓰기가 발생하여 IOCs가 생성됩니다.
- #1에 이어, BOF를 실행한 후 winmd 파일이 Beacon 프로세스가 종료될 때까지 디스크에서 잠깁니다. 이를 해결하기 위해 잘 알려진 자체 삭제(self-delection) 기능을 추가하는 등 약간 시도해 보았지만 파일은 디스크에 잠긴 상태로 남아 있었습니다. 이 문제를 해결/우회할 수 있을 수도 있지만, 다른 사람이 추적할 문제입니다.
- 원래 연구에서 언급된 대로, WinGet 내에서 pwsh 리소스를 사용하기 때문에 conhost.exe 프로세스가 ConfigurationRemotingServer.exe 아래에서 생성됩니다. Claude는 pwsh를 호출하는 대신 사용자 정의 바이너리 모듈을 리소스로 로드하는 것이 가능할 수 있으며, 이는 conhost 문제를 해결할 것이라고 제안했습니다. 그러나 이를 위해서는 추가 파일을 디스크에 드롭해야 하며, 작동시키지 못했습니다. 불가능할 수도 있습니다. 만약 가능하다면, 일반 .NET dll을 디스크에 드롭하여 ConfigurationRemotingServer.exe에 로드되고 전달된 셸코드/매개변수 등을 실행할 수 있는 길이 열립니다.
- 이 BOF는 필요한 COM 인터페이스의 Async 버전을 구현합니다. Sync 버전을 사용하면 ConfigurationRemotingServer.exe 프로세스가 완료될 때까지 Beacon이 중단되거나 콜백되지 않습니다. 간단한 역방향 셸 예제의 경우 셸이 종료될 때까지 Beacon이 다시 체크인하지 않음을 의미합니다. Async 인터페이스로 전환하면 이 문제가 방지되지만 일부 타이밍 문제가 발생합니다. 특정 호출 사이를 지연시키기 위해 실제로 작동하는 하드코딩된 3초 지연이 있지만, 이는 물론 올바른 구현 방법이 아닙니다.
- COM 인터페이스 정의는 GitHub에서 winget-cli .msixbundle을 다운로드하고, 추출하고, .msix를 추출하고, .winmd 파일을 찾아서 얻었습니다. 그런 다음 winmdidl.exe를 사용하여 IDL 파일을 추출했습니다. 그런 다음 midlrt.exe를 사용하여 IDL을 헤더/.c 파일로 변환했으며, Claude에 의해 필요한 정의만 포함하도록 파싱되었습니다. 여전히 코드가 엉망입니다. 이 Microsoft 링크가 이 과정을 더 잘 이해하는 데 도움이 될 것입니다.
- 코드는 일반적으로 POC 단계를 벗어나지 못했기 때문에 약간 엉망입니다.
- BOF가 성공하려면 대상 머신에서
winget configure --enable 명령이 최소 한 번 실행되어야 합니다. 이 이유는 ConfigurationremotingServer.exe가 포함된 DotNet 디렉터리가 명령이 실행되거나 바이너리가 다운로드될 때까지 존재하지 않기 때문입니다. 이러한 파일은 C:\Program files\WindowsApps...에 위치하므로 낮은 권한 사용자가 쓸 수 없으며, BOF로 직접 디스크에 파일을 드롭하여 작동시킬 수도 없습니다.
- 조사해 본 결과, 이들은 DCOM 인터페이스가 아니라 단순 COM 인터페이스입니다. 따라서 다른 머신으로의 측면 이동을 위한 실행 가능한 원시 요소가 아닙니다.
- #7로 인해, 이것은 좋은/신뢰할 수 있는 초기 접근 방법이 아니라고 생각합니다. WinGet이 비활성화된 머신(원래 블로그 게시물 참조)에 도달하거나 configure --enable 명령이 실행되지 않은 경우, 완전히 차단됩니다. 사후 침투 목적으로는 가치가 있을 수 있지만, 코드를 생성/실행할 고정 프로세스이고 pwsh이므로 AMSI가 작동한다는 점에서 다소 제약이 있습니다.
컴파일
이 도구는 일반적인 BOF API 선언(예: bofdefs.h 파일) 없이 작성되었습니다. Matt Ehrnschwender의 이 블로그 게시물에 설명된 대로, objcopy를 사용하여 컴파일 후 BOF에 DLL$API 형식의 적절한 심볼을 패치할 수 있습니다.
저는 이 과정을 자동화하는 BOFPatcher라는 도구를 작성했습니다. 이를 통해 사용자는 번거로운 API 선언에 신경 쓰지 않고 일반 C로 BOF를 작성할 수 있습니다:

이 도구는 제 BOF Development and Tradecraft 강좌를 구매한 분들에게 제공됩니다.
BOFPatcher 도구는 이 저장소에 포함되어 있지 않지만, 이 도구의 Makefile은 objcopy를 호출하여 적절한 심볼 대체를 포함하는 imports_dscourier64.txt 파일을 전달함으로써 BOF를 사용 가능하게 만듭니다.
크레딧
- Dylan과 Matt의 훌륭한 작업. 앞으로 더 많은 것을 기대합니다!
- 대부분을 엉성하게 작성해준 Claude에게 감사합니다.