DEEP DIVE REPORT

PHP 비신뢰 역직렬화 점검 가이드: 신뢰 경계 입력과 POP 체인

SecurityDesk
2026.09.05 조회 5

PHP 애플리케이션에서 공격자가 제어하는 직렬화 객체를 unserialize()로 역직렬화하면, 클래스 인스턴스화와 마법 메서드 호출을 통해 코드 실행으로 이어질 수 있습니다. 이 가이드는 신뢰 경계를 넘는 비신뢰 입력에서 이 위험이 어떻게 발생하는지, 점검과 대응 방향을 정리합니다. 프레임워크 큐의 직렬화 동작은 확인된 사실로 기술하며, 큐 페이로드가 신뢰 경계를 넘거나 공격자에 의해 수정될 수 있는 경우에만 별도 점검이 필요합니다.

개요

개요 인포그래픽
PHP의 unserialize() 함수는 직렬화 문자열을 PHP 값으로 되돌리는 함수입니다. 이 함수 자체가 임의 PHP 코드를 실행하는 것은 아닙니다. 위험은 공격자가 제어하는 객체를 역직렬화할 때 클래스가 인스턴스화되고, 그 과정에서 마법 메서드가 호출될 수 있다는 점에 있습니다(PHP Manual).

객체를 복원하는 과정에서 PHP는 __wakeup() 또는 __unserialize() 메서드가 존재하면 자동으로 호출을 시도합니다. 이 자동 호출이 공격 벡터의 진입점이 됩니다.

실제 공격에서는 단일 클래스만으로 끝나지 않습니다. 여러 클래스를 연결한 POP 체인(Property Oriented Programming chain), 즉 gadget chain을 구성하여 각 마법 메서드가 다음 클래스의 마법 메서드를 트리거하는 방식으로 코드 실행에 이릅니다(Insecure Deserialization in PHP).

적용 환경·전제조건

다음 중 하나라도 해당되면 이 가이드의 점검 범위에 들어갑니다.

  • untrusted user input을 unserialize()에 전달하는 경로
  • 외부 저장된 직렬화 데이터를 역직렬화하는 경로
  • 프레임워크 큐 시스템에서 job 직렬화를 사용하고, 큐 페이로드가 신뢰 경계를 넘거나 공격자에 의해 수정될 수 있는 경우

PHP 공식 문서는 allowed_classes 옵션 값과 무관하게 untrusted user input을 unserialize()에 전달하지 말 것을 명시적으로 경고합니다. 객체 인스턴스화와 autoloading으로 코드가 로드되고 실행될 수 있기 때문입니다.

이 가이드의 전제는 특정 CVE나 확정 악용 사례가 아닌, 일반적 취약성 클래스의 메커니즘 기반 점검이라는 점입니다. 제공된 근거에는 특정 PHP 버전 범위나 KEV 등록 상태가 포함되어 있지 않습니다.

기술 절차·판단 근거

신뢰 경계 식별

점검의 시작은 "어디서 누가 이 데이터를 작성하고, 어디에서 역직렬화되는가"를 확인하는 것입니다.

  • 입력 원천이 외부 사용자(클라이언트, API 호출자)인 경로
  • 외부 저장된 직렬화 데이터가 공격자에 의해 수정될 수 있는지 확인
  • 프레임워크 내부 직렬화와 외부 입력 직렬화 구분
  • 프레임워크 큐 시스템(예: Laravel 큐)의 job 직렬화 경로

Laravel 큐의 job 직렬화 동작에 관한 상세 설명은 아래 '큐 직렬화 경로' 절에서 다룹니다.

POP 체인 가용성 판단

역직렬화 위험이 현실화되기 위한 핵심 조건은 객체 복원 시 PHP가 __wakeup() 또는 __unserialize() 메서드를 자동으로 호출한다는 점입니다. 실제 공격에서는 이 자동 호출을 트리거로 여러 클래스를 연결한 POP 체인, 즉 gadget chain을 구성하여 코드 실행에 이릅니다. 각 마법 메서드가 다음 클래스의 마법 메서드를 트리거하는 방식입니다(Insecure Deserialization in PHP).

단, 특정 gadget 목록이나 버전별 가용성은 제공된 근거에 포함되지 않으므로, 적용 환경의 코드베이스를 직접 확인해야 합니다.

allowed_classes 옵션의 위치 이해

