Skip to content

Commit 6f618a9

Browse files
committed
Limit the number of filters
Chaining filters is becoming an increasingly popular primitive to exploit PHP applications. Limiting the usage of only a few of them at the time should, if not close entirely, make it significantly less attractive. This should close #10453
1 parent fa15ac5 commit 6f618a9

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

ext/standard/php_fopen_wrapper.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "php_memory_streams.h"
2929
#include "php_fopen_wrappers.h"
3030
#include "SAPI.h"
31+
#include "zend_exceptions.h"
3132

3233
static ssize_t php_stream_output_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
3334
{
@@ -146,13 +147,22 @@ static const php_stream_ops php_stream_input_ops = {
146147
NULL /* set_option */
147148
};
148149

150+
static const char max_stream_filters = 5;
151+
149152
static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */
150153
{
151154
char *p, *token = NULL;
152155
php_stream_filter *temp_filter;
156+
char nb_filters = 0;
153157

154158
p = php_strtok_r(filterlist, "|", &token);
155159
while (p) {
160+
if (nb_filters >= max_stream_filters) {
161+
zend_throw_exception_ex(NULL, 0, "Unable to apply filter, maximum number (%d) reached", max_stream_filters);
162+
return;
163+
}
164+
nb_filters++;
165+
156166
php_url_decode(p, strlen(p));
157167
if (read_chain) {
158168
if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream)))) {

tests/security/bug10453.phpt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Bug #10453 (using a high amount of filters for nefarious purposes)
3+
--FILE--
4+
<?php
5+
$fp = fopen('php://output', 'w');
6+
for($i=0; $i<10; $i++)
7+
stream_filter_append($fp, 'string.rot13');
8+
fwrite($fp, "This is a test.\n");
9+
10+
$fp = fopen('php://filter/write=string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13|string.rot13/resource=php://output', 'w');
11+
fwrite($fp, "This is a test.\n");
12+
?>
13+
--EXPECTF--
14+
This is a test.
15+
16+
Fatal error: Uncaught Exception: Unable to apply filter, maximum number (5) reached in %s
17+
Stack trace:
18+
#0 %s: fopen('php://filter/wr...', 'w')
19+
#1 {main}
20+
thrown in %s

0 commit comments

Comments
 (0)