跟bWAPP学WEB安全(PHP代码)--终结篇:文件目录遍历、文件上传、SSRF、CSRF、XXE、文件包含

前言




过年过的很不顺,家里领导和我本人接连生病,年前腊月29才都治好出院,大年初六家里的拉布拉多爱犬又因为细小医治无效离开了,没能过年回家,花了好多钱,狗狗还离世了。所以也就没什么心思更新博客。今天初七,正式上班了,更新一篇吧,把bWAPP中常见的web漏洞也就一次性更新完毕,完成这个系列,虽然有点虎头蛇尾,但是也颇感无奈了。去年立的flag也还有两个大系列没有完成,一个是互联网公司常见漏洞分析,一个是C语言基础自学笔记,要看的东西太多了,也就是借着努力学习工作来忘却生活的打击和痛苦吧。

文件和目录遍历




从本质上说,二者的漏洞原因没啥不一样,尤其是linux系统中,一般都出现在文件阅读、下载、展示、或者可以列出目录的地方。

PHP代码


function directory_traversal_check_1($data)
{

    // Not bulletproof

    $directory_traversal_error = "";  

    // Searches for special characters in the GET parameter
    if(strpos($data, "../") !== false ||
       strpos($data, "..\\") !== false ||
       strpos($data, "/..") !== false ||
       strpos($data, "\..") !== false)

    {

        $directory_traversal_error = "Directory Traversal detected!";

    }

    /*
    else
    {

        echo "Good path!";

    }
     */

    return $directory_traversal_error;

}

function directory_traversal_check_2($data)
{

    // Not bulletproof

    $directory_traversal_error = "";  

    // Searches for special characters in the GET parameter
    if(strpos($data, "../") !== false ||
       strpos($data, "..\\") !== false ||
       strpos($data, "/..") !== false ||
       strpos($data, "\..") !== false ||
       strpos($data, ".") !== false)

    {

        $directory_traversal_error = "Directory Traversal detected!";

    }

    /*
    else
    {

        echo "Good path!";

    }
     */

    return $directory_traversal_error;

}

function directory_traversal_check_3($user_path,$base_path = "")
{

    $directory_traversal_error = "";

    $real_base_path = realpath($base_path);

    // echo "base path: " . $base_path . " real base path: " . $real_base_path . "<br />";

    $real_user_path = realpath($user_path);

    // echo "user path: " . $user_path . " real user path: " . $real_user_path . "<br />";

    // int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
    // URL: http://php.net/manual/en/function.strpos.php
    if(strpos($real_user_path, $real_base_path) === false)
    {

        $directory_traversal_error = "<font color=\"red\">An error occurred, please try again.</font>";

    }

    /*
    else
    {

        echo "Good path!";

    }
     */

    return $directory_traversal_error;

}

代码分析



函数一过滤了../ ..\ /.. .. , 函数二还过滤了. 但是绕过都很简单,直接使用绝对路径,不使用相对路径即可,例如/etc/passwd。函数三则对相对路径转为绝对路径后,和允许访问的绝对路径比对,如果不一致则禁止访问,真正做到了约束和防御。

文件上传



PHP代码

function file_upload_check_1($file, $file_extensions  = array("asp", "aspx", "dll", "exe", "jsp", "php"), $directory = "images")
{

    $file_error = "";

    // Checks if the input field is empty
    if($file["name"] == "")
    {

        $file_error = "Please select a file...";

        return $file_error;

    }

    // Checks if there is an error with the file
    switch($file["error"])

    // URL: http://php.net/manual/en/features.file-upload.errors.php

    {

        case 1 : $file_error = "Sorry, the file is too large. Please try again...";
                 break;

        case 2 : $file_error = "Sorry, the file is too large. Please try again...";
                 break;

        case 3 : $file_error = "Sorry, the file was only partially uploaded. Please try again...";
                 break;

        case 6 : $file_error = "Sorry, a temporary folder is missing. Please try again...";
                 break;

        case 7 : $file_error = "Sorry, the file could not be written. Please try again...";
                 break;

        case 8 : $file_error = "Sorry, a PHP extension stopped the file upload. Please try again...";
                 break;

    }

    if($file_error)
    {

        return $file_error;

    }

    // Breaks the file in pieces (.) All pieces are put in an array
    $file_array = explode(".", $file["name"]);

    // Puts the last part of the array (= the file extension) in a new variabele
    // Converts the characters to lower case
    $file_extension = strtolower($file_array[count($file_array) - 1]);

    // Searches if the file extension exists in the ‘allowed‘ file extensions array
    if(in_array($file_extension, $file_extensions))
    {

       $file_error = "Sorry, the file extension is not allowed. The following extensions are blocked: <b>" . join(", ", $file_extensions) . "</b>";

       return $file_error;

    }

    // Checks if the file already exists in the directory
    if(is_file("$directory/" . $file["name"]))
    {

        $file_error = "Sorry, the file already exists. Please rename the file...";      

    }

    return $file_error;

}

