본문으로 건너뛰기
Docker 보안 취약점 가이드 - CVE-2025 컨테이너 탈출 방어

# Docker 보안 취약점 완벽 가이드: 2025년 CVE-2025-9074 컨테이너 탈출 방어 전략

Table of Contents

프로덕션 보안 사고: 금요일 오전 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/sudoers
EOF

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/Debian
sudo apt update
sudo apt install runc

# RHEL/CentOS
sudo yum update runc

# 또는 수동 설치 (최신 버전)
wget https://github.com/opencontainers/runc/releases/download/v1.2.8/runc.amd64
sudo 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/host
mount /dev/sda1 /mnt/host

# 이제 호스트의 전체 파일시스템 접근 가능!
cat /mnt/host/etc/shadow
chroot /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:$PATH
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock

# 3. ~/.bashrc에 추가
echo 'export PATH=/home/$USER/bin:$PATH' >> ~/.bashrc
echo 'export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock' >> ~/.bashrc

# 4. systemd 사용자 서비스로 시작
systemctl --user start docker
systemctl --user enable docker

# 5. 확인
docker run hello-world

Rootless vs 일반 Docker 비교:

# 일반 Docker (루트 권한)
$ docker run -it ubuntu bash
root@container# id
uid=0(root) gid=0(root) # ← 컨테이너 내부는 루트!

# Rootless Docker (비루트 권한)
$ docker run -it ubuntu bash
root@container# id
uid=0(root) gid=0(root) # 컨테이너 내부는 root로 보이지만...

# 호스트에서 확인하면:
$ ps aux | grep bash
user 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 bash
root@container# id
uid=0(root) gid=0(root)

# 호스트에서 확인
$ ps aux | grep bash
100000 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 bash

SELinux (RHEL/CentOS):

# SELinux 상태 확인
sestatus

# Docker SELinux 레이블 확인
ps auxZ | grep dockerd

# 컨테이너 실행 시 SELinux 레이블 적용
docker run --security-opt label=type:svirt_apache_t -it ubuntu bash

4. 보안 스캐닝 도구 사용

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:latest

Snyk:

# 설치
npm install -g snyk

# 로그인
snyk auth

# Dockerfile 스캔
snyk container test nginx:latest

# 수정 제안
snyk container fix nginx:latest

5. 최소 권한 원칙 (Least Privilege)

** 안전한 컨테이너 설정:**

# docker-compose.yml
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 /app
COPY --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 3000
CMD ["node", "server.js"]

보안 모니터링 및 감지

Falco (런타임 보안 모니터링)

설치 (Kubernetes):

# Helm으로 설치
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm 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 cap

2단계: 긴급 완화 조치 (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 DROP
sudo iptables -A INPUT -p tcp --dport 2376 -j DROP

3단계: 패치 적용 (4시간 내)

# runc 업그레이드
sudo apt update && sudo apt install runc

# Docker Desktop 업그레이드 (Windows/Mac)
# GUI에서 업데이트 확인 또는 공식 사이트에서 다운로드

# Kubernetes 노드 순차 패치 (드레인 후 재부팅)
kubectl drain node-1 --ignore-daemonsets
sudo apt update && sudo apt install runc
sudo reboot
kubectl uncordon node-1

4단계: 검증 (패치 후)

# 버전 재확인
runc --version
docker 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 컨테이너는 완벽하게 격리되지 않으며, 취약점이 발견되면 호스트 서버 전체가 장악될 수 있습니다. 이 글에서 다룬 핵심 사항들을 정리하면:

핵심 요약:

  1. CVE-2025-9074 (CVSS 9.3): Docker Desktop 4.41.0 이상으로 업그레이드 필수
  2. runc 취약점: runc 1.2.8, 1.3.3, 1.4.0-rc.3 이상으로 업그레이드
  3. Rootless Docker: 컨테이너 탈출 시에도 루트 권한 획득 불가
  4. 최소 권한 원칙: --privileged 금지, Capabilities 최소화, 읽기 전용 파일시스템
  5. 보안 스캐닝: Trivy, Docker Scout, Snyk로 정기 스캔
  6. 런타임 모니터링: Falco로 컨테이너 탈출 시도 실시간 감지

다음 단계:

  • runc 및 Docker 버전 긴급 점검
  • 특권 컨테이너 및 Docker Socket 마운트 제거
  • Rootless Docker 또는 User Namespace 활성화
  • 보안 스캐닝 CI/CD에 통합 (Trivy)
  • Falco 런타임 모니터링 구축
  • Pod Security Standards 적용 (Kubernetes)

컨테이너 보안은 한 번에 끝나지 않습니다. 정기적인 취약점 스캔, 패치 적용, 그리고 최소 권한 원칙 준수가 필수입니다. 2025년에만 CVSS 9.3 등급의 치명적 취약점이 여러 개 발견되었습니다. 당신의 프로덕션 환경이 안전한지 지금 바로 점검하세요.

이 글 공유하기:
My avatar

글을 마치며

이 글이 도움이 되었기를 바랍니다. 궁금한 점이나 의견이 있다면 댓글로 남겨주세요.

더 많은 기술 인사이트와 개발 경험을 공유하고 있으니, 다른 포스트도 확인해보세요.

유럽살며 여행하며 코딩하는 노마드의 여정을 함께 나누며, 함께 성장하는 개발자 커뮤니티를 만들어가요! 🚀


관련 포스트