1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
Backported from 5.6.25 by Remi.
From c1cfd6a9fe23765191ea2f654790c7b127d4b797 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Tue, 2 Aug 2016 01:08:42 -0700
Subject: [PATCH] Fix bug #72663 - destroy broken object when unserializing
---
ext/standard/tests/strings/bug72663.phpt | 26 +++++++++++
ext/standard/tests/strings/bug72663_2.phpt | 17 ++++++++
ext/standard/var_unserializer.c | 70 ++++++++++++++++--------------
ext/standard/var_unserializer.re | 5 ++-
4 files changed, 84 insertions(+), 34 deletions(-)
create mode 100644 ext/standard/tests/strings/bug72663.phpt
create mode 100644 ext/standard/tests/strings/bug72663_2.phpt
diff --git a/ext/standard/tests/strings/bug72663.phpt b/ext/standard/tests/strings/bug72663.phpt
new file mode 100644
index 0000000..e61f939
--- /dev/null
+++ b/ext/standard/tests/strings/bug72663.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Bug #72663: Create an Unexpected Object and Don't Invoke __wakeup() in Deserialization
+--FILE--
+<?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];
+?>
+DONE
+--EXPECTF--
+Notice: unserialize(): Unexpected end of serialized data in %sbug72663.php on line %d
+
+Notice: unserialize(): Error at offset 46 of 47 bytes in %sbug72663.php on line %d
+DONE
\ No newline at end of file
diff --git a/ext/standard/tests/strings/bug72663_2.phpt b/ext/standard/tests/strings/bug72663_2.phpt
new file mode 100644
index 0000000..ac605e9
--- /dev/null
+++ b/ext/standard/tests/strings/bug72663_2.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #72663: Create an Unexpected Object and Don't Invoke __wakeup() in Deserialization
+--FILE--
+<?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);
+var_dump($_SESSION);
+?>
+DONE
+--EXPECTF--
+Notice: session_decode(): Unexpected end of serialized data in %sbug72663_2.php on line %d
+array(0) {
+}
+DONE
\ No newline at end of file
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 1e45b03..e4ddecf 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -437,6 +437,9 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
}
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
+ /* We've got partially constructed object on our hands here. Wipe it */
+ zend_hash_clean(Z_OBJPROP_PP(rval));
+ ZVAL_NULL(*rval);
return 0;
}
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index d1d4ef9..c1c18c9 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -443,6 +443,9 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
}
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
+ /* We've got partially constructed object on our hands here. Wipe it. */
+ zend_hash_clean(Z_OBJPROP_PP(rval));
+ ZVAL_NULL(*rval);
return 0;
}
From b25f44098fdc8cecfd62d0fc5422c23d8747dcd2 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Thu, 4 Aug 2016 00:03:31 -0700
Subject: [PATCH] Update comment
---
ext/standard/var_unserializer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index e4ddecf..1d459ae 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -437,7 +437,7 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
}
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
- /* We've got partially constructed object on our hands here. Wipe it */
+ /* We've got partially constructed object on our hands here. Wipe it. */
zend_hash_clean(Z_OBJPROP_PP(rval));
ZVAL_NULL(*rval);
return 0;
From 75c0dbdd028ffa20eae5cf3a2fae194961464b8b Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Sun, 7 Aug 2016 15:33:29 -0700
Subject: [PATCH] Improve fix for #72663
---
ext/standard/tests/strings/bug72663_3.phpt | 18 ++++++++
ext/standard/var_unserializer.c | 68 ++++++++++++++++--------------
ext/standard/var_unserializer.re | 8 +++-
3 files changed, 62 insertions(+), 32 deletions(-)
create mode 100644 ext/standard/tests/strings/bug72663_3.phpt
diff --git a/ext/standard/tests/strings/bug72663_3.phpt b/ext/standard/tests/strings/bug72663_3.phpt
new file mode 100644
index 0000000..e336bc8
--- /dev/null
+++ b/ext/standard/tests/strings/bug72663_3.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #72663: Create an Unexpected Object and Don't Invoke __wakeup() in Deserialization
+--FILE--
+<?php
+class obj {
+ var $ryat;
+ function __wakeup() {
+ $this->ryat = str_repeat('A', 0x112);
+ }
+}
+
+$poc = 'O:8:"stdClass":1:{i:0;O:3:"obj":1:{s:4:"ryat";R:1;';
+unserialize($poc);
+?>
+DONE
+--EXPECTF--
+Notice: unserialize(): Error at offset 51 of 50 bytes in %sbug72663_3.php on line %d
+DONE
\ No newline at end of file
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 1d459ae..c8e6f8a 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -438,11 +438,17 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
/* We've got partially constructed object on our hands here. Wipe it. */
- zend_hash_clean(Z_OBJPROP_PP(rval));
+ if(Z_TYPE_PP(rval) == IS_OBJECT) {
+ zend_hash_clean(Z_OBJPROP_PP(rval));
+ }
ZVAL_NULL(*rval);
return 0;
}
+ if (Z_TYPE_PP(rval) != IS_OBJECT) {
+ 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);
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index c1c18c9..11b93c5 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -444,11 +444,17 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
/* We've got partially constructed object on our hands here. Wipe it. */
- zend_hash_clean(Z_OBJPROP_PP(rval));
+ if(Z_TYPE_PP(rval) == IS_OBJECT) {
+ zend_hash_clean(Z_OBJPROP_PP(rval));
+ }
ZVAL_NULL(*rval);
return 0;
}
+ if (Z_TYPE_PP(rval) != IS_OBJECT) {
+ 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);
|