summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Fuhrmannek2014-07-14 13:08:16 +0200
committerBen Fuhrmannek2014-07-14 13:08:16 +0200
commit81435af6f665c73e46562cf1489aaa3f0435b615 (patch)
tree55bff05b6b568d1e25bbb9559bcec6fb3c8b31d6
parent1dc59e48642c98e34320f1a31c120fbf290fd509 (diff)
parent6bb8cdbbd56c09a6864b40ce21f9a87abd942305 (diff)
Merge branch 'filter'
-rw-r--r--ifilter.c2
-rw-r--r--php_suhosin.h1
-rw-r--r--suhosin.c1
-rw-r--r--tests/filter/suhosin_upload_disallow_binary_utf8.phpt44
-rw-r--r--tests/filter/suhosin_upload_disallow_binary_utf8fail.phpt45
-rw-r--r--tests/filter/suhosin_upload_remove_binary.phptbin0 -> 796 bytes
-rw-r--r--tests/filter/suhosin_upload_remove_binary_utf8.phpt32
-rw-r--r--tests/filter/suhosin_upload_remove_binary_utf8fail.phpt32
-rw-r--r--ufilter.c108
9 files changed, 233 insertions, 32 deletions
diff --git a/ifilter.c b/ifilter.c
index cd02869..8b2e8a3 100644
--- a/ifilter.c
+++ b/ifilter.c
@@ -366,7 +366,7 @@ unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int v
366 } 366 }
367 367
368 /* Drop this variable if it begins with whitespace which is disallowed */ 368 /* Drop this variable if it begins with whitespace which is disallowed */
369 if (*var == ' ') { 369 if (isspace(*var)) {
370 if (SUHOSIN_G(disallow_ws)) { 370 if (SUHOSIN_G(disallow_ws)) {
371 suhosin_log(S_VARS, "request variable name begins with disallowed whitespace - dropped variable '%s'", var); 371 suhosin_log(S_VARS, "request variable name begins with disallowed whitespace - dropped variable '%s'", var);
372 if (!SUHOSIN_G(simulation)) { 372 if (!SUHOSIN_G(simulation)) {
diff --git a/php_suhosin.h b/php_suhosin.h
index e85fc38..4b460e4 100644
--- a/php_suhosin.h
+++ b/php_suhosin.h
@@ -151,6 +151,7 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin)
151 zend_bool upload_disallow_elf; 151 zend_bool upload_disallow_elf;
152 zend_bool upload_disallow_binary; 152 zend_bool upload_disallow_binary;
153 zend_bool upload_remove_binary; 153 zend_bool upload_remove_binary;
154 zend_bool upload_allow_utf8;
154 char *upload_verification_script; 155 char *upload_verification_script;
155 156
156 zend_bool no_more_variables; 157 zend_bool no_more_variables;
diff --git a/suhosin.c b/suhosin.c
index 469e88f..f57e85a 100644
--- a/suhosin.c
+++ b/suhosin.c
@@ -986,6 +986,7 @@ PHP_INI_BEGIN()
986 STD_PHP_INI_ENTRY("suhosin.upload.disallow_elf", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_elf, zend_suhosin_globals, suhosin_globals) 986 STD_PHP_INI_ENTRY("suhosin.upload.disallow_elf", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_elf, zend_suhosin_globals, suhosin_globals)
987 STD_PHP_INI_ENTRY("suhosin.upload.disallow_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_binary, zend_suhosin_globals, suhosin_globals) 987 STD_PHP_INI_ENTRY("suhosin.upload.disallow_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_binary, zend_suhosin_globals, suhosin_globals)
988 STD_PHP_INI_ENTRY("suhosin.upload.remove_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_remove_binary, zend_suhosin_globals, suhosin_globals) 988 STD_PHP_INI_ENTRY("suhosin.upload.remove_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_remove_binary, zend_suhosin_globals, suhosin_globals)
989 STD_PHP_INI_ENTRY("suhosin.upload.allow_utf8", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_allow_utf8, zend_suhosin_globals, suhosin_globals)
989 STD_PHP_INI_ENTRY("suhosin.upload.verification_script", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadString, upload_verification_script, zend_suhosin_globals, suhosin_globals) 990 STD_PHP_INI_ENTRY("suhosin.upload.verification_script", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadString, upload_verification_script, zend_suhosin_globals, suhosin_globals)
990 991
991 992
diff --git a/tests/filter/suhosin_upload_disallow_binary_utf8.phpt b/tests/filter/suhosin_upload_disallow_binary_utf8.phpt
new file mode 100644
index 0000000..557a8d5
--- /dev/null
+++ b/tests/filter/suhosin_upload_disallow_binary_utf8.phpt
@@ -0,0 +1,44 @@
1--TEST--
2Testing: suhosin.upload.disallow_binary=On with UTF-8
3--INI--
4suhosin.log.syslog=0
5suhosin.log.sapi=0
6suhosin.log.stdout=255
7suhosin.log.script=0
8file_uploads=1
9suhosin.upload.disallow_binary=On
10suhosin.upload.allow_utf8=On
11max_file_uploads=40
12suhosin.upload.max_uploads=40
13--SKIPIF--
14<?php include('skipif.inc'); ?>
15--COOKIE--
16--GET--
17--POST_RAW--
18Content-Type: multipart/form-data; boundary=bound
19--bound
20Content-Disposition: form-data; name="test"; filename="test"
21
22Spaß am Gerät!
23
24--bound--
25--FILE--
26<?php
27var_dump($_FILES);
28?>
29--EXPECTF--
30array(1) {
31 ["test"]=>
32 array(5) {
33 ["name"]=>
34 string(4) "test"
35 ["type"]=>
36 string(0) ""
37 ["tmp_name"]=>
38 string(%d) "%s"
39 ["error"]=>
40 int(0)
41 ["size"]=>
42 int(17)
43 }
44}
diff --git a/tests/filter/suhosin_upload_disallow_binary_utf8fail.phpt b/tests/filter/suhosin_upload_disallow_binary_utf8fail.phpt
new file mode 100644
index 0000000..413d25a
--- /dev/null
+++ b/tests/filter/suhosin_upload_disallow_binary_utf8fail.phpt
@@ -0,0 +1,45 @@
1--TEST--
2Testing: suhosin.upload.disallow_binary=On with UTF-8 and allow_utf8=Off
3--INI--
4suhosin.log.syslog=0
5suhosin.log.sapi=0
6suhosin.log.stdout=255
7suhosin.log.script=0
8file_uploads=1
9suhosin.upload.disallow_binary=On
10suhosin.upload.allow_utf8=Off
11max_file_uploads=40
12suhosin.upload.max_uploads=40
13--SKIPIF--
14<?php include('skipif.inc'); ?>
15--COOKIE--
16--GET--
17--POST_RAW--
18Content-Type: multipart/form-data; boundary=bound
19--bound
20Content-Disposition: form-data; name="test"; filename="test"
21
22Spaß am Gerät!
23
24--bound--
25--FILE--
26<?php
27var_dump($_FILES);
28?>
29--EXPECTF--
30array(1) {
31 ["test"]=>
32 array(5) {
33 ["name"]=>
34 string(4) "test"
35 ["type"]=>
36 string(0) ""
37 ["tmp_name"]=>
38 string(0) ""
39 ["error"]=>
40 int(8)
41 ["size"]=>
42 int(0)
43 }
44}
45ALERT - uploaded file contains binary data - file dropped (attacker 'REMOTE_ADDR not set', file '%s')
diff --git a/tests/filter/suhosin_upload_remove_binary.phpt b/tests/filter/suhosin_upload_remove_binary.phpt
new file mode 100644
index 0000000..f4337d9
--- /dev/null
+++ b/tests/filter/suhosin_upload_remove_binary.phpt
Binary files differ
diff --git a/tests/filter/suhosin_upload_remove_binary_utf8.phpt b/tests/filter/suhosin_upload_remove_binary_utf8.phpt
new file mode 100644
index 0000000..6fbd240
--- /dev/null
+++ b/tests/filter/suhosin_upload_remove_binary_utf8.phpt
@@ -0,0 +1,32 @@
1--TEST--
2Testing: suhosin.upload.remove_binary=On with UTF-8
3--INI--
4suhosin.log.syslog=0
5suhosin.log.sapi=0
6suhosin.log.stdout=255
7suhosin.log.script=0
8file_uploads=1
9suhosin.upload.disallow_binary=Off
10suhosin.upload.remove_binary=On
11suhosin.upload.allow_utf8=On
12max_file_uploads=40
13suhosin.upload.max_uploads=40
14--SKIPIF--
15<?php include('skipif.inc'); ?>
16--COOKIE--
17--GET--
18--POST_RAW--
19Content-Type: multipart/form-data; boundary=bound
20--bound
21Content-Disposition: form-data; name="test"; filename="test"
22
23Spaß am Gerät!
24
25--bound--
26--FILE--
27<?php
28var_dump(file_get_contents($_FILES['test']['tmp_name']));
29?>
30--EXPECTF--
31string(17) "Spaß am Gerät!
32" \ No newline at end of file
diff --git a/tests/filter/suhosin_upload_remove_binary_utf8fail.phpt b/tests/filter/suhosin_upload_remove_binary_utf8fail.phpt
new file mode 100644
index 0000000..5c31115
--- /dev/null
+++ b/tests/filter/suhosin_upload_remove_binary_utf8fail.phpt
@@ -0,0 +1,32 @@
1--TEST--
2Testing: suhosin.upload.remove_binary=On with UTF-8 and allow_utf8=Off
3--INI--
4suhosin.log.syslog=0
5suhosin.log.sapi=0
6suhosin.log.stdout=255
7suhosin.log.script=0
8file_uploads=1
9suhosin.upload.disallow_binary=Off
10suhosin.upload.remove_binary=On
11suhosin.upload.allow_utf8=Off
12max_file_uploads=40
13suhosin.upload.max_uploads=40
14--SKIPIF--
15<?php include('skipif.inc'); ?>
16--COOKIE--
17--GET--
18--POST_RAW--
19Content-Type: multipart/form-data; boundary=bound
20--bound
21Content-Disposition: form-data; name="test"; filename="test"
22
23Spaß am Gerät!
24
25--bound--
26--FILE--
27<?php
28var_dump(file_get_contents($_FILES['test']['tmp_name']));
29?>
30--EXPECTF--
31string(13) "Spa am Gert!
32" \ No newline at end of file
diff --git a/ufilter.c b/ufilter.c
index 5a85b54..6d9669f 100644
--- a/ufilter.c
+++ b/ufilter.c
@@ -197,6 +197,29 @@ return_failure:
197} 197}
198/* }}} */ 198/* }}} */
199 199
200static inline int suhosin_validate_utf8_multibyte(const char* cp)
201{
202 if ((*cp & 0xe0) == 0xc0 && // 1st byte is 110xxxxx
203 (*(cp+1) & 0xc0) == 0x80 && // 2nd byte is 10xxxxxx
204 (*cp & 0x1e)) { // overlong check 110[xxxx]x 10xxxxxx
205 return 2;
206 }
207 if ((*cp & 0xf0) == 0xe0 && // 1st byte is 1110xxxx
208 (*(cp+1) & 0xc0) == 0x80 && // 2nd byte is 10xxxxxx
209 (*(cp+2) & 0xc0) == 0x80 && // 3rd byte is 10xxxxxx
210 ((*cp & 0x0f) | (*(cp+1) & 0x20))) { // 1110[xxxx] 10[x]xxxxx 10xxxxxx
211 return 3;
212 }
213 if ((*cp & 0xf8) == 0xf0 && // 1st byte is 11110xxx
214 (*(cp+1) & 0xc0) == 0x80 && // 2nd byte is 10xxxxxx
215 (*(cp+2) & 0xc0) == 0x80 && // 3rd byte is 10xxxxxx
216 (*(cp+3) & 0xc0) == 0x80 && // 4th byte is 10xxxxxx
217 ((*cp & 0x07) | (*(cp+1) & 0x30))) { // 11110[xxx] 10[xx]xxxx 10xxxxxx 10xxxxxx
218 return 4;
219 }
220 return 0;
221}
222
200int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TSRMLS_DC) 223int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TSRMLS_DC)
201{ 224{
202 int retval = SUCCESS; 225 int retval = SUCCESS;
@@ -250,38 +273,61 @@ int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TS
250 } 273 }
251 } 274 }
252 275
253 if (SUHOSIN_G(upload_disallow_binary)) { 276 if (SUHOSIN_G(upload_disallow_binary)) {
254 277
255 multipart_event_file_data *mefd = (multipart_event_file_data *) event_data; 278 multipart_event_file_data *mefd = (multipart_event_file_data *) event_data;
256 size_t i;
257
258 for (i=0; i<mefd->length; i++) {
259 if (mefd->data[i] < 32 && !isspace(mefd->data[i])) {
260 suhosin_log(S_FILES, "uploaded file contains binary data - file dropped");
261 if (!SUHOSIN_G(simulation)) {
262 goto continue_with_failure;
263 }
264 }
265 }
266 }
267 279
268 if (SUHOSIN_G(upload_remove_binary)) { 280 char *cp, *cpend;
269 281 int n;
270 multipart_event_file_data *mefd = (multipart_event_file_data *) event_data; 282 cpend = mefd->data + mefd->length;
271 size_t i, j; 283 for (char *cp = mefd->data; cp < cpend; cp++) {
272 284 if (*cp >= 32 || isspace(*cp)) {
273 for (i=0, j=0; i<mefd->length; i++) { 285 continue;
274 if (mefd->data[i] >= 32 || isspace(mefd->data[i])) { 286 }
275 mefd->data[j++] = mefd->data[i]; 287 if ((*cp & 0x80) && SUHOSIN_G(upload_allow_utf8)) {
276 } 288 SDEBUG("checking char %x", *cp);
277 } 289 if ((n = suhosin_validate_utf8_multibyte(cp))) { // valid UTF8 multibyte character
278 SDEBUG("removing binary %u %u",i,j); 290 cp += n - 1;
279 /* IMPORTANT FOR DAISY CHAINING */ 291 continue;
280 mefd->length = j; 292 }
281 if (mefd->newlength) { 293 }
282 *mefd->newlength = j; 294
283 } 295 suhosin_log(S_FILES, "uploaded file contains binary data - file dropped");
284 } 296 if (!SUHOSIN_G(simulation)) {
297 goto continue_with_failure;
298 }
299 break;
300 }
301 }
302
303 if (SUHOSIN_G(upload_remove_binary)) {
304
305 multipart_event_file_data *mefd = (multipart_event_file_data *) event_data;
306 size_t i, j;
307 int n;
308
309 for (i=0, j=0; i<mefd->length; i++) {
310 if (mefd->data[i] >= 32 || isspace(mefd->data[i])) {
311 mefd->data[j++] = mefd->data[i];
312 } else if (SUHOSIN_G(upload_allow_utf8) && mefd->data[i] & 0x80) {
313 n = suhosin_validate_utf8_multibyte(mefd->data + i);
314 if (!n) { continue; }
315 while (n) {
316 mefd->data[j++] = mefd->data[i++];
317 n--;
318 }
319 i--;
320 }
321 }
322 mefd->data[j] = '\0';
323
324 SDEBUG("removing binary %zu %zu",i,j);
325 /* IMPORTANT FOR DAISY CHAINING */
326 mefd->length = j;
327 if (mefd->newlength) {
328 *mefd->newlength = j;
329 }
330 }
285 331
286 break; 332 break;
287 333