AZURE PlayFab 구현한 것에서 공격 재현 - Heartbeat

WONY_yoon·2025년 12월 16일

CVE-2025-59247 AZURE PlayFab 취약점 재현

MACos 환경에서 구현
Mac에서 LocalMultiplayerAgent 없이 완전한 GSDK 환경 구성

⚠️ 주의: 이 문서는 보안 연구 및 교육 목적으로 작성되었습니다. 실제 환경에서의 무단 테스트는 법적 문제를 야기할 수 있으며, 반드시 본인 소유의 격리된 환경에서만 실습하시기 바랍니다.

1. Mock LocalMultiplayerAgent 만들기

1. Python Mock Agent

mkdir -p ~/Desktop/Docker/PlayFab/MockAgent
cd ~/Desktop/Docker/PlayFab/MockAgent

cat > mock_agent.py << 'EOF'
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import threading
import time

(생략)

EOF

2. Mock Agent를 Docker 컨테이너로 만들기

cd ~/Desktop/Docker/PlayFab/MockAgent

cat > Dockerfile << 'EOF'
FROM python:3.11-slim

WORKDIR /app
COPY mock_agent.py .

EXPOSE 56001

CMD ["python", "mock_agent.py"]
EOF
# 빌드
docker build -t mock-agent:v1 .

2. GSDK Config 파일 생성

mkdir -p ~/Desktop/Docker/PlayFab/config
cd ~/Desktop/Docker/PlayFab/config

