Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2025-7384 — WordPress Database for Contact Form 7의 인증되지 않은 치명적인 PHP 객체 인젝션에 대한 Exploit PoC 및 근본 원인 분석으로, 임의 파일 삭제를 통한 RCE로 이어집니다. | Kitploit
도구/GitHubGitHub/dungsocool/cve-2025-7384
Vulnerability AnalysisExploitationWeb Application ExploitationLearning & EducationLabs & Practice
GitHubdungsocool/cve-2025-7384

CVE-2025-7384

WordPress Database for Contact Form 7의 인증되지 않은 치명적인 PHP 객체 인젝션에 대한 Exploit PoC 및 근본 원인 분석으로, 임의 파일 삭제를 통한 RCE로 이어집니다.

저장소 보기
122개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2025-7384 — PHP 객체 인젝션을 통한 RCE

플러그인: Database for Contact Form 7 (contact-form-entries) ≤ 1.4.3
CVSS: 9.8 (치명적)
CWE: CWE-502 — 신뢰할 수 없는 데이터의 역직렬화
인증 요구 사항: 없음 (비인증)
영향: 원격 코드 실행


목차

  1. 취약점 개요
  2. 관련 개념
  3. 근본 원인 분석 (소스 코드 + 디버그)
  4. 공격 체인
  5. 단계별 재현 (POC)
  6. 영향 평가
  7. 수정 및 대응 방안

1. 취약점 개요

"Database for Contact Form 7" 플러그인(슬러그: contact-form-entries) 버전 1.4.3 이하에는 PHP 객체 인젝션 취약점이 존재합니다. WordPress 관리자가 관리자 패널에서 양식 기록(항목)을 조회하면, 이 플러그인은 인증되지 않은 사용자가 Contact Form 7을 통해 제출한 데이터에 대해 인스턴스화할 수 있는 클래스 목록을 제어하지 않은 채 maybe_unserialize() 함수를 직접 호출합니다.

공격자는 로그인할 필요가 없습니다. 직렬화된 PHP 객체를 아무 양식 필드에 삽입하여 일반 문의 양식을 제출하기만 하면 됩니다. 이 데이터는 데이터베이스에 원본 그대로 저장됩니다. 관리자가 해당 항목을 열어 보면 역직렬화 함수가 공격자가 선택한 객체를 인스턴스화하여 __destruct() 또는 __wakeup() 같은 매직 메서드를 트리거하고, WordPress 환경에 존재하는 POP 가젯에 따라 임의의 동작을 실행하게 됩니다.

심각도: 적절한 POP 가젯(예: __destruct() 메서드에서 unlink()를 호출하는 클래스)이 있으면 공격자는 wp-config.php 파일을 삭제하여 WordPress를 초기 설치 화면으로 되돌릴 수 있습니다 → 이후 공격자가 통제하는 관리자 계정으로 재설치 → 웹셸이 포함된 플러그인 설치 → 서버에서 완전한 원격 코드 실행(RCE) 달성.

속성값
CVE IDCVE-2025-7384
CVSS 점수9.8 (치명적)
CWECWE-502 — 신뢰할 수 없는 데이터의 역직렬화
영향 받는 플러그인contact-form-entries (Database for Contact Form 7) ≤ 1.4.3
인증 요구 사항없음 — CF7 양식을 제출하는 모든 사용자가 페이로드를 주입할 수 있음
트리거 조건관리자가 관리자 패널에서 주입된 항목을 조회할 때
최대 영향인증되지 않은 원격 코드 실행
패치 버전1.4.4+ (unserialize를 json_decode 또는 allowed_classes: false로 대체)

2. 관련 개념

PHP 직렬화 / 역직렬화

PHP는 객체를 구조화된 텍스트 문자열로 변환하기 위해 serialize()를 사용하고, 그 문자열에서 객체를 복원하기 위해 unserialize()를 사용합니다. unserialize()가 신뢰할 수 없는 소스(예: 사용자 입력)로부터 데이터를 받으면, 공격자는 해당 시점에 PHP 메모리에 로드된 클래스에 속하는 임의의 객체를 구성할 수 있습니다.

