Skip to content

Commit 7731252

Browse files
jvoisinSjoerd Langkemper
authored andcommitted
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 php#10453
1 parent c0af268 commit 7731252

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

ext/standard/php_fopen_wrapper.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "php_memory_streams.h"
2727
#include "php_fopen_wrappers.h"
2828
#include "SAPI.h"
29+
#include "zend_exceptions.h"
2930

3031
static ssize_t php_stream_output_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
3132
{
@@ -144,13 +145,22 @@ static const php_stream_ops php_stream_input_ops = {
144145
NULL /* set_option */
145146
};
146147

148+
static const char max_stream_filters = 5;
149+
147150
static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain) /* {{{ */
148151
{
149152
char *p, *token = NULL;
150153
php_stream_filter *temp_filter;
154+
char nb_filters = 0;
151155

152156
p = php_strtok_r(filterlist, "|", &token);
153157
while (p) {
158+
if (nb_filters >= max_stream_filters) {
159+
zend_throw_exception_ex(NULL, 0, "Unable to apply filter, maximum number (%d) reached", max_stream_filters);
160+
return;
161+
}
162+
nb_filters++;
163+
154164
php_url_decode(p, strlen(p));
155165
if (read_chain) {
156166
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)