Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: log and optionally terminate function_exists()-calls on non-whitelisted or blacklisted functions #31

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- Fix read after efree() that lets function_exists() malfunction
- Fix build with clang compiler
- Added a request variable drop statistic log message
- Added optional logging and termination of function_exists()-calls on non-whitelisted
or blacklisted function-names, including new error class S_EXISTENCE

2012-01-19 - 0.9.33

Expand Down
16 changes: 16 additions & 0 deletions execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1078,21 +1078,37 @@ static int ih_function_exists(IH_HANDLER_PARAMS)
if (SUHOSIN_G(in_code_type) == SUHOSIN_EVAL) {
if (SUHOSIN_G(eval_whitelist) != NULL) {
if (!zend_hash_exists(SUHOSIN_G(eval_whitelist), lcname, func_name_len+1)) {
suhosin_log(S_EXISTENCE, "evaluated existence of a function not within eval whitelist: eval('function_exists(\"%s\");')", lcname);
if (SUHOSIN_G(eval_exists_forbidden) && !SUHOSIN_G(simulation)) {
zend_error(E_ERROR, "SUHOSIN - Evaluating existence of functions not within eval whitelist is forbidden by configuration");
}
retval = 0;
}
} else if (SUHOSIN_G(eval_blacklist) != NULL) {
if (zend_hash_exists(SUHOSIN_G(eval_blacklist), lcname, func_name_len+1)) {
suhosin_log(S_EXISTENCE, "evaluated existence of a function within eval blacklist: eval('function_exists(\"%s\");')", lcname);
if (SUHOSIN_G(eval_exists_forbidden) && !SUHOSIN_G(simulation)) {
zend_error(E_ERROR, "SUHOSIN - Evaluating existence of functions within eval blacklist is forbidden by configuration");
}
retval = 0;
}
}
}

if (SUHOSIN_G(func_whitelist) != NULL) {
if (!zend_hash_exists(SUHOSIN_G(func_whitelist), lcname, func_name_len+1)) {
suhosin_log(S_EXISTENCE, "tested existence of a function not within whitelist: function_exists('%s')", lcname);
if (SUHOSIN_G(func_exists_forbidden) && !SUHOSIN_G(simulation)) {
zend_error(E_ERROR, "SUHOSIN - Testing existence of functions not within whitelist is forbidden by configuration");
}
retval = 0;
}
} else if (SUHOSIN_G(func_blacklist) != NULL) {
if (zend_hash_exists(SUHOSIN_G(func_blacklist), lcname, func_name_len+1)) {
suhosin_log(S_EXISTENCE, "tested existence of a blacklisted function: function_exists('%s')", lcname);
if (SUHOSIN_G(func_exists_forbidden) && !SUHOSIN_G(simulation)) {
zend_error(E_ERROR, "SUHOSIN - Testing existence of blacklisted functions is forbidden by configuration");
}
retval = 0;
}
}
Expand Down
2 changes: 2 additions & 0 deletions log.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ static char *loglevel2string(int loglevel)
return "SQL";
case S_EXECUTOR:
return "EXECUTOR";
case S_EXISTENCE:
return "EXISTENCE";
case S_VARS:
return "VARS";
default:
Expand Down
8 changes: 7 additions & 1 deletion php_suhosin.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ ZEND_BEGIN_MODULE_GLOBALS(suhosin)
HashTable *eval_whitelist;
HashTable *eval_blacklist;

zend_bool func_exists_forbidden;
zend_bool eval_exists_forbidden;
zend_bool executor_disable_eval;
zend_bool executor_disable_emod;

Expand Down Expand Up @@ -272,6 +274,10 @@ ZEND_END_MODULE_GLOBALS(suhosin)
#define zend_symtable_exists zend_hash_exists
#endif

/* Error Constants not part of the patch */
#ifndef S_EXISTENCE
#define S_EXISTENCE (1<<9L)
#endif

/* Error Constants */
#ifndef S_MEMORY
Expand All @@ -285,7 +291,7 @@ ZEND_END_MODULE_GLOBALS(suhosin)
#define S_MAIL (1<<7L)
#define S_SESSION (1<<8L)
#define S_INTERNAL (1<<29L)
#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MAIL | S_SESSION | S_MISC | S_SQL | S_EXECUTOR)
#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MAIL | S_SESSION | S_MISC | S_SQL | S_EXECUTOR | S_EXISTENCE)
#endif