function file_upload_check_2($file, $file_extensions  = array("jpeg", "jpg", "png", "gif"), $directory = "images")
{

    $file_error = "";

    // Checks if the input field is empty
    if($file["name"] == "")
    {

        $file_error = "Please select a file...";

        return $file_error;

    }

    // Checks if there is an error with the file
    switch($file["error"])

    // URL: http://php.net/manual/en/features.file-upload.errors.php

    {

        case 1 : $file_error = "Sorry, the file is too large. Please try again...";
                 break;

        case 2 : $file_error = "Sorry, the file is too large. Please try again...";
                 break;

        case 3 : $file_error = "Sorry, the file was only partially uploaded. Please try again...";
                 break;

        case 6 : $file_error = "Sorry, a temporary folder is missing. Please try again...";
                 break;

        case 7 : $file_error = "Sorry, the file could not be written. Please try again...";
                 break;

        case 8 : $file_error = "Sorry, a PHP extension stopped the file upload. Please try again...";
                 break;

    }

    if($file_error)
    {

        return $file_error;

    }

    // Breaks the file in pieces (.) All pieces are put in an array
    $file_array = explode(".", $file["name"]);

    // Puts the last part of the array (= the file extension) in a new variabele
    // Converts the characters to lower case
    $file_extension = strtolower($file_array[count($file_array) - 1]);

    // Searches if the file extension exists in the ‘allowed‘ file extensions array
    if(!in_array($file_extension, $file_extensions))
    {

       $file_error = "Sorry, the file extension is not allowed. Only the following extensions are allowed: <b>" . join(", ", $file_extensions) . "</b>";

       return $file_error;

    }

    // Checks if the file already exists in the directory
    if(is_file("$directory/" . $file["name"]))
    {

        $file_error = "Sorry, the file already exists. Please rename the file...";      

    }

    return $file_error;

}

代码分析



上面的代码对于防文件上传不是特别典型,就不分析了,我们看一下正确的PHP文件上传的代码

  • 1、扩展名检查(要白名单不能黑名单,一般就是允许jpg、jpeg、png等等)。
  • 2、重命名随机新文件名,且该新文件名不返回到前端,这个时候一定要注意扩展名。
  • 3、对图片进行二次渲染,如果不是上传图片文件就忽略这一点。
  • 4、文件转存到一个路径,该路径不要暴露。
  • 5、保证服务器版本,避免解析漏洞。
<?php
  //配置属性
  $upload_path = ‘/var/www/images/‘;
  $target_file   =  md5(uniqid());
  $allow_extend_filenames = array(‘jpg‘, ‘jpeg‘, ‘png‘);//限定可以上传的文件扩展名
  //文件获取
  if(isset($_POST[‘file‘])){
    checkToken($_REQUEST[‘csrfToken‘], $_SESSION[‘csrfToken‘], ‘upload.php‘);
  }
  $file = $_FILES[‘file‘];

  //获取文件属性
  $name = $file[‘name‘];
  $type = $file[‘type‘];
  $size = $file[‘size‘];
  $tmp_name = $file[‘tmp_name‘]
  $extend_name = strtolower(substr($name, strrops($name, ‘.‘) + 1));

  //文件属性更新
  $target_file = $upload_path . $target_file . ‘.‘;

  //白名单检查
  $dot_count = substr_count(‘.‘);
  if ($dot_count > 1){
    return ‘filename error!‘;
  }

  if(!in_array($extend_name, $allow_extend_filenames)){
    return ‘filetype error!‘;
  }

  if ($type != ‘image/jpeg‘ && $type != ‘image/png‘){
    return ‘filetype error!‘;
  }

  //图片二次渲染
  if($type == ‘image/jpeg‘){
    $img = imagecreatefromjpeg($tmp_name);
    imagejpeg($img, $target_file . ‘jpg‘, 100);
  }
  else{
    $img = imagecreatefrompng($tmp_name);
    imagepng($img, $target_file . ‘png‘, 9);
  }
  imagedestory($img);

  return ‘upload success!‘;

  generateSessionToken();
 ?>

SSRF




关键问题是对内部可能发起访问的地址,做白名单限制,或者按照自定义规则验证合法性,而不是任意发起,没有php级别的防御措施,是代码逻辑防御级别的。

CSRF



防御方式



表单隐藏随机token验证的方式防御,或者弹出验证码防御,后者是功能逻辑防御,影响用户体验但更安全,代码层面来介绍下前者。

防御代码

<input type="hideen" value="token_value" name="token"></input>
if($_SESSION[‘id‘] &&  $_POST[‘csrfToken‘]  == $_SESSION[‘csrfToken‘]){
    return true;
}
else{
    return false;
}

XXE的PHP级别防御



防御原理



由于simplexml_load_string函数的XML解析问题出在libxml库上,所以加载实体前可以调用一个函数来禁用。

防御代码


<?php libxml_disable_entity_loader(true); ?>

文件包含的防御


防御远程文件包含

//PHP配置文件
allow_url_include = OFF

防御本地文件包含

