php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73131 Use-after-free in php_var_serialize_intern
Submitted: 2016-09-20 17:23 UTC Modified: 2016-09-21 07:33 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: ahihibughunter at gmail dot com Assigned:
Status: Open Package: Session related
PHP Version: 5.6.26 OS: ALL
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: ahihibughunter at gmail dot com
New email:
PHP Version: OS:

 

 [2016-09-20 17:23 UTC] ahihibughunter at gmail dot com
Description:
------------
static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC) /* {{{ */
{
 ....
 switch (Z_TYPE_P(struc)) {
 ...
  case IS_ARRAY: {
  ...
  if (Z_TYPE_PP(data) == IS_ARRAY) {
	php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC);   <----------- call php_var_serialize_intern again with new data
...
}

Free the memory when call to call_user_function_ex

static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC) /* {{{ */
{
 ....
 switch (Z_TYPE_P(struc)) {
  ....
  case IS_OBJECT: {
  ....
   if (ce && ce != PHP_IC_ENTRY && zend_hash_exists(&ce->function_table, "__sleep", sizeof("__sleep"))) {
   ...
   res = call_user_function_ex(CG(function_table), &struc, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
   ...
}

.....
.....
/php-src-PHP-5.6.26/Zend/zend_execute.h:80
		efree_rel(zval_ptr); <------------------------ Free the memory


And memory reused

static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var_hash TSRMLS_DC) /* {{{ */
{
 ...
 case IS_OBJECT: {
 ...
  if (res == SUCCESS) {
   if (retval_ptr) {
	 if (HASH_OF(retval_ptr)) {
		php_var_serialize_class(buf, struc, retval_ptr, var_hash TSRMLS_CC);   <----------------------- BOOM
 ...
}


Test script:
---------------
<?php
class Ahihi {};
class Ihaha
{
    function __sleep()
    {
	new Ahihi;
	$_SESSION['ihaha'] = "gogogo";
	return array();
    }
}

session_start();
$_SESSION['ihaha']['boom'] = new Ihaha;
?>




Expected result:
----------------
No crash

Actual result:
--------------
$ gdb php-src-PHP-5.6.26/sapi/cli/php 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
..
(gdb) r crash.php 
Starting program: /home/s/php/php-src-PHP-5.6.26/sapi/cli/php crash.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".


Program received signal SIGSEGV, Segmentation fault.
0x0000000000927a21 in php_var_serialize_class_name (buf=0x7fffffffcd10, struc=0x7ffff7fc9e00)
    at /home/s/php/php-src-PHP-5.6.26/ext/standard/var.c:607
607		PHP_SET_CLASS_ATTRIBUTES(struc);
(gdb) (gdb) print *struc
$1 = {value = {lval = 6510615555426900570, dval = 1.7838867517321418e+127, str = {
      val = 0x5a5a5a5a5a5a5a5a <error: Cannot access memory at address 0x5a5a5a5a5a5a5a5a>, len = 1515870810}, 
    ht = 0x5a5a5a5a5a5a5a5a, obj = {handle = 1515870810, handlers = 0x5a5a5a5a5a5a5a5a}, ast = 0x5a5a5a5a5a5a5a5a}, 
  refcount__gc = 1515870810, type = 90 'Z', is_ref__gc = 90 'Z'}
gdb) bt
#0  0x0000000000927a21 in php_var_serialize_class_name (buf=0x7fffffffcd10, struc=0x7ffff7fc9e00)
    at /home/s/php/php-src-PHP-5.6.26/ext/standard/var.c:607
#1  0x00000000009283bf in php_var_serialize_class (buf=0x7fffffffcd10, struc=0x7ffff7fc9e00, 
    retval_ptr=0x7ffff7fcb678, var_hash=0x7ffff7fcb0f8) at /home/s/php/php-src-PHP-5.6.26/ext/standard/var.c:623
#2  0x000000000092c1c1 in php_var_serialize_intern (buf=0x7fffffffcd10, struc=0x7ffff7fc9e00, var_hash=0x7ffff7fcb0f8)
    at /home/s/php/php-src-PHP-5.6.26/ext/standard/var.c:813
#3  0x000000000092cd72 in php_var_serialize_intern (buf=0x7fffffffcd10, struc=0x7ffff7fccf90, var_hash=0x7ffff7fcb0f8)
    at /home/s/php/php-src-PHP-5.6.26/ext/standard/var.c:886
#4  0x000000000092d0cd in php_var_serialize (buf=0x7fffffffcd10, struc=0x7ffff7fcea08, var_hash=0x7fffffffccd0)
    at /home/s/php/php-src-PHP-5.6.26/ext/standard/var.c:905
#5  0x00000000007fc8b6 in ps_srlzr_encode_php (newstr=0x7fffffffcd68, newlen=0x7fffffffcd80)
    at /home/s/php/php-src-PHP-5.6.26/ext/session/session.c:988
#6  0x00000000007f9a73 in php_session_encode (newlen=0x7fffffffcd80)
    at /home/s/php/php-src-PHP-5.6.26/ext/session/session.c:209
#7  0x00000000007fa72d in php_session_save_current_state () at /home/s/php/php-src-PHP-5.6.26/ext/session/session.c:542
#8  0x000000000080041a in php_session_flush () at /home/s/php/php-src-PHP-5.6.26/ext/session/session.c:1646
#9  0x00000000008027ff in zm_deactivate_session (type=1, module_number=28)
    at /home/s/php/php-src-PHP-5.6.26/ext/session/session.c:2415
#10 0x0000000000ab451f in zend_deactivate_modules () at /home/s/php/php-src-PHP-5.6.26/Zend/zend_API.c:2488
#11 0x0000000000a0e158 in php_request_shutdown (dummy=0x0) at /home/s/php/php-src-PHP-5.6.26/main/main.c:1867
#12 0x0000000000b5f4af in do_cli (argc=2, argv=0x1457a20) at /home/s/php/php-src-PHP-5.6.26/sapi/cli/php_cli.c:1177
#13 0x0000000000b5fd39 in main (argc=2, argv=0x1457a20) at /home/s/php/php-src-PHP-5.6.26/sapi/cli/php_cli.c:1378



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-20 17:39 UTC] stas@php.net
-Type: Security +Type: Bug
 [2016-09-20 23:05 UTC] ahihibughunter at gmail dot com
Hi stas,
Can I know why this Use-After-Free is not security issue? I think it critical more than other null pointer dereference or integer overflow because this kind of issue can lead to code execution easier than others.
Thanks
 [2016-09-21 07:25 UTC] yohgaki@php.net
Because it requires to control script, not external data.

It's possible to inject PHP script to system and exploit. However, if PHP script could be injected, attackers can do anything with injected PHP scripts without using null pointer dereference.

It may be used to workaround open_basedir restriction, but PHP does not provide full virtual environment nor perfect security in the first place. There are number of ways to workaround the restriction by using simple PHP code.
 [2016-09-21 07:33 UTC] ahihibughunter at gmail dot com
Ok, thanks for your explanation.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Fri Dec 13 21:01:24 2019 UTC