PHP 매직 메서드

PHP가 객체 수명 주기 동안 자동으로 호출하는 특수 메서드입니다. 이 맥락에서 가장 중요한 것:

  • __wakeup() — 객체가 역직렬화될 때 즉시 호출됨
  • __destruct() — 객체가 소멸될 때(범위를 벗어나거나 요청이 종료될 때) 호출됨
  • __toString() — 객체가 문자열로 캐스팅될 때 호출됨

POP 체인 (Property-Oriented Programming)

애플리케이션 내 기존 클래스의 여러 매직 메서드를 연결하여 위험한 동작 시퀀스를 구성하는 기법입니다. 공격자는 새 코드를 작성하지 않으며, 기존 객체의 속성만 조작하여 매직 메서드가 실행될 때 개발자가 의도하지 않은 동작을 수행하게 합니다.

WordPress의 maybe_unserialize()

WordPress 코어 래퍼 함수입니다. is_serialized()를 호출하여 문자열이 직렬화된 데이터인지 확인하고, 맞으면 unserialize()를 호출하여 객체를 복원합니다. 문제: 이 함수는 인스턴스화가 허용되는 클래스를 제한하기 위해 allowed_classes 매개변수(PHP 7.0부터 사용 가능)를 전달하지 않습니다.


3. 근본 원인 분석 — 소스 코드에서 취약점 발견

1단계: 싱크 포인트 찾기 (싱크 헌팅)

먼저 플러그인 전체 소스 코드를 grep하여 역직렬화 함수를 찾습니다. 이들은 PHP에서 가장 위험한 함수로, 객체 인젝션으로 이어질 수 있습니다:

grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

image.png

출력 결과 maybe_unserialize() 호출 지점이 여러 곳 발견되며, 특히 includes/data.php의 545행, verify_val() 함수 내부에 있습니다:

image 1.png

// data.php lines 538-548
public function verify_val($string){
    if(in_array(substr(ltrim($string),0,1), array('{','['))
       && in_array(substr(rtrim($string),-1), array('}',']'))
    ){
        $val = json_decode($string, 1);
        if(is_array($val)){ $string = $val; }
    } else if(is_serialized($string)){            // line 544
        $string = maybe_unserialize($string);     // ★ line 545 — SINK
    }
    return $string;
}

핵심 질문: $string 변수는 어디에서 오는가? 필터링 없이 사용자 입력에서 온다면 → 이는 취약점입니다.

2단계: 역추적 — 데이터는 어디에서 오는가?

verify_val()이 호출되는 위치를 찾습니다. 같은 data.php 파일에서 역추적합니다:

image 2.png

// data.php lines 520-535
public function get_lead_detail($lead_id){
    global $wpdb;
    $table = $wpdb->prefix . 'vxcf_leads_detail';
    $detail_arr = $wpdb->get_results(
        $wpdb->prepare("SELECT * FROM $table WHERE lead_id=%d", $lead_id),
        ARRAY_A
    );

    foreach($detail_arr as $k => $v){
        if(!empty($v['value'])){
            $detail_arr[$k]['value'] = $this->verify_val($v['value']);  // ← calls verify_val
        }
    }
    return $detail_arr;
}

→ $string은 정확히 $v['value'], 즉 wp_vxcf_leads_detail 데이터베이스 테이블에서 가져온 값입니다. 이 함수는 관리자가 양식 항목의 세부 정보를 조회할 때 호출됩니다.

다음 질문: wp_vxcf_leads_detail 내부의 데이터는 어디에서 오는가? 누가 기록하는가?

3단계: 데이터 기록 지점 찾기 (소스)

2단계에서 데이터가 데이터베이스에서 가져와진다는 것을 알았습니다. 다음 질문: 누가 그 안에 데이터를 기록하는가? data.php에서 INSERT 쿼리를 검색합니다:

grep -rn "insert" wp-src/wp-content/plugins/contact-form-entries/includes/data.php

image 3.png

자세한 내용은 create_lead() 함수 코드(85-103행)를 확인합니다:

image 4.png