//include类函数的参数不允许用户控制,或者在白名单内做限制。

原文地址:https://www.cnblogs.com/KevinGeorge/p/10362324.html

时间: 2024-11-07 04:50:10

跟bWAPP学WEB安全(PHP代码)--终结篇:文件目录遍历、文件上传、SSRF、CSRF、XXE、文件包含的相关文章

跟bWAPP学WEB安全(PHP代码)--邮件头和LDAP注入

背景 由于时间限制和这俩漏洞也不是特别常用,在这里就不搭建环境了,我们从注入原来和代码审计的角度来看看. 邮件头注入 注入原理: 这个地方首先要说一下邮件的结构,分为信封(MAIL FROM.RCPT TO).头部(From,To,Subject.CC.BCC等).主体(message),所谓的邮件头注入,其实就是针对头部的部分.使用telnet对25端口进行手工发邮件的过程的事后会发现,对于邮件头部的字段其实就是换行符0x0A或者0x0D0x0A分割 ,在绝大部分系统里面不是\n 就是\r\n

跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击

背景 这个系列有很多题,但是其实考察的相近,类似的就不在多说,我们来看吧.主要分几个点来讲: 反射型 存储型 JSON XM 头部字段相关 分类介绍 反射型 在请求中构造了XSS的Payload,一般又是受害者点击导致受害者的客户端被攻击.例如:http://172.16.204.213/bWAPP/xss_get.php?firstname=%3Cscript%3Ealert(document.cookie)%3C/script%3E&lastname=2&form=submit 存储型

web 文件上传组件 Plupload

Plupload官网:点击打开链接   建议下载最新版本,低版本会出现浏览器兼容问题. 最近公司有个项目需要在web端使用多文件上传功能,刚开始准备使用HTML5来做,但是IE9以下是都不支持的,于是想到了flash,在网上搜了下各种开源的组件,最后决定使用Plupload,下面来介绍一下该组件使用时遇到的一些问题以及解决方案. 先贴出配置参数: <script type="text/javascript"> // Initialize the widget when th

Web应用安全之文件上传漏洞详解

什么是文件上传漏洞 文件上传漏洞是在用户上传了一个可执行的脚本文件,本通过此脚本文件获得了执行服务器端命令的功能,这种攻击方式是最为直接,最为有效的,有时候,几乎没有什么门槛,也就是任何人都可以进行这样的攻击.文件上传为什么会是漏洞呢?文件上传本身是没有问题的,问题是文件上传后看服务器怎么来处理,怎么来解析这个文件.如果说服务器处理的模式不够安全,那么就会导致严重的后果,也就是上传了恶意的可执行文件以后,服务器端对此文件进行执行. 文件上传后导致的安全问题 上传的文件是web脚本语言,服务器的w

《白帽子讲WEB安全》学习笔记之第8章 文件上传漏洞

第8章 文件上传漏洞 8.1 文件上传漏洞概述 文件上传漏洞是指用户上传一个可执行的脚本文件,并通过此脚本文件活动执行服务器端的能力. 原理:由于文件上传功能实现代码没有严格限制用户上传的文件后缀以及文件类型,导致允许攻击者向某个可通过 Web 访问的目录上传任意PHP文件. 文件上传漏洞安全问题: q  上传文件是WEB脚本文件,服务器的WEB服务器解释并执行了用户上传的脚本,导致代码执行: q  上传文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行

web大文件上传解决方案支持分片断点上传

一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输.关闭浏览器后保留进度信息. 支持文件夹批量上传下载,服务器端保留文件夹层级结构,服务器端文件夹层级结构与本地相同. 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验:支持文件夹上传,文件夹中的文件数量达到1万个以上,且包含层级结构. 支持断点续传,关闭浏览器或刷新浏览

JavaScript大文件上传解决方案实例代码

一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输.关闭浏览器后保留进度信息. 支持文件夹批量上传下载,服务器端保留文件夹层级结构,服务器端文件夹层级结构与本地相同. 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验:支持文件夹上传,文件夹中的文件数量达到1万个以上,且包含层级结构. 支持断点续传,关闭浏览器或刷新浏览

ASP.NET Core WEB API 使用element-ui文件上传组件el-upload执行手动文件文件,并在文件上传后清空文件

前言: 从开始学习Vue到使用element-ui-admin已经有将近快两年的时间了,在之前的开发中使用element-ui上传组件el-upload都是直接使用文件选取后立即选择上传,今天刚好做了一个和之前类似的文件选择上传的需求,不过这次是需要手动点击按钮把文件上传到服务器中进行数据导入,而且最多只能够选择一个文件进行上传,上传成功后需要对file-list中的文件列表数据进行清空操作,在这里服务端使用的是ASP.NET Core WEB API来进行文件流数据接收和保存. 一.简单概述e

java web 文件上传下载

文件上传下载案例: 首先是此案例工程的目录结构: 处理上传: FileUploadServlet.java 1 package fnz.fileUploadTest; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.PrintWriter; 7 import java.text.SimpleDateFormat; 8 import java.