米桃安全漏洞讲堂系列第3期:任意文件上传漏洞

一、概述

信息系统的建设过程中,经常会涉及文件上传的业务功能需求。如果在系统研发过程中未对上传的文件进行合理限制,或限制功能存在绕过漏洞,则系统投产后存在"任意文件上传漏洞"。

恶意攻击者可以通过上传恶意文件并在服务器端执行,造成严重危害。如下图某WebShell所示,攻击者可浏览并查看服务器文件,并对服务器拥有管理权限。

历年企业护网行动中,红队(攻击队)经常利用系统的"文件上传"功能,上传木马工具,最终实现对攻击目标的控制,攻陷目标。因此,对于"任意文件上传漏洞"的防护,平台提供方需要高度重视。

二、文件上传漏洞原理

2.1 漏洞原理

文件上传漏洞的出现,是由于代码没有严格限制用户上传文件后缀以及文件类型,导致攻击者向某个可通过Web访问的目录上传任意脚本文件,并能够将这些文件传递给解释器,在远程服务器上执行任意脚本。

存在文件上传功能的地方都有可能存在文件上传漏洞。比如用户头像、视频、照片分享、用户意见反馈等。如果移动端APP端也存在类似的操作,同理也存在文件上传漏洞风险。

2.2 文件上传漏洞产生原因

一个完整的文件漏洞利用过程,需要三个步骤:

(1)攻击者通过文件上传功能,成功上传恶意文件至后端服务器

用户上传文件时,系统前后端均未进行文件格式检查,造成用户可以上传非功能设定的文件。如jsp、asp、php等可执行文件。

(2)攻击者获得上传恶意文件所在路径,并能成功访问

成功上传可执行文件后,系统服务端返回上传文件访问路径。用户通过浏览器访问该链接,即可查看自己上传的文件。
高级别攻击者,可以在服务端不返回文件目录的情况下,主动去构造上传文件访问路径+文件名。或者结合其他漏洞访问服务器文件目录,获取文件在服务器上的绝对路径。

(3)上传的恶意文件,可执行

上传恶意的可执行文件后(jsp、php、asp等),上传目录允许该文件作执行操作。访问该文件拉起可执行木马文件,获得当前主机命令执行权限或者文件管理权限,进而控制整台主机。该步骤就是红蓝攻防中所称的getshell操作。

在可执行恶意文件这一领域中,随着安全软件检测手段的更新,攻击者的攻击手段也在不断进化。从最初的直接上传多功能木马(俗称大马),改成仅包含上传功能的木马(俗称小马)再二次上传大马,到更精简版的一句话木马,甚至近些年流行的内存马 。都是在攻守双方在不断博弈期间的升级手段。

木马相关内容,本期只作简要说明,详情将在下一期内容中详述。

2.3 漏洞危害

"文件上传"本身功能没有危害,危害发生在恶意文件上传后在服务器端执行,常见危害包括:

  1. 执行任意代码: 攻击者可以上传包含恶意代码的文件,例如 Web shell(用于远程执行命令的脚本文件),从而在受影响的服务器上执行任意命令。这使得攻击者能够控制服务器、窃取数据、修改文件等。
  2. 窃取敏感信息: 攻击者可以上传恶意脚本,用于窃取服务器上的敏感信息,包括数据库凭证、用户信息、密码等。
  3. 横向移动: 通过上传恶意文件,攻击者可以在服务器上建立后门,从而在网络内部进行横向移动,攻击其他系统。
  4. 拒绝服务攻击(DoS): 攻击者可以上传大文件或者耗尽服务器资源的文件,导致服务器过载,无法提供正常服务。
  5. 恶意文件传播: 攻击者可以上传恶意文件,然后将下载链接传播给其他用户,使得这些用户受到攻击。
  6. 绕过权限和访问控制: 攻击者可以上传包含针对安全漏洞的攻击代码的文件,绕过服务器上的权限和访问控制,从而执行未经授权的操作。
  7. 破坏文件完整性: 攻击者可以上传恶意文件,修改、删除或篡改服务器上的文件,破坏文件的完整性。
  8. 利用服务器作为攻击平台: 攻击者可以利用受感染的服务器发送垃圾邮件、发起DDoS攻击、托管恶意网站等,使用服务器作为攻击平台。

2.4 文件上传漏洞案例

