0


第25天:安全开发-PHP应用&文件管理&包含&写入&删除&下载&上传&遍历&安全

时间轴:

知识点

1、PHP 文件管理-下载&删除功能实现

2、PHP 文件管理-编辑&包含功能实现

php文件操作安全

文件包含、文件上传、文件下载、文件删除、文件写入、文件遍历

其中文件上传可以上传在本地服务器,也可以上传在oss对象存储。但是如果使用oss又不进行相关配置,在浏览器中f12后可以在upload.js文件中看到access id/key,再利用oss browser登陆,就可以看到上传的文件。

架构

1.上传至服务器本身的存储磁盘(传统方法)

2.借助云产品OSS存储对象去存储文件(不解析)(泄露安全)

由于只能存储而不能解析,因此即使上传木马也不能获取权限,就更加安全,但是如果在浏览器中f12,也有可能可以找到access id/key

3.把文件上传到其他域名

例如:www.xiaodi8.com—>upload.xiaodi8.com

OSS存储对象

1.在upload.js里配置accesskey(RAM访问控制->概述->accesskey)

文件查看url:

将accesskey等输入upload.js

设置好之后去oss上传,发现报错了

2.报错需要改为公共读写(权限控制-读写权限)

或者使用oss-browser.exe,输入access id和key连接上去,就可以看见具体数据

accesskey泄露:

如果在浏览器中f12,也有可能可以找到access id/key

演示案例:文件管理模块-加工后续-编辑&删除&下载&包含

相关知识

文件包含相关函数

include() 在错误发生后脚本继续执行

require() 在错误发生后脚本停止执行

include_once() 如果已经包含,则不再执行

require_once() 如果已经包含,则不再执行