allowed_classes => false를 지정하면 직렬화 객체가 원래 클래스로 인스턴스화되지 않고 __PHP_Incomplete_Class로 표현되며, 마법 메서드가 트리거되지 않습니다. 그러나 PHP 공식 문서는 이 옵션만으로 untrusted input을 전달해도 안전하지 않다고 경고합니다.

운영상 영향

비신뢰 입력 역직렬화의 일반 위험

공격자가 제어하는 직렬화 데이터가 unserialize()로 전달되면, 객체 인스턴스화와 마법 메서드 자동 호출을 통해 POP 체인이 실행될 수 있습니다. 이 위험은 애플리케이션 내에 호출 가능한 마법 메서드와 적합한 gadget chain이 존재하는 등 조건이 충족될 때 현실화됩니다.

큐 직렬화 경로

Laravel 큐에서는 job 처리 시 Eloquent 모델과 로드된 관계가 직렬화·역직렬화되며, job 생성자에 Eloquent 모델을 전달하는 경우 큐에는 모델의 식별자만 직렬화됩니다(Laravel Queues). 이 동작 자체는 정상적인 프레임워크 동작이며, 큐 페이로드가 신뢰 경계를 넘거나 공격자에 의해 수정될 수 있는 경우에만 역직렬화 위험과 연결하여 점검이 필요합니다.

점검 원칙

점검 시 확인해야 할 핵심은 두 가지입니다.

  • 입력 신뢰 경계: unserialize()에 전달되는 데이터의 원천이 외부 사용자인지, 내부 생성 데이터인지 확인
  • 외부 저장 데이터 무결성: 외부 저장소에서 읽는 직렬화 데이터에 hash_hmac() 기반 무결성 검증이 적용되어 있는지 확인

탐지·대응

탐지

  • unserialize() 호출 지점의 입력 원천을 확인하여 비신뢰 입력인지 판별
  • 외부 저장된 직렬화 데이터에 hash_hmac() 기반 무결성 검증이 적용되어 있는지 확인
  • allowed_classes 옵션 설정 값을 확인하되, allowed_classes => false도 untrusted input을 안전하게 처리하지 못한다는 점에 주의

대응

대응의 최우선 방향은 신뢰 경계 자체를 제거하는 것입니다.

즉시 적용할 점검·보완

  • 외부 저장된 직렬화 데이터를 역직렬화할 경우 hash_hmac()로 데이터 무결성 검증 적용
  • allowed_classes 옵션 설정을 확인하되, 이 옵션만으로 untrusted input을 안전하게 처리할 수 없음을 전제하고 추가 검증 병행

장기적 형식 전환

  • 신뢰 경계를 넘는 데이터에 PHP 직렬화를 사용 중인 경로에서 JSON 등 표준 형식으로 전환

PHP 공식 문서는 unserialize() 대신 JSON 같은 표준 형식을 권고합니다.

한계 및 참고자료

이 가이드는 제공된 근거 범위 내에서 작성되었습니다. 다음 사항에 대한 단정은 자료에 의해 지지되지 않습니다.

  • 특정 CVE 번호 또는 CNA 등록 정보
  • 영향 받는 PHP 버전의 정확한 범위
  • 확정된 실제 악용 사례 또는 KEV 등록 상태
  • 프레임워크별 구체적 gadget 목록
  • hash_hmac() 검증의 키 관리 상세 절차

적용 환경의 코드베이스, 프레임워크 버전, 저장소 구성에 따라 실제 위험도와 점검 우선순위는 달라질 수 있습니다.

참고자료

함께 읽으면 좋은 글

본 콘텐츠는 AI 기술로 작성된 분석 리포트를 포함하고 있습니다. 내용 중 사실과 다르거나 보완이 필요한 정보를 발견하셨으면 댓글을 통해 의견을 부탁드립니다. 여러분의 피드백은 더 정확한 보안 정보 공유에 큰 도움이 됩니다.

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

로그인

아직 댓글이 없습니다.

첫 번째 댓글을 작성해보세요!

IT 도구 서랍

→ Unix: 2025-01-15T09:30:00
→ 날짜: 1736934600

→ ASCII: ABC
→ 문자: 65 66 67

ASCII 코드표 — 클릭하면 입력란에 추가

DecHex약어설명
DecHex문자
DecHex문자

→ 유니코드: 홍길동
→ 문자: \ud64d\uae38\ub3d9