PHP serialization 취약점에 대해서 다시 접하게 되었다. 관련된 내용을 찾아보니 그 내용이 간단하지만은 않아 따로 정리하게 되었다.
PHP에는 serialize
라는 기능이 존재한다.
데이터를 직렬화하여 저장하거나, 전달하는 등 관리측면에서 효율성을 얻기 위해 만들어졌다.
사용되는 함수를 확인해보자.
serialize ( mixed $value ) : string
인자로 전달되는 값을 직렬화시켜 문자열 형태로 반환한다.
value
The value to be serialized. serialize() handles all types, except the resource-type and some objects (see note below).
인자는 일부 오브젝트, 리소스타입을 제외하고 모든 유형이 전달될 수 있다고 한다.
데이터를 직렬화시킨 값들의 유형을 살펴보자.
String s:size:value; Integer i:value; Boolean b:value; (does not store "true" or "false", does store '1' or '0') Null N; Array a:size:{key definition;value definition;(repeated per element)} Object O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}
이런 직렬화 기능이 왜 문제가 되는 것일까?
직렬화 기능자체에는 문제가 없다.
직렬화 기능이 수행될 때 자동적으로 실행되는 magic method에서 취약점이 발생한다.
magic method란 특정 PHP events에 대응해 자동실행하여 기능을 수행하는 함수를 말한다.
__
로 시작하며, 생성자나 소멸자의 기능을 하여 객체가 생성되고 소멸될 때 실행되는 __construct
, __destruct
도 이에 해당한다.
https://lornajane.net/posts/2012/9-magic-methods-in-php
자세한 종류는 링크를 확인하자.
오브젝트는 클래스가 인스턴스화된 객체를 말한다.
안에는 그 오브젝트의 메소드, 변수 등 관련된 값이 포함되어있다.
serialize로 인해 이런 오브젝트 값을 직렬화시켜 외부에 전달하거나 전달받아 관련된 처리를 하는 형태의 코드를 작성할 수 있게 되었다.
하지만 이런 구조의 웹서버에 변조된 오브젝트를 전달한다면?
웹서버는 조작된 값을 그대로 받아 의도하지 않은 데이터나 코드를 실행할 것이다.
이게 바로 php의 serialize에 의해 발생할 수 있는 Object Injection 취약점이다.
오브젝트 인젝션을 활용해서 데이터 변조, 코드 인젝션 등 다양한 악의적인 행동을 유발할 수 있다.
OWASP에 나와있는 몇가지 예제를 이용해 살펴보겠다.
class Example1
{
public $cache_file;
function __construct()
{
// some PHP code...
}
function __destruct()
{
$file = "/var/www/cache/tmp/{$this->cache_file}";
if (file_exists($file)) @unlink($file);
}
}
// some PHP code...
$user_data = unserialize($_GET['data']);
// some PHP code...
Example1
이라는 클래스가 선언되어있고 GET
파라미터로 데이터를 전달받아 unserialize()
을 실행한다.
만약 다음의 데이터를 전달한다면
http://testsite.com/vuln.php?data=O:8:"Example1":1:{s:10:"cache_file";s:15:"../../index.php";}
cache_file
에 내가 설정한 ../../index.php라는 값이 저장될 것이다.
class Example2
{
private $hook;
function __construct()
{
// some PHP code...
}
function __wakeup()
{
if (isset($this->hook)) eval($this->hook);
}
}
// some PHP code...
$user_data = unserialize($_COOKIE['data']);
// some PHP code...
hook
변수의 값이 __wakeup()
이 실행될 때 코드로서 실행된다.
__wakeup()
은 unserialize()
가 실행될 때 trigger되는 magic method이다.
내가 조작된 hook
이 포함되어있는 오브젝트를 인젝션 한다면 unserialize
할 때 __wakeup()
이 실행되면서 내가 조작한 코드가 실행될 것이다.
GET /vuln.php HTTP/1.0
Host: testsite.com
Cookie: data=O%3A8%3A%22Example2%22%3A1%3A%7Bs%3A14%3A%22%00Example2%00hook%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D
Connection: close
다른 예제들도 같은 방식을 이용하는 것이다.
또한, 위에서는 변수값만 변조했지만 대상을 함수로 바꾼다면 변조된 함수를 실행시킬 수 있을 것이다.
phar에서도 직렬화된 데이터를 사용하는 구간이 있고 같은 방식의 취약점을 확인할 수 있다고 한다.
https://www.hahwul.com/2018/11/phar-php-deserialization-vulnerability.html
https://securitycafe.ro/2015/01/05/understanding-php-object-injection/
: Object Injection 설명
https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
: OWASP