#define SUHOSIN_NORMAL 0
Expand Down
8 changes: 8 additions & 0 deletions suhosin.c
Original file line number Diff line number Diff line change
Expand Up @@ -873,8 +873,10 @@ PHP_INI_BEGIN()
STD_ZEND_INI_BOOLEAN("suhosin.executor.include.allow_writable_files", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_include_allow_writable_files, zend_suhosin_globals, suhosin_globals)
ZEND_INI_ENTRY("suhosin.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_eval_whitelist)
ZEND_INI_ENTRY("suhosin.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_eval_blacklist)
STD_ZEND_INI_BOOLEAN("suhosin.executor.eval.exists_forbidden", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, eval_exists_forbidden, zend_suhosin_globals, suhosin_globals)
ZEND_INI_ENTRY("suhosin.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_func_whitelist)
ZEND_INI_ENTRY("suhosin.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_func_blacklist)
STD_ZEND_INI_BOOLEAN("suhosin.executor.func.exists_forbidden", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, func_exists_forbidden, zend_suhosin_globals, suhosin_globals)
STD_ZEND_INI_BOOLEAN("suhosin.executor.disable_eval", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_disable_eval, zend_suhosin_globals, suhosin_globals)
STD_ZEND_INI_BOOLEAN("suhosin.executor.disable_emodifier", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_disable_emod, zend_suhosin_globals, suhosin_globals)

Expand Down Expand Up @@ -1044,6 +1046,12 @@ PHP_MINIT_FUNCTION(suhosin)
REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS);
REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS);
}

/* register constants which never have been part of any suhosin-patch,
* hence they have not previously been registered by a possible patched PHP */
if (zend_hash_exists(EG(zend_constants), "S_EXISTENCE", sizeof("S_EXISTENCE"))==0) {
REGISTER_MAIN_LONG_CONSTANT("S_EXISTENCE", S_EXISTENCE, CONST_PERSISTENT | CONST_CS);
}

/* check if shared ini directives are already known (maybe a patched PHP) */
if (zend_hash_exists(EG(ini_directives), "suhosin.log.syslog", sizeof("suhosin.log.syslog"))) {
Expand Down
34 changes: 30 additions & 4 deletions suhosin.ini
Original file line number Diff line number Diff line change
Expand Up @@ -91,25 +91,51 @@ extension = suhosin.so

; Comma separated whitelist of functions that are allowed to be called. If the
; whitelist is empty the blacklist is evaluated, otherwise calling a function
; not in the whitelist will terminate the script and get logged.
; not in the whitelist will terminate the script and get logged. Executing
; function_exists() on a function not in the whitelist will log an event with
; the class S_EXISTENCE and if the flag suhosin.executor.func.exists_forbidden
; is enabled also terminate the script.
;suhosin.executor.func.whitelist =

; Comma separated blacklist of functions that are not allowed to be called. If
; no whitelist is given, calling a function within the blacklist will terminate
; the script and get logged.
; the script and get logged. Executing function_exists() on a function within
; the blacklist will log an event with the class S_EXISTENCE and if the flag
; suhosin.executor.func.exists_forbidden is enabled also terminate the script.
;suhosin.executor.func.blacklist =

; When this configuration flag is turned on, the script will terminate, if
; function_exists() is executed on a function not in the whitelist (if given)
; or within the blacklist (if given), after the problem has been logged. This
; flag is meant for development, deployment or paranoid use only. Unless you
; really want to annoy users, there are (very) good reasons NOT to enable this
; flag. If it's enabled, you deserve all the heat you'll get.
;suhosin.executor.func.exists_forbidden = Off

; Comma separated whitelist of functions that are allowed to be called from
; within eval(). If the whitelist is empty the blacklist is evaluated,
; otherwise calling a function not in the whitelist will terminate the script
; and get logged.
; and get logged. The execution of function_exists() on a function not in the
; non-empty whitelist will log an event with the class S_EXISTENCE and if the
; flag suhosin.executor.eval.exists_forbidden is enabled terminate the script.
;suhosin.executor.eval.whitelist =

; Comma separated blacklist of functions that are not allowed to be called from
; within eval(). If no whitelist is given, calling a function within the
; blacklist will terminate the script and get logged.
; blacklist will terminate the script and get logged and testing existence via
; function_exists() will log an event with the class S_EXISTENCE. If the flag
; suhosin.executor.eval.exists_forbidden is enabled the latter case will also
; terminate the script.
;suhosin.executor.eval.blacklist =

; When this configuration flag is turned on, the script will terminate, if
; function_exists() is executed from within eval() on a function not in the
; whitelist (if given) or within the blacklist (if given), after the problem
; has been logged. This flag is meant for development, deployment or paranoid
; use only. Unless you really want to annoy users, there are (very) good reasons
; NOT to enable this flag. If it's enabled, you deserve all the heat you'll get.
;suhosin.executor.eval.exists_forbidden = Off

; eval() is a very dangerous statement and therefore you might want to disable
; it completely. Deactivating it will however break lots of scripts. Because
; every violation is logged, this allows finding all places where eval() is
Expand Down
19 changes: 19 additions & 0 deletions tests/executor/eval_blacklist_with_exists_forbidden_off.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Testing: suhosin.executor.eval.blacklist with suhosin.executor.eval.exists_forbidden=0
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.disable_eval=0
suhosin.executor.eval.whitelist=
suhosin.executor.eval.blacklist=intval
suhosin.executor.eval.exists_forbidden=0
--FILE--
<?php
$test = true;
eval('$test = function_exists("intval");');
var_dump($test);
?>
--EXPECTF--
ALERT - evaluated existence of a function within eval blacklist: eval('function_exists("intval");') (attacker 'REMOTE_ADDR not set', file '%s(3) : eval()'d code', line 1)
bool(false)
18 changes: 18 additions & 0 deletions tests/executor/eval_blacklist_with_exists_forbidden_on.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Testing: suhosin.executor.eval.blacklist with suhosin.executor.eval.exists_forbidden=1
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.disable_eval=0
suhosin.executor.eval.whitelist=
suhosin.executor.eval.blacklist=intval
suhosin.executor.eval.exists_forbidden=1
--FILE--
<?php
eval('function_exists("intval");');
?>
--EXPECTF--
ALERT - evaluated existence of a function within eval blacklist: eval('function_exists("intval");') (attacker 'REMOTE_ADDR not set', file '%s(2) : eval()'d code', line 1)

Fatal error: SUHOSIN - Evaluating existence of functions within eval blacklist is forbidden by configuration in %s(2) : eval()'d code on line 1
19 changes: 19 additions & 0 deletions tests/executor/eval_whitelist_with_exists_forbidden_off.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Testing: suhosin.executor.eval.whitelist with suhosin.executor.eval.exists_forbidden=0
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.disable_eval=0
suhosin.executor.eval.whitelist=function_exists,var_dump
suhosin.executor.eval.blacklist=
suhosin.executor.eval.exists_forbidden=0
--FILE--
<?php
$test = true;
eval('$test = function_exists("intval");');
var_dump($test);
?>
--EXPECTF--
ALERT - evaluated existence of a function not within eval whitelist: eval('function_exists("intval");') (attacker 'REMOTE_ADDR not set', file '%s(3) : eval()'d code', line 1)
bool(false)
18 changes: 18 additions & 0 deletions tests/executor/eval_whitelist_with_exists_forbidden_on.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Testing: suhosin.executor.eval.whitelist with suhosin.executor.eval.exists_forbidden=1
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.disable_eval=0
suhosin.executor.eval.whitelist=function_exists
suhosin.executor.eval.blacklist=
suhosin.executor.eval.exists_forbidden=1
--FILE--
<?php
eval('function_exists("intval");');
?>
--EXPECTF--
ALERT - evaluated existence of a function not within eval whitelist: eval('function_exists("intval");') (attacker 'REMOTE_ADDR not set', file '%s(2) : eval()'d code', line 1)

Fatal error: SUHOSIN - Evaluating existence of functions not within eval whitelist is forbidden by configuration in %s(2) : eval()'d code on line 1
17 changes: 17 additions & 0 deletions tests/executor/func_blacklist_with_exists_forbidden_off.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Testing: suhosin.executor.func.blacklist with suhosin.executor.func.exists_forbidden=0
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.func.whitelist=
suhosin.executor.func.blacklist=intval
suhosin.executor.func.exists_forbidden=0
--FILE--
<?php
$test = function_exists("intval");
var_dump($test);
?>
--EXPECTF--
ALERT - tested existence of a blacklisted function: function_exists('intval') (attacker 'REMOTE_ADDR not set', file '%s', line 2)
bool(false)
17 changes: 17 additions & 0 deletions tests/executor/func_blacklist_with_exists_forbidden_on.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Testing: suhosin.executor.func.blacklist with suhosin.executor.func.exists_forbidden=1
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.func.whitelist=
suhosin.executor.func.blacklist=intval
suhosin.executor.func.exists_forbidden=1
--FILE--
<?php
function_exists("intval");
?>
--EXPECTF--
ALERT - tested existence of a blacklisted function: function_exists('intval') (attacker 'REMOTE_ADDR not set', file '%s', line 2)

Fatal error: SUHOSIN - Testing existence of blacklisted functions is forbidden by configuration in %s on line 2
17 changes: 17 additions & 0 deletions tests/executor/func_whitelist_with_exists_forbidden_off.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Testing: suhosin.executor.func.whitelist with suhosin.executor.func.exists_forbidden=0
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.func.whitelist=function_exists,var_dump
suhosin.executor.func.blacklist=
suhosin.executor.func.exists_forbidden=0
--FILE--
<?php
$test = function_exists("intval");
var_dump($test);
?>
--EXPECTF--
ALERT - tested existence of a function not within whitelist: function_exists('intval') (attacker 'REMOTE_ADDR not set', file '%s', line 2)
bool(false)
17 changes: 17 additions & 0 deletions tests/executor/func_whitelist_with_exists_forbidden_on.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Testing: suhosin.executor.func.whitelist with suhosin.executor.func.exists_forbidden=1
--SKIPIF--
<?php include "../skipifnotcli.inc"; ?>
--INI--
suhosin.log.sapi=512
suhosin.executor.func.whitelist=function_exists
suhosin.executor.func.blacklist=
suhosin.executor.func.exists_forbidden=1
--FILE--
<?php
function_exists("intval");
?>
--EXPECTF--
ALERT - tested existence of a function not within whitelist: function_exists('intval') (attacker 'REMOTE_ADDR not set', file '%s', line 2)

Fatal error: SUHOSIN - Testing existence of functions not within whitelist is forbidden by configuration in %s on line 2