文件包含存在的漏洞:如果含有变量,例如:include($_GET['page'];,在访问时?page=可以为任何文件,很容易被上传木马。

例如设置1.txt为

当直接访问?page=1.txt时,回显如下图所示

文件包含的优点:可以进行文件的调用,例如:如果不设置文件包含,在访问upload.php之前需要先访问upload.html,但如果在upload.php中include 'upload.html'后就可以直接访问upload.php了。

漏洞产生原因

1.使用什么函数去执行(函数方面的)

2.可以控制的值(用户提交的恶意数据)

文件上传机制

1、无过滤机制

2、黑名单过滤机制

3、白名单过滤机制

4、文件类型过滤机制

实现文件编辑、删除、下载、包含功能具体步骤

最终完整代码
<?php
ini_set('open_basedir',__DIR__);
$path=$_GET['path'] ?? './';
$action=isset($_GET['a']) ?$_GET['a']:'';
$path=isset($_GET['path']) ?$_GET['path']:'.';

if(is_file($path)){//判断是否是文件
    //获得文件名
    $file=basename($path);
    //获得路径
    $path=dirname($path);
}elseif(!is_dir($path)){//判断,不是目录
    echo '无效的文件文件路径参数';
}

function getlist($path){
    $hd=opendir($path);
    while(($file_name=readdir($hd))!==false){
        if($file_name!='.' and $file_name!='..'){
            $file_path="$path/$file_name";
            $file_type=filetype($file_path);
        }
        $list[@$file_type][] =array(
            'file_name'=>@$file_name,
            'file_path'=>@$file_path,
            'file_size'=>round(filesize(@$file_path)/1024),
            'file_time'=>date('Y/m/d H:i:s',filemtime(@$file_path)),
        );
    }
    closedir($hd);
    return $list;
}
$list=getlist($path);

//接收方法,判断怎么操作
switch($action){
    case 'del':
        unlink("$path/$file");//或者写成($file)或者可以用以下的cmd方式删除
        //  system("del $file");
        break;
    case 'down':
        header("Content-Type: application/octet-stream");
        header("Content-Disposition: attachment; filename=\"" . $file . "\"");
        header("Content-Length: " . filesize($file));
        readfile($file);
        break;
    case 'edit';
        $content=file_get_contents($file);
        echo "<form name='form1' method='post' action=''>";
        echo "文件名:".$file.'<br>';
        echo "文件内容:<br>";
        echo '<textarea name="code" style="resize:none;" rows="100" cols="100">'.$content.'</textarea><br>';
        echo "<input type='submit' name='submit' id='submit' value='提交'>";
        echo "</form>";
        break;
}
if(isset($_POST['code'])){
    $f=fopen("$path/$file",'w+');
    fwrite($f,$_POST['code']);
    fclose($f);
}
?>

<table width="100%" style="font-size: 10px;text-align: center;">
    <tr>
        <th>图标</th>
        <th>名称</th>
        <th>日期</th>
        <th>大小</th>
        <th>路径</th>
        <th>操作</th>
    </tr>
        <?php foreach($list['dir'] as $value):?>
        <tr>
            <td><img src="./img/list.png" width="20" height="20"></td>
            <td><?php echo $value['file_name'];?></td>
            <td><?php echo $value['file_time'];?></td>
            <td>-</td>
            <td><?php echo $value['file_path'];?></td>
            <td><a href="?path=<?php echo $value['file_path'];?>">打开</a></td>
        </tr>
        <?php endforeach;?>

        <?php foreach($list['file'] as $value):?>
        <tr>
            <td><img src="./img/file.png" width="20" height="20"></td>
            <td><?php echo $value['file_name'];?></td>
            <td><?php echo $value['file_time'];?></td>
            <td><?php echo $value['file_size'];?></td>
            <td><?php echo $value['file_path'];?></td>
            <td>
                <a href="?a=edit&path=<?php echo $value['file_path'];?>">编辑</a>
                <a href="?a=down&path=<?php echo $value['file_path'];?>">下载</a>
                <a href="?a=del&path=<?php echo $value['file_path'];?>">删除</a>
            </td>

        </tr>
        <?php endforeach;?>
</table>
具体过程
第一步

首先创建一个filemanager.php,在其中写入最基本的网页前端代码。

再在demo01文件夹下创建img文件夹,用于存放网页图标。

<table width="100%" style="font-size: 10px;text-align: center;">
    <tr>
        <th>图标</th>
        <th>名称</th>
        <th>日期</th>
        <th>大小</th>
        <th>路径</th>
        <th>操作</th>
    </tr>
    <tr>
        <td><img src="./img/list.png" width="20" height="20"></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
    </tr>

    <tr>
        <td><img src="./img/file.png" width="20" height="20"></td>
        <td></td>
        <td></td>
        <td></td>
        <td></td>
        <td>
        </td>

    </tr>
</table>

效果如图所示:

之后要实现在网页上显示出文件和文件夹,代码和结果如下图所示

<?php
$path=$_GET['path'] ?? './';
$hd=opendir($path);
while(($file_name=readdir($hd))!==false){
    if($file_name!='.' and $file_name!='..'){
        echo $file_name."<br>";
    }
}
?>

第二步

此时,显示出来的有文件夹也有文件,那么接下来需要把文件夹和文件分开,list.png图标显示文件夹,file.png图标显示文件。

代码变成

<?php
$path=$_GET['path'] ?? './';
$hd=opendir($path);
while(($file_name=readdir($hd))!==false){
    if($file_name!='.' and $file_name!='..'){
//        完整路径
        $file_path = "$path/$file_name";
//        获取文件或者文件夹类型
        $file_type = filetype($file_path);
    }
//    将文件、文件夹封装为数组,其中[@$file_type]为外部键,'file_name'为内部键,@$file_name是值
    $list[@$file_type][] =array(
        'file_name'=>@$file_name,//文件名存储键值file_name
        'file_path'=>@$file_path,//文件路径存储键值file_path
        'file_size'=>round(filesize(@$file_path)/1024),//通过换算文件大小存储键值file_path
        'file_time'=>date('Y/m/d H:i:s',filemtime(@$file_path)),//获取文件时间并存储键值
    );
}
?>

<table width="100%" style="font-size: 10px;text-align: center;">
    <tr>
        <th>图标</th>
        <th>名称</th>
        <th>日期</th>
        <th>大小</th>
        <th>路径</th>
        <th>操作</th>
    </tr>
       <?php foreach($list['dir'] as $value):?>           //foreach循环遍历
       <tr>
          <td><img src="./img/list.png" width="20" height="20"></td>
          <td><?php echo $value['file_name'];?></td>
          <td><?php echo $value['file_time'];?></td>
          <td>-</td>
<!--           文件夹没有大小-->
          <td><?php echo  $value['file_path'];?></td>
          <td></td>
       </tr>
<!--       结束语句-->                         //记得结束语句
       <?php endforeach;?>

       <?php foreach($list['file'] as $value):?>
       <tr>
          <td><img src="./img/file.png" width="20" height="20"></td>
          <td><?php echo $value['file_name'];?></td>
          <td><?php echo $value['file_time'];?></td>
          <td><?php echo $value['file_size'];?></td>
          <td><?php echo $value['file_path'];?></td>
          <td>
          </td>
       </tr>
       <?php endforeach;?>
</table>

显示如下图

知识点1:filemtime()函数

返回文件内容上次的修改时间

知识点2:foreach()函数

foreach循环(只能用于数组):

第一种语法:

foreach ($array as $value){
   code to be executed;
}

第二种语法:

foreach ($array as $key => $value){
   code to be executed;
}

每进行一次循环迭代,当前数组元素的值就会被赋值给$value,并且数组指针会逐一移动,直到最后一个元素。

第三步

接下来要实现文件夹的打开功能。php代码中需要定义函数,并将html中的操作代码添加a标签。代码变成:

function getlist($path){
    $hd=opendir($path);
    while(($file_name=readdir($hd))!==false){
        if($file_name!='.' and $file_name!='..'){
            $file_path="$path/$file_name";
            $file_type=filetype($file_path);
        }
        $list[@$file_type][] =array(
            'file_name'=>@$file_name,
            'file_path'=>@$file_path,
            'file_size'=>round(filesize(@$file_path)/1024),
            'file_time'=>date('Y/m/d H:i:s',filemtime(@$file_path)),
        );
    }
    closedir($hd);
    return $list;
}
$list=getlist($path);
?>

网页端可以看到:

第四步

实现文件的删除功能,代码如下:

网页端显示如下

现在尝试点击删除1.php,刷新页面后,1.php消失,说明删除功能实现

知识点3:unlink()函数

用于删除文件

unlink(filename[必需],content[可选:规定文件句柄的环境])

知识点4

标签用于创建超链接

href属性指定链接的目标url

知识点5

$action=isset($_GET['a']) ?$_GET['a']:'';的解释:

?:是三元运算符,类似于if_else语句

语法为:(condition) ? (true_expression) : (false_expression)

如果isset($_GET['a'])为true,即a存在,则将$_GET['a']的值赋给$action;如果isset($_GET['a'])为false,即a不存在,则将空字符串赋给$action。

知识点:6switch语句

用于根据多个不同条件执行不同动作

语法:

<?php switch (expression){ case value1:若expression的值等于某个case的值,就执行相应代码块 //代码块1 break;(用于终止switch语句,防止继续执行下一个case) case value2: //代码块2 break; //更多的case语句 default:(是可选的,用于指定当没有匹配的case时执行的代码块) //如果没有匹配的值 } ?>
第五步

实现文件的下载功能

在switch语句下增加代码:

case 'down':
        header("Content-Type: application/octet-stream");
        header("Content-Disposition: attachment; filename=\"" . $file . "\"");
//        Content-Disposition用于指定内容处理方式
//        attachment表示浏览器应将响应内容作为下载文件处理,而非显示  
        header("Content-Length: " . filesize($file));
        readfile($file);
        break;

点击下载1.txt,可以看到文件下载功能也实现了。

第六步

实现文件的编辑功能

修改后的代码参考上面的最终完整代码,效果如图

在文本框中输入内容点击下面的提交,刷新可以看到写入的内容

知识点7:basename()函数

返回路径中的文件名部分

basename(path[必需],suffix[可选,规定文件扩展名,若有文件扩展名,将不会显示该扩展名])

知识点8:dirname()函数

返回路径中的目录名称部分

知识点9:有关文件读、写的函数

1.file_get_contents():读取文件内容

2.fopen()、fread():文件打开、读入

3.fwrite(file[必需] string[必需,要写入的内容] length[可选,要写入的最大字节])

知识点10:ini_set()

ini_set('open_basedir',DIR);等价于dirname(FILE)

_DIR_是魔术常量,返回当前php文件所在的目录路径,值随着它们在代码中的位置改变而改变

知识点11

注释:

if(isset($_POST['code'])){
$f=fopen("$path/$file",'w+');
fwrite($f,$_POST['code']);
fclose($f);
}

第一行用于检查表单是否提交,并且code字段是否存在;

w+表示文件以读写方式打开,若文件不存在,则创建该文件,若文件存在,打开文件后文件内容会被清空,即文件大小变为0;

第三行中的$_POST['code']包含用户在文本区域中输入的内容。

文件下载漏洞(编辑、删除同理)

?a=down&path=

当等号后面的值不同时,就可以下载其他文件,同理,也可以删除、编辑其他文件。

例如,当访问?a=down&path=./1.txt时,会自动下载1.txt文件

文件使用系统指令删除:

switch($action){
    case 'del':
//        unlink($file);
        $cmd="del $file";
        system($cmd);
        echo $cmd;
        break;

和在cmd下使用一样的原理

dnslog回显

当不知道执行结果时,可以使用?path=del 1.txt | ping 127.0.0.1

例如,我删除了一个文件,但是不会立即反馈给我是否删除成功,此时就可以 | ping dnslog(get subdomain)。

但是也有可能被以下代码过滤掉:

if(is_file($path)){//判断是否是文件
    //获得文件名
    $file=basename($path);
    //获得路径
    $path=dirname($path);
}elseif(!is_dir($path)){//判断,不是目录
    echo '无效的文件文件路径参数';
}

该文章由番薯小羊卷~和李豆豆喵共同完成。


本文转载自: https://blog.csdn.net/m0_74930529/article/details/143375575
版权归原作者 李豆豆喵 所有, 如有侵权,请联系我们删除。

“第25天:安全开发-PHP应用&文件管理&包含&写入&删除&下载&上传&遍历&安全”的评论:

还没有评论