cat > config.json << 'EOF'
{
  "heartbeatEndpoint": "http://mock-agent:56001/v1/sessionHosts/test-session-host",
  "sessionHostId": "test-session-host-id",
  "vmId": "test-vm-id",
  "logFolder": "/logs",
  "certificateFolder": "/certs",
  "sharedContentFolder": "/shared",
  "buildMetadata": {

(생략)

EOF

3. wrapper 실행 가능하도록 Dockerfile 복원

cd ~/Desktop/Docker/PlayFab/MpsSamples/wrappingGsdk
cat > Dockerfile << 'EOF'
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /source

# Copy csproj and restore
COPY fakegame/*.csproj ./fakegame/
COPY wrapper/*.csproj ./wrapper/
RUN dotnet restore ./fakegame && dotnet restore ./wrapper

(생략)

EOF
# 재빌드
docker rmi myfirstgame:v1
docker build -t myfirstgame:v1 .

4. 전체 환경 실행

1. 네트워크 생성 (이미 있으면 스킵)

docker network create playfab 2>/dev/null || echo "Network already exists"

2. Mock Agent 실행

docker run -d 
  --name mock-agent \
  --network playfab \
  -p 56001:56001 \
  mock-agent:v1

3. Wrapper + Fakegame 실행 (GSDK 활성화)

docker run -d \
  --name playfab-cve-test \
  --network playfab \
  -p 56100:80 \
  -v ~/Desktop/Docker/PlayFab/config/config.json:/config.json:ro \
  -e GSDK_CONFIG_FILE=/config.json \
  -e PF_SERVER_LOG_DIRECTORY=/logs \
  myfirstgame:v1

5. 동작 확인

1. Mock Agent 로그 확인

docker logs -f mock-agent

예시 출력:

[REQUEST] /v1/sessionHosts/test-session-host
[HEARTBEAT] CurrentGameState: Initializing
[RESPONSE] {'operation': 'Continue'}

2. Wrapper 로그 확인

docker logs -f playfab-cve-test

예시 출력:

Wrapper sample for Azure PlayFab Multiplayer Servers
[GSDK] Heartbeat sent: Initializing
[GSDK] Heartbeat sent: StandingBy
[GSDK] Heartbeat sent: Active

3. 게임 서버 테스트

curl http://127.0.0.1:56100/hello

4. 한 번에 실행하는 스크립트

cat > ~/Desktop/Docker/PlayFab/start_cve_test.sh << 'EOF'
#!/bin/bash

echo "=== CVE-2025-59247 Test Environment Setup ==="

# Stop and remove existing containers
echo "Cleaning up old containers..."
docker stop mock-agent playfab-cve-test 2>/dev/null
docker rm mock-agent playfab-cve-test 2>/dev/null

# Create network
echo "Creating Docker network..."
docker network create playfab 2>/dev/null || echo "Network already exists"

# Start Mock Agent
echo "Starting Mock LocalMultiplayerAgent..."
docker run -d \
  --name mock-agent \
  --network playfab \
  -p 56001:56001 \
  mock-agent:v1

(생략)

EOF

취약점 분석 (교육 목적)

⚠️ 중요: 아래 내용은 보안 연구 및 방어 전략 수립을 위한 교육 자료입니다. 실제 공격에 사용해서는 안 됩니다.

1. 취약점의 원리

CVE-2025-59247은 GSDK의 Heartbeat 응답 처리 과정에서 입력값 검증 부재로 인해 발생합니다.

취약한 부분

# 검증 없이 응답을 처리하는 예시 (취약한 코드)
response = {
    "operation": "Terminate",  # 검증되지 않은 operation 값
    "configOverride": {
        "logFolder": "../../../sensitive-data"  # 경로 순회 가능
    }
}

잠재적 공격 벡터 (이론적 분석)

  1. 경로 순회 (Path Traversal)

    • logFolder, certificateFolder 등의 필드에 ../ 사용
    • 시스템의 민감한 파일 접근 가능성
  2. 버퍼 오버플로우

    • 과도하게 긴 문자열 전송
    • 메모리 손상 가능성
  3. 명령어 인젝션

    • 검증되지 않은 필드를 통한 코드 실행 시도

2. 악의적 페이로드 구조 분석

# 교육 목적의 페이로드 구조 예시 (실제 공격 코드 아님)
malicious_response = {
    "operation": "(생략)",  # 예상치 못한 operation 값
    "maliciousCommand": "(생략)",  # 시스템 명령어
    "injectedScript": "(생략)",  # 스크립트 인젝션
    "configOverride": {
        "logFolder": "(생략)",  # 경로 순회 패턴
        "certificateFolder": "(생략)"
    },
    "longField": "(생략)",  # 버퍼 오버플로우 시도
    "pathTraversal": "(생략)"  # 민감한 파일 경로
}

3. 취약점 시뮬레이션 환경 구성

실제 악의적 코드는 보안상 (생략) 처리

cd ~/Desktop/Docker/PlayFab/MockAgent

# 취약점 분석용 Agent (상세 구현은 생략)
cat > analysis_agent.py << 'EOF'
# 이 부분의 상세 코드는 보안상의 이유로 (생략)
# 
# 주요 기능:
# - 정상 요청 4회 처리
# - 5번째 요청부터 비정상 응답 전송
# - 다양한 공격 벡터 시뮬레이션
#
# (생략)
EOF

4. Docker 이미지 빌드

cd ~/Desktop/Docker/PlayFab/MockAgent

cat > Dockerfile.analysis << 'EOF'
FROM python:3.11-slim

WORKDIR /app
COPY analysis_agent.py .

EXPOSE 56001

CMD ["python", "analysis_agent.py"]
EOF

빌드:

docker build -f Dockerfile.analysis -t analysis-agent:v1 .

5. 취약점 모니터링

cat > ~/Desktop/Docker/PlayFab/monitor_vulnerability.sh << 'EOF'
#!/bin/bash

echo "=== CVE-2025-59247 Vulnerability Monitor ==="
echo ""
echo "Press Ctrl+C to stop monitoring"
echo ""
echo "=================================="

# 로그 모니터링 (상세 구현 생략)
# (생략)

wait
EOF

chmod +x ~/Desktop/Docker/PlayFab/monitor_vulnerability.sh

6. 취약점 분석 스크립트

cat > ~/Desktop/Docker/PlayFab/analyze_vulnerability.sh << 'EOF'
#!/bin/bash

echo "╔═══════════════════════════════════════════════════════════╗"
echo "║        CVE-2025-59247 VULNERABILITY ANALYSIS              ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""

echo "🔍 Checking wrapper behavior..."
echo ""

# Wrapper 로그에서 응답 처리 확인
echo "=== Wrapper Logs Analysis ==="
docker logs playfab-cve-test 2>&1 | grep -E "(error|exception|Terminate)" || echo "No obvious issues in logs"
(생략)

echo "═══════════════════════════════════════════════════════════"
EOF

chmod +x ~/Desktop/Docker/PlayFab/analyze_vulnerability.sh

7. 실행 방법

실제 공격 코드는 보안상 (생략) 처리되었습니다.

분석 환경 구축

cd ~/Desktop/Docker/PlayFab

# 1. 환경 구축 (상세 명령어 생략)
# (생략)

# 2. 로그 모니터링 (새 터미널)
# (생략)

# 3. 취약점 분석 실행
./analyze_vulnerability.sh

수동 테스트 시뮬레이션

# 정상 요청 테스트
echo "━━━ Normal Request Test ━━━"
curl -s -X POST http://localhost:56002/v1/sessionHosts/test-session \
  -H 'Content-Type: application/json' \
  -d '{"CurrentGameState":"Initializing"}' | python3 -m json.tool

# 비정상 응답 시뮬레이션 (상세 내용 생략)
# (생략)

방어 전략

1. 입력값 검증 강화

// 안전한 구현 예시
public class SecureHeartbeatValidator
{
    private static readonly string[] AllowedOperations = 
        { "Continue", "Active", "Terminate" };
    
    private const int MAX_RESPONSE_SIZE = 1024 * 10; // 10KB
    private const string ALLOWED_BASE_PATH = "/app/";
    
    public void ValidateResponse(HeartbeatResponse response)
    {
        // 1. Operation 필드 검증
        if (!AllowedOperations.Contains(response.Operation))
        {
            throw new SecurityException($"Invalid operation: {response.Operation}");
        }
        
        // 2. 응답 크기 제한
        var jsonSize = JsonConvert.SerializeObject(response).Length;
        if (jsonSize > MAX_RESPONSE_SIZE)
        {
            throw new SecurityException($"Response too large: {jsonSize} bytes");
        }
        
        // 3. 경로 검증
        if (!string.IsNullOrEmpty(response.LogFolder))
        {
            ValidatePath(response.LogFolder);
        }
    }
    
    private void ValidatePath(string path)
    {
        // 절대 경로만 허용
        if (!Path.IsPathRooted(path))
        {
            throw new SecurityException("Relative paths not allowed");
        }
        
        // 경로 순회 방지
        string normalizedPath = Path.GetFullPath(path);
        if (!normalizedPath.StartsWith(ALLOWED_BASE_PATH))
        {
            throw new SecurityException($"Path outside allowed directory: {path}");
        }
        
        // 위험한 경로 패턴 검사
        if (path.Contains("..") || path.Contains("~"))
        {
            throw new SecurityException($"Dangerous path pattern detected: {path}");
        }
    }
}

2. 네트워크 격리

# docker-compose.yml - 보안 강화 설정
version: '3.8'

services:
  game-server:
    image: myfirstgame:v1
    networks:
      - isolated-network
    # 읽기 전용 파일 시스템
    read_only: true
    # 임시 파일용 볼륨만 쓰기 가능
    tmpfs:
      - /tmp
      - /logs
    # 최소 권한으로 실행
    user: "1000:1000"
    # 리소스 제한
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '0.5'

networks:
  isolated-network:
    driver: bridge
    internal: true  # 외부 네트워크 접근 차단

3. 로깅 및 모니터링

import logging
from datetime import datetime

# 보안 이벤트 로깅
security_logger = logging.getLogger('security')
security_logger.setLevel(logging.WARNING)

# 파일 핸들러 설정
handler = logging.FileHandler('/var/log/security.log')
formatter = logging.Formatter(
    '%(asctime)s - SECURITY - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
security_logger.addHandler(handler)

def log_security_event(event_type, details, severity='WARNING'):
    """보안 이벤트 로깅"""
    security_logger.log(
        getattr(logging, severity),
        f"Event: {event_type}",
        extra={
            'event_type': event_type,
            'details': details,
            'timestamp': datetime.now().isoformat(),
            'severity': severity
        }
    )

# 사용 예시
def validate_heartbeat(response):
    if detect_path_traversal(response.get('logFolder', '')):
        log_security_event(
            'PATH_TRAVERSAL_ATTEMPT',
            {
                'path': response['logFolder'],
                'source': request.remote_addr,
                'session_id': response.get('sessionId')
            },
            severity='CRITICAL'
        )
        raise SecurityException("Path traversal detected")

참고 자료

공식 문서

보안 도구

  • 정적 분석: SonarQube, Semgrep, CodeQL
  • 동적 분석: OWASP ZAP, Burp Suite
  • 컨테이너 보안: Trivy, Snyk, Anchore

학습 리소스

0개의 댓글