Backported from 5.6.25 by Remi. From 27fe2b42fc4a0e82b30dba11e177611ac6a88bf5 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 7 Aug 2016 15:16:28 -0700 Subject: [PATCH] Fix bug #70436: Use After Free Vulnerability in unserialize() --- ext/standard/tests/strings/bug70436.phpt | 65 ++++++++++++++++++++++++++++++++ ext/standard/var.c | 1 + 2 files changed, 66 insertions(+) create mode 100644 ext/standard/tests/strings/bug70436.phpt diff --git a/ext/standard/tests/strings/bug70436.phpt b/ext/standard/tests/strings/bug70436.phpt new file mode 100644 index 0000000..c62e468 --- /dev/null +++ b/ext/standard/tests/strings/bug70436.phpt @@ -0,0 +1,65 @@ +--TEST-- +Bug #70436: Use After Free Vulnerability in unserialize() +--FILE-- +data); + } + + function unserialize($data) + { + $this->data = unserialize($data); + } +} + +$fakezval = ptr2str(1122334455); +$fakezval .= ptr2str(0); +$fakezval .= "\x00\x00\x00\x00"; +$fakezval .= "\x01"; +$fakezval .= "\x00"; +$fakezval .= "\x00\x00"; + +$inner = 'C:3:"obj":3:{ryat'; +$exploit = 'a:4:{i:0;i:1;i:1;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:2;s:'.strlen($fakezval).':"'.$fakezval.'";i:3;R:5;}'; + +$data = unserialize($exploit); + +var_dump($data); + +function ptr2str($ptr) +{ + $out = ''; + + for ($i = 0; $i < 8; $i++) { + $out .= chr($ptr & 0xff); + $ptr >>= 8; + } + + return $out; +} +?> +DONE +--EXPECTF-- +Notice: unserialize(): Error at offset 0 of 3 bytes in %sbug70436.php on line %d + +Notice: unserialize(): Error at offset 17 of 17 bytes in %sbug70436.php on line %d +array(4) { + [0]=> + int(1) + [1]=> + object(obj)#%d (1) { + ["data"]=> + bool(false) + } + [2]=> + string(24) "%s" + [3]=> + bool(false) +} +DONE \ No newline at end of file diff --git a/ext/standard/var.c b/ext/standard/var.c index f0efef2..137e794 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -965,6 +965,7 @@ PHP_FUNCTION(unserialize) p = (const unsigned char*) buf; PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) { + var_push_dtor(&var_hash, &return_value); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); zval_dtor(return_value); if (!EG(exception)) {