[代码审计] php 文件上传

admin 2024年8月20日13:15:14评论44 views字数 4777阅读15分55秒阅读模式

0x00 介绍

  1. 文件类型验证:确保只允许特定类型的文件上传。

  2. 文件扩展名检查:检查文件的扩展名,但不要仅依赖于此。

  3. MIME 类型验证:通过 finfo_file() 函数获取文件的 MIME 类型进行验证。

  4. 文件内容检查:对文件内容进行检查,防止上传恶意文件。

  5. 上传目录的权限设置:确保上传目录不可执行。

  6. 文件重命名:避免使用用户上传的文件名,生成随机文件名。


0x01 文件上传函数

$_FILES:一个超全局数组,用于处理上传的文件。
$_FILES['file']['name']:上传文件的原始名称。 $_FILES['file']['type']:上传文件的 MIME 类型。 $_FILES['file']['tmp_name']:文件在临时目录中的路径。 $_FILES['file']['error']:文件上传的错误代码。 $_FILES['file']['size']:文件的大小(以字节为单位)。    


move_uploaded_file():将上传的文件从临时目录移动到指定的目标目录。
$uploadFile = 'uploads/' . basename($_FILES['file']['name']);if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadFile)) { echo "File uploaded successfully.";} else { echo "File upload failed.";}


is_uploaded_file():检查指定的文件是否是通过 HTTP POST 上传的。
if (is_uploaded_file($_FILES['file']['tmp_name'])) { // 文件是通过 HTTP POST 上传的}


file_exists():检查指定的文件是否存在。
php
if (file_exists($uploadFile)) { echo "File already exists.";}


unlink():删除指定的文件。
if (unlink($uploadFile)) { echo "File deleted.";} else { echo "Failed to delete file.";}


basename():获取文件的基本名称。
$fileName = basename($_FILES['file']['name']);


pathinfo():获取文件路径信息,如目录名、基本名称、扩展名等。
$pathInfo = pathinfo($_FILES['file']['name']);$extension = $pathInfo['extension'];


 finfo_file()
功能:获取文件的 MIME 类型,通常用于验证文件类型。
示例:
$finfo = finfo_open(FILEINFO_MIME_TYPE);$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);finfo_close($finfo);
if ($mimeType === 'image/jpeg') { // 处理 JPEG 图片}


getimagesize()
功能:获取图像文件的大小和其他信息。
示例:
$imageInfo = getimagesize($_FILES['file']['tmp_name']);if ($imageInfo !== false) { // 处理图像文件}


file_put_contents()
功能:将字符串写入文件,通常用于保存上传的文件数据。
示例:
file_put_contents($uploadFilePath, $fileContents);


file_get_contents()
功能:读取文件内容到字符串中,通常用于处理上传的文件。
示例:
php
$fileContents = file_get_contents($_FILES['file']['tmp_name']);


0x02 示例

1、

[代码审计] php 文件上传

搜索关键字

[代码审计] php 文件上传

[代码审计] php 文件上传

[代码审计] php 文件上传

[代码审计] php 文件上传

有特定模板,需要下载模板后加入马

[代码审计] php 文件上传

[代码审计] php 文件上传

[代码审计] php 文件上传




2、

<?php  header("Content-type: text/html;charset=utf-8");  define("UPLOAD_PATH", "./");
if(isset($_POST['submit'])) { if(file_exists(UPLOAD_PATH)) { // 判断 content-type 的类型,如果是image/png则通过 if($_FILES['upload_file']['type'] == 'image/png') { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']; if (move_uploaded_file($temp_file, $img_path)) echo "上传完成."; else echo "上传出错."; } } }?>
<body> <form enctype="multipart/form-data" method="post"> <input class="input_file" type="file" name="upload_file"> <input class="button" type="submit" name="submit" value="上传"> </form></body>

先思考一下代码中限制的条件是什么

 if($_FILES['upload_file']['type'] == 'image/png')  //条件

只验证MIME类型: 代码中验证了上传的MIME类型,绕过方式使用Burp抓包,将上传的一句话小马*.php中的Content-Type:application/php,修改成Content-Type: image/png然后上传即可


3、

<?php  header("Content-type: text/html;charset=utf-8");  define("UPLOAD_PATH", "./");
if(isset($_POST['submit'])) { if(file_exists(UPLOAD_PATH)) { $allow_ext = array(".jpg",".png",".jpeg");
$file_name = trim($_FILES['upload_file']['name']); // 取出文件名 $file_ext = strrchr($file_name, '.'); $file_ext = str_ireplace('::$DATA', '', $file_ext); //去除字符串::$DATA $file_ext = strtolower($file_ext); // 转换为小写 $file_ext = trim($file_ext); // 首尾去空
if(in_array($file_ext, $allow_ext)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; if (move_uploaded_file($temp_file,$img_path)) echo "上传完成: {$img_path} <br>"; else echo "上传失败 <br>"; } } }?>
<body> <form enctype="multipart/form-data" method="post"> <input class="input_file" type="file" name="upload_file"> <input class="button" type="submit" name="submit" value="上传"> </form></body>

同样思考上传限制

  if(in_array($file_ext$allow_ext)) //满足两个条件
$allow_ext = array(".jpg",".png",".jpeg");

$file_name = trim($_FILES['upload_file']['name']); // 取出文件名$file_ext = strrchr($file_name, '.');$file_ext = str_ireplace('::$DATA', '', $file_ext); //去除字符串::$DATA$file_ext = strtolower($file_ext); // 转换为小写$file_ext = trim($file_ext);

白名单的绕过: 白名单就是允许上传某种类型的文件,该方式比较安全,只有后缀为限制的后缀可上传成功,这时候需要搭配组合的漏洞才能getshell

<?php  header("Content-type: text/html;charset=utf-8");  define("UPLOAD_PATH", "./");
function getReailFileType($filename){ $file = fopen($filename, "rb"); $bin = fread($file, 2); fclose($file); $strInfo = @unpack("C2chars", $bin); $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); $fileType = ''; switch($typeCode) { case 255216: $fileType = 'jpg'; break; case 13780: $fileType = 'png'; break; case 7173: $fileType = 'gif'; break; default: $fileType = 'unknown'; } return $fileType; }
if(isset($_POST['submit'])) { if(file_exists(UPLOAD_PATH)) { $temp_file = $_FILES['upload_file']['tmp_name']; $file_type = getReailFileType($temp_file); if($file_type == 'unknown') { echo "上传失败 <br>"; }else { $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type; if(move_uploaded_file($temp_file,$img_path)) echo "上传完成 <br>"; } } }?>
<body> <form enctype="multipart/form-data" method="post"> <input class="input_file" type="file" name="upload_file"> <input class="button" type="submit" name="submit" value="上传"> </form></body>

绕过检测文件头: 这种方式是通过文件头部起始位置进行匹配的从而判断是否上传,我们可以通过在上传文件前面追加合法的文件头进行绕过,例如在文件开头部位加上GIF89a<?php phpinfo();?> 即可完成绕过,或者如果是xffxd8xff 需要在文件开头先写上%ff%d8%ff<?php phpinfo(); ?> 然后,选择特殊字符,右击CONVERT->URL->URL-Decode编码后释放.

原文始发于微信公众号(Pik安全实验室):[代码审计] php 文件上传

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月20日13:15:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   [代码审计] php 文件上传https://cn-sec.com/archives/3082075.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息