클라이언트: MacBook Moonlight
서버: Windows VM 10.10.0.20 Sunshine
게이트웨이: Linux tailscale0 → nftables FORWARD → 전용 NIC
Linux 기반 악성코드 분석 VM 격리망 · 1/5
구성 요약원격 접속 요구사항패킷 경로Windows VM 가상 디스플레이 설정Sunshine/Moonlight 허용 포트신규 연결과 응답 트래픽흐름별 허용·차단 정책패킷 및 counter 검증정리Sources작업 기록공식·프로젝트 문서시리즈 이동
구성 요약
Moonlight, Linux gateway, Sunshine의 실행 위치는 다음과 같다.
MacBook: Moonlight Client Linux: Tailscale subnet router + nftables gateway Windows VM 10.10.0.20: Sunshine Server + 분석 도구
Linux에는 Sunshine과 Moonlight를 설치하지 않았다. Linux는 Tailnet 패킷을 전용 NIC로 전달하고 nftables에서 허용 여부를 결정한다.
원격 접속 요구사항
악성코드는 Windows VM에서 실행한다. 화면 수신과 입력은 MacBook에서 처리한다. 물리 모니터가 없는 VM에는 Sunshine이 캡처할 가상 디스플레이가 필요하다.
에서 Wake-on-LAN까지 포함한 Windows 원격 운용을 고민했고, 에서 1소켓 6코어, 메모리 24GB의 Windows VM을 구성했다. 이후 에서 Virtual Display Driver와 MonitorSwapAutomation을 적용했다.
신규 Sunshine 세션은 MacBook에서 시작한다. 패킷은 Linux의 FORWARD hook을 거쳐 Windows VM에 도착한다.
패킷 경로
구성 요소 | 실행 위치 | 역할 |
Moonlight | MacBook | Windows 화면 수신과 입력 전달 |
Tailscale | MacBook·Linux | MacBook에서 Linux 게이트웨이까지 관리 터널 제공 |
nftables | Linux | Tailnet과 분석망 사이의 신규 흐름 심사 |
Sunshine | Windows VM 10.10.0.20 | 화면 캡처·인코딩·스트리밍 서비스 |
Virtual Display Driver | Windows VM | 물리 모니터가 없어도 캡처할 화면 생성 |
Windows VM 가상 디스플레이 설정
Windows VM은 CPU 1소켓 6코어, 메모리 24GB로 구성했고 ballooning을 활성화했다. 물리 모니터가 없으므로 Sunshine이 캡처할 디스플레이가 존재하지 않았다.
Virtual Display Driver로 두 번째 가상 화면을 만들고 Sunshine이 그 화면을 사용하도록 했다. MonitorSwapAutomation은 물리·가상 디스플레이 전환 과정의 불편을 줄이기 위한 보조 도구였다.
- Virtual Display Driver: itsmikethetech/Virtual-Display-Driver
- MonitorSwapAutomation: Nonary/MonitorSwapAutomation
- Sunshine 공식 저장소: LizardByte/Sunshine
Sunshine은 Virtual Display Driver가 만든 화면을 캡처하고, MacBook의 Moonlight가 영상과 입력 세션을 처리한다.
Sunshine/Moonlight 허용 포트
nftables에는 다음 포트 범위를 정의했다.
define S_TCP = { 47984-47990, 48010 } define S_UDP = { 47998-48010 }
S_TCP와 S_UDP는 서버에 실제 적용한 허용 범위다. 범위 안의 모든 포트가 항상 필수라는 뜻은 아니다. Sunshine 문서에는 HTTPS, HTTP, Web UI, RTSP, video, control, audio처럼 포트별 역할이 구분되어 있다. Sunshine Network configuration이 범위는 서버에 적용했던 화이트리스트이며 Sunshine의 필수 포트 목록과 동일하지 않다. 애플리케이션 버전과 스트리밍 채널을 고려해 공식 문서의 개별 포트보다 넓게 설정했다.
신규 연결과 응답 트래픽
Moonlight가 MacBook에서 Windows VM의 Sunshine으로 연결을 시작하면 신규 패킷은 다음 규칙을 통과한다.
iif $IF_TS oif $IF_INTERNAL ip daddr $VM_IP tcp dport $S_TCP counter accept iif $IF_TS oif $IF_INTERNAL ip daddr $VM_IP udp dport $S_UDP counter accept
Windows가 보내는 정상 응답은 별도의 역방향 신규 허용 규칙이 없어도 connection tracking으로 처리된다.
ct state { established, related } counter accept
패킷 흐름을 세션 기준으로 보면 다음과 같다.
1. MacBook Moonlight가 10.10.0.20 Sunshine으로 연결 시작 2. tailscale0 → Linux FORWARD → 전용 NIC 3. nftables가 목적지·포트 기준으로 신규 연결 허용 4. Windows의 응답은 established 상태로 복귀
최종 ruleset에는 Windows VM이 Tailnet의 동일 목적 포트로 신규 연결을 시작하는 역방향 예외도 있다. 이 예외는 Sunshine 응답용
established 규칙과 별개의 신규 연결 규칙이다.흐름별 허용·차단 정책
Sunshine 세션과 Windows VM의 일반 라우팅은 다음과 같이 분리했다.
흐름 | 결과 | 의미 |
MacBook → Windows Sunshine | ALLOW | 원격 관리 경로 |
Windows → 같은 세션의 응답 | ALLOW | stateful response |
Windows → Linux 호스트 신규 연결 | DROP | 분석 VM이 게이트웨이 서비스를 탐색하지 못하게 함 |
Windows → WAN 일반 라우팅 | DROP | Linux를 인터넷 출구로 사용하지 못하게 함 |
Windows → Tailnet 임의 포트 | DROP | 관리망으로의 횡적 이동 제한 |
MacBook → Windows Sunshine 세션과 해당 응답은 허용된다. Windows VM → Linux·WAN·Tailnet 비허용 포트의 신규 연결은 차단된다.
패킷 및 counter 검증
Linux에서 연결 여부만 확인하는 대신 인터페이스와 nftables counter를 함께 본다.
sudo nft list chain inet filter FWD-TS sudo nft list chain inet filter FWD-STATE sudo tcpdump -ni tailscale0 host 10.10.0.20 sudo tcpdump -ni enx00e04c637a20 host 10.10.0.20
확인할 포인트는 세 가지다.
- MacBook에서 연결을 시작할 때 tailscale0에 패킷이 보이는가
- 같은 세션이 enx00e04c637a20으로 전달되는가
- 응답 패킷이 FWD-STATE의 established counter를 증가시키는가
세 조건이 충족되면 Sunshine 세션이 Linux에서 정상적으로 forwarding되고 FWD-STATE가 응답 패킷을 처리한 것이다.
정리
Moonlight는 MacBook, Sunshine과 Virtual Display Driver는 Windows VM에서 실행한다. Linux는 tailscale0와 전용 NIC 사이에서 IP forwarding과 nftables filtering을 수행한다.
FWD-TS는 목적지 10.10.0.20과 스트리밍 포트의 신규 연결을 허용한다. FWD-STATE는 해당 세션의
established,related 응답을 처리한다. Windows VM의 Linux·WAN·Tailnet 비허용 포트 접근은 별도 DROP 규칙에 도달한다.