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

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

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 .


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


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 .

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

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

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
docker logs -f mock-agent
예시 출력:
[REQUEST] /v1/sessionHosts/test-session-host
[HEARTBEAT] CurrentGameState: Initializing
[RESPONSE] {'operation': 'Continue'}
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
curl http://127.0.0.1:56100/hello
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
⚠️ 중요: 아래 내용은 보안 연구 및 방어 전략 수립을 위한 교육 자료입니다. 실제 공격에 사용해서는 안 됩니다.
CVE-2025-59247은 GSDK의 Heartbeat 응답 처리 과정에서 입력값 검증 부재로 인해 발생합니다.
# 검증 없이 응답을 처리하는 예시 (취약한 코드)
response = {
"operation": "Terminate", # 검증되지 않은 operation 값
"configOverride": {
"logFolder": "../../../sensitive-data" # 경로 순회 가능
}
}
경로 순회 (Path Traversal)
logFolder, certificateFolder 등의 필드에 ../ 사용버퍼 오버플로우
명령어 인젝션
# 교육 목적의 페이로드 구조 예시 (실제 공격 코드 아님)
malicious_response = {
"operation": "(생략)", # 예상치 못한 operation 값
"maliciousCommand": "(생략)", # 시스템 명령어
"injectedScript": "(생략)", # 스크립트 인젝션
"configOverride": {
"logFolder": "(생략)", # 경로 순회 패턴
"certificateFolder": "(생략)"
},
"longField": "(생략)", # 버퍼 오버플로우 시도
"pathTraversal": "(생략)" # 민감한 파일 경로
}
실제 악의적 코드는 보안상 (생략) 처리
cd ~/Desktop/Docker/PlayFab/MockAgent
# 취약점 분석용 Agent (상세 구현은 생략)
cat > analysis_agent.py << 'EOF'
# 이 부분의 상세 코드는 보안상의 이유로 (생략)
#
# 주요 기능:
# - 정상 요청 4회 처리
# - 5번째 요청부터 비정상 응답 전송
# - 다양한 공격 벡터 시뮬레이션
#
# (생략)
EOF

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 .

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
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
실제 공격 코드는 보안상 (생략) 처리되었습니다.
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
# 비정상 응답 시뮬레이션 (상세 내용 생략)
# (생략)
// 안전한 구현 예시
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}");
}
}
}
# 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 # 외부 네트워크 접근 차단
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")