2.4.1 文件上传漏洞+webshell,完成主机权限控制
  1. 针对目标网站,使用弱密码爆破方式,登录web后台。账号密码为admin/passw0rd。

2. 在界面风格>编辑模板/css文件>添加模板处将aspx一句话木马添加成html文件,1.asp

此处即为文件上传漏洞的利用方式。新增模板地址即为木马访问路径。
3. 使用木马连接工具连接上传的一句话木马文件1.asp地址。成功完成对目标主机的文件控制。攻陷主机为Windows系统。

4. 利用该木马管理工具,再次上传大马(具有多种功能的木马),完成对主机、文件、数据库的完全控制。

此时,即完成了一次getshell的攻击过程。后续的内网扩展内容,不在本文讨论范围。

三、漏洞检测方法

"任意文件上传漏洞"通常按以下测试思路进行检测

检测服务端文件后缀名过滤是否严格

如黑名单模式下过滤了.php、.jsp、.asp等可执行脚本文件,但却未过滤.php2、.php3、.php5等。以及双扩展名绕过。如上传xxx.jsp.jsp文件。 常见可执行文件后缀扩容包括:

vbnet 复制代码
PHP: phtml, .php, .php3, .php4, .php5, and .inc
ASP: asp, .aspx
PERL: .pl, .pm, .cgi, .lib
JSP: .jsp, .jspx, .jsw, .jsv, .jspf
Python:.py, .py3, .pyw, .pyx、
Coldfusion: .cfm, .cfml, .cfc, .dbm

检测文件上传限制是否仅在浏览器端JS(前端)限制

可通过抓包修改上传文件后缀名进行测试。 ● 在检测过程中使用字符截断技术

如"\0"、"?"、"%00"等,绕过文件后缀名过滤逻辑,如aaa.jsp%00.jpg,在只可上传jpg文件的位置上传jsp文件,在可以控制文件路径的情况下,使用超长的文件名也有可能会导致文件路径截断,绕过服务端限制。

检测Web中间件是否存在文件解析漏洞 (如IIS解析漏洞、Apache 文件解析问题)。

当存在漏洞时,可能导致原本不可被执行的图片,.htaccess等文件被视作asp,jsp等文件进行解析,从而可上传包含恶意代码的图片文件。

检测第三方组件是否包含文件上传漏洞,典型案例有CKEditor。

检测服务器是否支持HTTP PUT方法,能否在无文件上传功能的场景下上传文件。

检查HTTPHeader中的Content-Type,修改为text/html进行绕过。

只要能通过上述方式,上传可执行脚本文件,并正常访问文件,即证明该功能存在"任意文件上传漏洞"。

四、漏洞防护措施

4.1 研发设计视角

任意文件上传漏洞的防护思路。从研发设计角度,可以从其攻击流程三步骤入手。"允许上传恶意文件------访问上传文件------文件被执行"。只需要打断其攻击链,均可实现对文件上传漏洞攻击的防护。

4.1.1 文件上传角度防护

1、后端白名单检查文件扩展名

在判断文件类型时,可以结合使用MIME Type、后缀检查等方式。在文件类型检查中,强烈推荐白名单方式,不属于白名单范围的文件类型,不允许上传。黑名单的方式已经无数次被证明是不可靠的。此外,对于图片的处理,可以使用压缩函数或者resize函数,在处理图片的同时破坏图片中可能包含的HTML代码。不建议通过前端实现校验,攻击者可通过抓包改包方式绕过前端验证。

2、后端限制文件上传大小

辅助手段。明确上传的文件场景,可预先限定文件大小。防止上传大马等非正常文件。

4.1.2 文件访问角度防护

3、文件名随机命名 文件上传至服务器后,对文件随机命名。如UUID、GUID,不允许用户自定义。可增加攻击者访问上传文件难度。像shell.php.rar.rar和crossdomain.xml这种文件,都将因为重命名而无法攻击。

4、隐藏上传文件目录 在文件上传后,服务端不返回文件访问路径。使攻击者无法找到上传文件,切掉其攻击路径。

4.1.3 文件执行角度防护

5、上传文件保存目录不可执行

要求上传文件的保存目录无可执行权限,不可解析jsp、php、asp、py等脚本语言。只要web容器无法解析该目录下面的文件,即使攻击者上传了脚本文件,服务器本身也不会受到影响。

