文件上传漏洞的利用和防御

1.什么是文件上传漏洞

文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。这种漏洞是getShell最快最直接的方法之一。

常见场景是web服务器允许用户上传图片或者普通文本文件保存,而用户绕过上传机制上传恶意代码并执行从而控制服务器。

2.产生文件上传漏洞的原因

未于上传文件的后缀名(扩展名)没有做较为严格的限制

未于上传文件的MIMETYPE(用于描述文件的类型的一种表述方法) 没有做检查

未对文件进行从命名和对文件路径进行隐藏。

未限制文件的执行权限。

3.文件上传漏洞的攻击与防御

前端限制

原理

在表单中使用onsumbit=checkFile()调用js函数来检查上传文件的扩展名。当用户在客户端选择文件点击上传的时候,客户端还没有向服务器发送任何消息,就对本地文件进行检测来判断是否是可以上传的类型,这种方式称为前台脚本检测扩展名。

绕过方法

这种限制很简单,通过浏览器F12很简单的修改文件后缀名就可以完成绕过检查,或者是讲木马修改后缀名后上传,通过改包工具修改上传。如果是JS脚本检测,在本地浏览器客户端禁用JS即可。可使用火狐浏览器的NoScript插件、IE中禁用掉JS等方式实现绕过。

操作方法

准备webshell,修改后缀名为.jpg .png等后缀,进行上传操作,通过burpsuit抓包,更改为原后缀名。

例一句话木马:


后端检查拓展名

在后端对文件的后缀进行检,如不合法就不允许本次上传。

1.黑名单法

文件扩展名在黑名单中的为不合法

实例:

 private static final String[] FILE_SUFFIX_SUPPORT ={".jsp",".php",".asp","aspx"};
    public static void uploadVerify(MultipartFile multipartFile) {
        // 校验文件是否为空
        if (multipartFile == null) {
            throw new RuntimeException("文件不能为空!");
        }
        //得到文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 校验文件后缀
        if (!originalFilename.contains(".")) {
            throw new RuntimeException("文件不能没有后缀!");
        }
        String suffix = originalFilename.substring(originalFilename.lastIndexOf('.'));
        for (String s : FILE_SUFFIX_SUPPORT) {
            //转换为小写比较,Locale.ROOT为区域转换规则可不写
            if (s.equals(suffix.toLowerCase(Locale.ROOT))) {
                throw new RuntimeException("请上传正常的文件!");
            }
        }
    }

2.白名单法

文件扩展名不在白名单中的均为不合法

private static final String[] FILE_SUFFIX_SUPPORT ={".jpg",".png",".gif"};
    public static void uploadVerify(MultipartFile multipartFile) {
        // 校验文件是否为空
        if (multipartFile == null) {
            throw new RuntimeException("文件不能为空!");
        }
        //得到文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 校验文件后缀
        if (!originalFilename.contains(".")) {
            throw new RuntimeException("文件不能没有后缀!");
        }
        String suffix = originalFilename.substring(originalFilename.lastIndexOf('.'));
        for (String s : FILE_SUFFIX_SUPPORT) {
            if (!s.equals(suffix.toLowerCase(Locale.ROOT))) {
                //转换为小写比较,Locale.ROOT为区域转换规则可不写
                throw new RuntimeException("请上传正常的文件!");
            }
        }
    }

原理

当浏览器将文件提交到服务器端的时候,服务器端会根据设定的黑白名单对浏览器提交上来的文件扩展名进行检测,如果上传的文件扩展名不符合黑白名单的限制,则不予上传,否则上传成功。

绕过方法

在一些Web server中,存在解析漏洞:

ginx(0.5.x, 0.6.x, 0.7 <= 0.7.65, 0.8 <= 0.8.37)空字节漏洞 xxx.jpg%00.php 这样的文件名会被解析为php代码运行(fastcgi会把这个文件当php看,不受空字节影响,但是检查文件后缀的那个功能会把空字节后面的东西抛弃,所以识别为jpg)
apache1.x,2.x的解析漏洞,上传如a.php.rar a.php.gif 类型的文件名,可以避免对于php文件的过滤机制,但是由于apache在解析文件名的时候是从右向左读,如果遇到不能识别的扩展名则跳过,rar等扩展名是apache不能识别的,因此就会直接将类型识别为php,从而达到了注入php代码的目的

检查Content-Type

原理

HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改。

绕过方法

使用burpsuite等抓包工具强行篡改Header就可以,将Content-Type: application/php改为其他web程序允许的类型。

文件头检查文件

原理

利用的是每一个特定类型的文件都会有不太一样的开头或者标志位。

绕过方法

给上传脚本加上相应的幻数头字节就可以,php引擎会将

(一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符。)

文件系统00截断

原理

在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束。**利用00截断就是利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00、%00上传截断漏洞。

绕过方法

通过抓包截断将【evil.php.jpg】后面的一个【.】换成【0x00】。在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束,从而将【evil.php.jpg】的内容写入到【evil.php】中,从而达到攻击的目的。

文件上传漏洞的利用和防御_第1张图片

还有其他的防御方法和绕过方法可以结合upload-labs的靶场进行实战分析。

你可能感兴趣的:(网络安全)