文件上传漏洞的文件本质就一句话:服务器太信任用户传上来的东西了。你传个PHP文件上去,上传它当宝贝一样存着,漏洞还能直接访问执行——这事儿在2024年依然天天发生。总结
我前阵子帮朋友看一个CMS,文件后台头像上传功能,上传前端用JS校验了后缀名,漏洞只允许jpg/png。总结抓包改一下,文件把shell.php改成shell.php.jpg,上传Content-Type写成image/jpeg,漏洞服务端照单全收。总结更离谱的文件是,上传目录直接映射在web根路径下,上传路径都能猜到。漏洞这种代码我见过不下几十套,写法各异,毛病一模一样。
前端校验?那是给普通用户看的。Burp抓包改后缀、改MIME类型,这两招能打穿一半以上的站点。服务端如果只做黑名单,比如禁掉php、asp、jsp,那试试phtml、php5、php7、pHp——大小写混写、罕见后缀,Apache的AddHandler配置稍微不严谨就中招。
白名单就安全了?不一定。解析漏洞这事儿得单独拎出来说。Nginx早年那个fastcgi配置问题,传个1.jpg/x.php,Nginx把x.php当PHP脚本交给fastcgi处理。Apache的多后缀解析,shell.php.jpg在某些配置下照样当PHP跑。IIS 6那个分号截断和目录解析漏洞,老归老,内网里还跑着XP+IIS6的机器不在少数。
还有竞争上传。传上去、访问、删除,三步之间有个时间窗口。条件竞争脚本疯狂上传,在删除前抢着访问,照样能拿到shell。这个手法隐蔽,但成功率取决于服务器IO速度。
去年某次攻防演练,目标是一个在线教育平台。上传点是一个“导入题库”功能,只允许xlsx。我传了个正常xlsx,抓包看请求,发现服务端把文件存到了/upload/excel/下面,文件名是时间戳+原始文件名。改成test.xlsx内容换成PHP代码,后缀不动,上传成功。访问/upload/excel/xxx_test.xlsx,返回的是文件内容,不是执行结果——说明没解析。但目录可以列,我看到了其他队伍传的webshell,人家传的是.phtml,服务器居然认。我跟着传了一个,连上了。那台机器后来被我们当跳板用了三天,管理员愣是没发现。
这事儿说明什么?黑名单永远漏,白名单加解析漏洞等于没防。最要命的是上传目录和web目录没做隔离,权限也没降,www-data能读能写能执行。
我自己的做法:上传目录禁止脚本执行,Nginx里加location匹配,PHP文件直接返回403。文件名重写,用UUID,不带原始后缀信息。文件存到web根目录外面,通过一个代理脚本读取,Content-Disposition设成attachment。白名单只留业务需要的几种,服务端重新编码图片,把EXIF和多余数据全洗掉。
还有一点常被忽略:上传接口要做频率限制和文件大小限制。有人传个10G的zip,磁盘直接满,服务挂掉。这不算漏洞,但能搞出拒绝服务。
文件上传这玩意儿,写起来三行代码,防起来得考虑七八个层面。开发觉得能传就行,安全觉得能防就行,中间差的那部分,就是漏洞的生存空间。