6、文件内容检测

通过威胁检测等工具对文件进行安全检查,可有效防范图片马和文件二次渲染。

4.1.4 安全编码示例

代码层面,任意文件上传漏洞防护思路,研发同学可参考如下"任意文件上传漏洞"安全编码示例(Java):

java 复制代码
import java.io.*;
import java.util.UUID;
public class FileUploadHandler {

    private static final String UPLOAD_DIR = "/path/to/upload/directory"; // 上传文件保存的目录
    private static final String[] ALLOWED_EXTENSIONS = {"jpg", "jpeg", "png", "gif"}; // 允许上传的文件扩展名白名单
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 最大文件大小限制为10MB
    public boolean isValidFileExtension(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        for (String allowedExtension : ALLOWED_EXTENSIONS) {
            if (extension.equals(allowedExtension)) {
                return true;
            }
        }
        return false;
    }

    public boolean isValidFileSize(long fileSize) {
        return fileSize <= MAX_FILE_SIZE; //限制上传文件大小
    }

    public String saveUploadedFile(InputStream inputStream, String originalFileName) throws IOException {
        String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
        String randomFileName = UUID.randomUUID().toString() + fileExtension;
        String filePath = UPLOAD_DIR + File.separator + randomFileName;

        try (OutputStream outputStream = new FileOutputStream(filePath)) {
            int bytesRead;
            byte[] buffer = new byte[8192];
            while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        return randomFileName;
    }

    public static void main(String[] args) {
        // 示例用法
        FileUploadHandler uploadHandler = new FileUploadHandler();
        String uploadedFileName = "example.jpg"; // 假设上传的文件名为example.jpg
        long uploadedFileSize = 5000000; // 假设上传的文件大小为5MB

        if (uploadHandler.isValidFileExtension(uploadedFileName) && uploadHandler.isValidFileSize(uploadedFileSize)) {
            try {
                // 假设inputStream是上传文件的输入流
                InputStream inputStream = new FileInputStream("/path/to/uploaded/file/example.jpg");
                String savedFileName = uploadHandler.saveUploadedFile(inputStream, uploadedFileName);
                System.out.println("File saved with random name: " + savedFileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("Invalid file. File extension or size is not allowed.");
        }
    }
}

4.2 安全开发流程SDL视角

SDL的角度来看,"任意文件上传漏洞"可通过以下措施进行防范或缓解:

4.2.1 设计阶段

  • 考虑在服务端加入通用的文件上传校验逻辑;
  • 使用白名单等的方法对文件名进行过滤,并过滤存在安全隐患的特殊字符;
  • 使用随机数改写文件名和文件路径;
  • 将上传文件限制在某一路径下,并对此文件上传目录进行限制;
  • 对文件内容进行校验。

4.2.2 开发阶段

  • 开发完成后对源代码和环境配置进行审核,确保相关逻辑按照设计实现。

4.2.3 测试阶段

  • 对文件上传功能进行严格测试,修复必要的缺陷。

4.2.4 运维阶段

  • 定期对应用和Web中间件等安排检查,及时更新并加固中间件,可以有效避免因为中间件的漏洞而导致的文件上传漏洞;
  • 使用入侵检测系统、防病毒软件等监测恶意文件上传情况;
  • 采用WAF等安全防护设备可以有效的防御常见漏洞

五、总结展望

综上,文件上传漏洞指攻击者利用程序缺陷,绕过系统对文件的验证与处理策略,将恶意程序上传到服务器并获得执行服务器端命令的能力 。本文简要讲述了任意文件上传漏洞原理、危害、测试方法及防御措施。

该漏洞可与其他漏洞结合利用,尤其是与WebShell工具结合,可造成更大危害,如直接完成对主机权限控制。企业在研发、测试阶段,需重点关注。

本系列往期链接

米桃安全漏洞讲堂系列第2期:XSS跨站脚本攻击漏洞 - 掘金
米桃安全漏洞讲堂系列第1期:SQL注入漏洞 - 掘金

相关推荐
用户962377954481 天前
VulnHub DC-3 靶机渗透测试笔记
安全
叶落阁主2 天前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
用户962377954484 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机4 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机4 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954485 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star5 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954485 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher6 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行9 天前
网络安全总结
安全·web安全