98-99행에서 양식 필드(예: your-message)의 내용인 값 $v가 $wpdb->insert()를 통해 데이터베이스에 직접 삽입됩니다. 이 플러그인은 Contact Form 7의 wpcf7_before_send_mail 이벤트에 후킹되므로, 사용자가 양식을 제출할 때마다 모든 필드가 원본 그대로 저장됩니다.

추가 확인: 플러그인은 저장 전에 sanitize_text_field()와 sanitize_textarea_field()를 사용하지만, 이 두 함수는 HTML 태그와 특수 HTML 문자만 제거합니다. O:21:"VulnerableFileHandler":2:{...} 같은 직렬화된 페이로드에는 HTML 태그가 없으므로 완전히 그대로 통과합니다.

4단계: 결론 — 취약점 확인

이 시점에서 전체 흐름이 확립됩니다:

Unauthenticated user submits CF7 form (your-message field contains serialized object)
    ↓ sanitize_text_field() — DOES NOT block serialized strings
Saved into wp_vxcf_leads_detail table (raw payload)
    ↓
Admin views entry → get_lead_detail() → verify_val()
    ↓ is_serialized() returns true
maybe_unserialize($string) — line 545 → PHP instantiates arbitrary object
    ↓
Object's __destruct() executes → performs attacker-controlled action

근본 원인: data.php:545의 maybe_unserialize() 함수가 인증되지 않은 사용자 입력에서 비롯된 데이터에 대해 allowed_classes: false를 전달하지 않고 호출됩니다. 공격자는 CF7 양식의 your-message 필드를 통해 직렬화된 PHP 객체를 제출하기만 하면 되며, 관리자가 해당 항목을 조회하면 PHP가 그 객체를 인스턴스화하고 __destruct() 매직 메서드를 트리거합니다.

5단계: 디버거 검증 (Xdebug)

시각적 증명을 위해 Xdebug를 사용하여 data.php의 545행에 중단점을 설정합니다. 양식을 통해 페이로드를 주입하고 관리자가 항목을 조회하게 한 후, 디버거는 정확히 maybe_unserialize()에서 멈춥니다:

image 5.png

변수 패널에 공격자의 페이로드를 담은 $string이 표시됩니다:

  • $string = "O:21:\"VulnerableFileHandler\":2:{s:9:\"file_path\";s:27:\"/var/www/html/wp-config.php\";s:7:\"cleanup\";b:1;}" → 페이로드가 양식 → 데이터베이스 → 역직렬화 함수까지 차단 없이 이동함

실행 라인:

  • 545행: $string=maybe_unserialize($string);

호출 스택은 함수 호출 순서를 보여줍니다:

vxcf_form_data->verify_val        data.php:545
vxcf_form_data->get_entries       data.php:388
vxcf_form::get_entries            contact-form-entries.php:2682
vxcf_form_pages->entries_page     plugin-pages.php:1017
...
WP_Hook->apply_filters            class-wp-hook.php:324
WP_Hook->do_action                class-wp-hook.php:348

→ 분석된 정확한 흐름 확인: 관리자가 항목 조회 → get_entries() → verify_val() → maybe_unserialize().


4. 공격 체인

공격 체인은 5단계로 구성됩니다. 공격자는 1단계(양식 제출)만 수행하면 됩니다. 2~5단계는 관리자가 항목을 조회한 후 자동으로 발생합니다.

1단계 — 페이로드 주입 (인증 없음)

공격자는 메시지 필드에 직렬화된 PHP 객체를 넣어 CF7 양식을 제출합니다.

  • 엔드포인트: POST /wp-json/contact-form-7/v1/contact-forms/{id}/feedback
  • your-message 필드에 포함: O:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}
  • 플러그인이 페이로드를 wp_vxcf_leads_detail 테이블에 저장 — sanitize_text_field()는 직렬화된 문자열을 차단하지 않음

2단계 — 역직렬화 트리거 (관리자 대기)

관리자가 Contact Form Entries 페이지를 열고 → 항목 세부 정보를 조회하면 → 플러그인이 verify_val()을 호출하고 → maybe_unserialize()가 실행됩니다.

도구 다운로드