Windows: 10.10.0.20 GDB client
Docker: 10.20.0.10 gdbserver TCP 31234
경로: enx00e04c637a20 → Linux FORWARD → foxirain4
Linux 기반 악성코드 분석 VM 격리망 · 4/5
Windows–Docker 디버깅 요구사항macvlan 패킷 경로L3 bridge 패킷 경로foxirain4 network 설정Docker interface 목록Windows static routeWindows → Docker gdbserver 허용 규칙my_container 실행 설정my_kernel_container 실행 설정Docker → Windows 허용 규칙패킷 경로 검증정리Sources작업 기록공식 문서시리즈 이동
Windows–Docker 디버깅 요구사항
Windows 분석 VM에서는 Windows 도구를 실행하고, Docker에서는 CTF·커널·Linux 바이너리를 실행한다. Windows의 GDB client가 Docker의 gdbserver TCP 31234로 접속해야 한다.
GDB 연결 경로는 다음과 같다.
Windows VM 10.10.0.20 └─ GDB client └─ Linux nftables router └─ foxirain4 10.20.0.1/24 └─ my_container 10.20.0.10 └─ gdbserver TCP 31234
gdbserver는 Docker 안에서 Linux 실행 파일을 시작하고 원격 GDB 프로토콜을 제공한다. 네트워크 격리는 Linux의 route와 nftables가 담당한다.
macvlan 패킷 경로
Docker 컨테이너를 Windows와 연결된 물리 NIC에 macvlan으로 붙이면 같은 L2 segment에서 직접 통신할 수 있다. 컨테이너가 물리 네트워크의 독립 장비처럼 보이기 때문에 route 설정도 단순해진다.
이 방식에는 다음 문제가 있었다.
- 컨테이너와 Windows가 L2에서 직접 통신하면 패킷이 Linux의 L3 FORWARD 정책을 통과하지 않는다.
- macvlan용 별도 L2 필터 정책을 추가하면 정책 위치가 분산된다.
- Windows–Docker 트래픽이 Linux FORWARD hook을 통과해야 했다.
Docker 공식 문서도 bridge network에는 방화벽 규칙을 만들지만 macvlan·ipvlan·host networking에는 같은 방식의 규칙을 만들지 않는다고 설명한다. Docker packet filtering and firewalls
당시 테스트 기록에서도 macvlan 트래픽이 Linux의 L3 FORWARD 정책을 통과하지 않는 문제를 확인했다.
L3 bridge 패킷 경로
Docker bridge는 호스트 내부에 private network를 만들고, 컨테이너의 veth를 Linux bridge에 연결한다. 외부 네트워크와의 통신은 호스트의 routing과 firewall을 거친다. Docker networking drivers
Windows 10.10.0.20에서 Docker 10.20.0.0/24로 가는 패킷은 Linux의 FORWARD hook을 지난다. nftables 규칙에서 ingress, egress, source IP, destination IP, port, connection state를 검사한다.
foxirain4 network 설정
docker network inspect foxirain4_net의 설정값은 다음과 같다.{ "Name": "foxirain4_net", "Created": "2025-10-02T21:20:24+09:00", "Driver": "bridge", "EnableIPv4": true, "EnableIPv6": false, "IPAM": { "Config": [ { "Subnet": "10.20.0.0/24", "Gateway": "10.20.0.1" } ] }, "Internal": false, "Options": { "com.docker.network.bridge.name": "foxirain4" } }
같은 네트워크를 만드는 명령은 다음과 같다.
docker network create --driver bridge --subnet 10.20.0.0/24 --gateway 10.20.0.1 --opt com.docker.network.bridge.name=foxirain4 foxirain4_net
기본
br-<ID> 이름 대신 Linux interface 이름을 foxirain4로 고정했다. nftables에서 동적으로 바뀌는 bridge ID를 추적하지 않고 iifname "foxirain4"와 oifname "foxirain4"를 안정적으로 사용할 수 있기 때문이다.Internal: false이므로 이 네트워크는 Docker 자체의 internal-only network가 아니다. nftables에도 Docker bridge → WAN mark가 있기 때문에 컨테이너의 인터넷 egress가 허용된 별도 디버깅망이다.Docker interface 목록
에서 Linux에 생긴 인터페이스를 세 종류로 정리했다.
인터페이스 | 역할 | 네트워크 설정 |
docker0 | Docker 기본 bridge | 기본 컨테이너 네트워크 |
br-042225748a2d | 다른 사용자 정의 bridge | ID 기반 이름이라 재생성 시 변경 가능 |
foxirain4 | 이름을 고정한 사용자 정의 bridge | 10.20.0.0/24와 nftables 정책 연결 |
veth* | 컨테이너 eth0와 bridge를 잇는 가상 Ethernet pair | 각 컨테이너의 L2 연결 |
[container eth0] │ [veth pair] │ [host veth] │ [foxirain4 bridge 10.20.0.1] │ [Linux routing + nftables] │ [10.10.0.0/24 or WAN]
Windows static route
Windows는 10.20.0.0/24가 자신의 직접 연결 subnet이 아니라는 것을 알아야 한다. 다음 hop은 Linux의 분석망 주소 10.10.0.10이다.
route -p add 10.20.0.0 mask 255.255.255.0 10.10.0.10
Microsoft 문서에서
route /p add는 route를 registry에 저장해 TCP/IP가 다시 시작된 뒤에도 유지하는 옵션이다. Microsoft route command확인은 다음과 같이 한다.
route print 10.* tracert 10.20.0.10 Test-NetConnection 10.20.0.10 -Port 31234
당시 Windows 명령 기록은 Linux에 남아 있지 않지만, Linux의 FORWARD 규칙과 실제 SSH 시험 기록은 이 L3 경로를 사용하도록 구성되어 있다.
Windows → Docker gdbserver 허용 규칙
iifname $IF_INTERNAL oifname $IF_foxirain4 ip saddr 10.10.0.20 tcp dport 31234 ct state new counter accept comment "foxirain5 -> foxirain4 gdbserver"
규칙의 조건은 다음과 같다.
- ingress는 Windows와 연결된 전용 NIC다.
- source는 Windows VM 10.10.0.20이다.
- egress는 foxirain4다.
- 신규 TCP 연결의 destination port는 31234다.
현재 규칙에는
ip daddr 10.20.0.10이 없다. foxirain4에 연결된 컨테이너가 TCP 31234를 listen하면 접속 대상이 될 수 있다. 목적지 IP를 10.20.0.10으로 제한하는 규칙은 다음과 같다.ip saddr 10.10.0.20 ip daddr 10.20.0.10 tcp dport 31234 ct state new accept
my_container 실행 설정
항목 | 값 |
Image | amemoyoi-ctf |
User | pwn |
Network | foxirain4_net |
IP | 10.20.0.10 |
Published ports | 127.0.0.1:18080→18080, 127.0.0.1:31234→31234 |
Security | privileged, AppArmor unconfined, label disable |
자동 명령 | socat TCP 18080 → ./prob |
inspect 결과를 실행 명령으로 표현하면 다음과 같다.
docker run -it --name my_container --privileged --security-opt label=disable --network foxirain4_net --ip 10.20.0.10 -p 127.0.0.1:18080:18080 -p 127.0.0.1:31234:31234 amemoyoi-ctf /bin/sh -c 'socat TCP-LISTEN:18080,reuseaddr,fork EXEC:./prob,stderr'
컨테이너의 자동 시작 명령은 18080의
./prob 서비스다. 31234는 publish와 nftables에 gdbserver용으로 준비되어 있지만 Config에 gdbserver 자동 실행 명령은 없다. 컨테이너에 들어가 분석할 바이너리를 지정해 gdbserver를 별도로 실행하는 형태였다.예시는 다음과 같은 형태다.
gdbserver 0.0.0.0:31234 ./target_binary
Windows의 GDB client는 10.20.0.10:31234에 연결한다.
target remote 10.20.0.10:31234
호스트 publish 주소가 127.0.0.1인 것은 호스트의 31234를 외부 인터페이스에 공개하지 않기 위한 설정이다. Windows는 host port binding이 아니라 10.20.0.10으로 직접 routing하는 별도 경로를 사용한다.
my_kernel_container 실행 설정
docker run -it --name my_kernel_container --privileged --security-opt label=disable --network foxirain4_net --ip 10.20.0.30 -p 127.0.0.1:8080:8080 -p 127.0.0.1:41234:41234 -v /home/amemoyoi/kernel/kernel-connection/deploy:/home/pwn/ amemoyoi-kernel-ctf /bin/sh -c 'socat TCP-LISTEN:8080,reuseaddr,fork EXEC:./run.sh,stderr'
이 컨테이너는 커널 실습 디렉터리를 bind mount하고, 8080을 문제 실행 포트, 41234를 별도 디버깅 포트로 준비했다. 둘 다 호스트에서는 loopback에만 publish했다.
Docker → Windows 허용 규칙
DOCKER-USER에는 다음 mark 규칙도 있다.iifname $IF_foxirain4 oifname $IF_INTERNAL meta mark set (meta mark & $MARK_KEEP_MASK) | $MARK_ALLOW
FWD-DOCKER는 이 mark가 설정된 패킷을 accept한다. foxirain4에서 Windows 분석망으로 시작하는 신규 연결에는 목적지 IP와 포트 조건이 없다. Windows → Docker는 TCP 31234로 제한되지만 Docker → Windows는 제한 범위가 더 넓다.
Docker → Windows 규칙에 source subnet, destination 10.10.0.20, destination port 조건을 추가하면 허용 범위를 줄일 수 있다.
패킷 경로 검증
docker network inspect foxirain4_net docker inspect my_container docker inspect my_kernel_container ip -br link show foxirain4 ip route show 10.20.0.0/24 sudo nft list chain inet filter FWD-DOCKER sudo nft list chain ip filter DOCKER-USER sudo tcpdump -ni enx00e04c637a20 tcp port 31234 sudo tcpdump -ni foxirain4 tcp port 31234 ss -lntp | grep 31234
정상 연결이면 전용 NIC와 foxirain4 양쪽에서 같은 TCP 세션이 보이고, FWD-DOCKER의 31234 counter가 증가해야 한다.
정리
Docker 컨테이너는 foxirain4 bridge의 10.20.0.0/24를 사용한다. Windows에는
10.20.0.0/24 via 10.10.0.10 persistent route를 추가한다. Windows → Docker 트래픽은 Linux FORWARD hook에서 처리된다.Windows 10.10.0.20에서 foxirain4의 TCP 31234로 시작하는 신규 연결을 허용한다. 현재 규칙은 목적지 IP가 없고 Docker → Windows 방향에도 목적지·포트 제한이 없다.