文件上传这个功能点是现在大部分 UGC 站点必备的功能啦,像是头像、文章编辑、评论区等模块都标配。在编码时不考虑上传文件的内容和文件类型就有可能被上传 WebShell。

最常见的利用方法是对正常上传点,传递脚本直接获取 Web 服务控制权限,或者上传一个 HTML 页面将链接发给用户进行钓鱼;用户一看 URL 是官方就有可能放松警惕。

文件上传分为WebServer解析、应用检验不严格、前端检验这三种类型。

WebServer 解析问题

就算代码写的没问题,Web 服务器存在问题会把其他文件当做其他正常脚本解析。

Apache 1.x / 2.x 解析漏洞

  1. Apache 处理 shell.php.jss.zd 从右到做依次判断后缀名能不能解析,不能往前走,直到能解析就停下来,此时得到处理的文件是 shell.php

Apache 加载的 PHP 模块配置文件正则匹配默认解析 pht、phtml、php3、php4、php5。

IIS 5.x / 6.0 解析漏洞

IIS 调用 asp.dll 解析文件名时出现问题。

  1. Web 服务器上存在 .asp.asa.cer 结尾的目录,其目录下所有文件被访问时都会被当做脚本执行。
  2. 上传一个 xx.asp;.jpgxx.asa;.jpgxx.cer;.jpg 的图片,访问时这个图片会被当做脚本执行。

Nginx

pass

黑名单绕过

系统特性

如果代码采用黑名单检测的方式,可以使用大小写绕过限制。
Windows 下更改文件它会忽略大小写,最终指向同一个文件,这个特性在切换目录也可以提现出来,Linux 则当成两个不同的文件,它对大小写是区分的。

系统特性差异.png

NTFS 文件流绕过

这种绕过方式适用于黑名单。

每个文件都对应着一个文件流,即 Default,而每个文件可以有多个文件流。
创建文件流的格式:源文件:文件流名:文件流数据格式

很多人在上传时这样写:shell.ext::$DATA

如果服务器没有这个文件名,就会自动创建一个,有就把原文件内容重写。
为啥重写?像我们编辑一个文件时显示的内容都是默认文件流中的,Payload 中把文件流名留空不写就相当于对默认文件流写入数据。
NTFS默认文件流

我们重新创建一个文件流就依附在源文件上,可以用 dir /R 查看。
NTFS附加文件流

  1. 上传漏洞可以多加个完整的 filename 参数,有些程序可能取第二个文件名的值,WAF 也可能只匹配第一个参数值。
  2. .././../ 来跨越目录绕过黑名单拦截 ../../
  3. 代码有可能是直接剔除关键字,那么可以嵌套 1.asaspxpx,最终得到 1.aspx。有人称双写绕过。
  4. 后缀尝试,aspx 可以尝试上传 ashx,ascx,asmx。asp 尝试 cer、asa。它俩也可以试试 asmx。php 尝试上传 php2/3/4/5/phtm。jsp 尝试 jspx。

Apache htaccess 配置

htaccess 可以针对指定目录进行配置,颗粒度会更细,放置该文件的目录其子目录和文件都会受到影响。

下面的配置是将 .configz 的文件交给 PHP 解析。

AddType application/x-httpd-php .configz

这个配置是将 shell.* 这个文件交给 PHP 解析。

<FilesMatch "shell">
    SetHandler application/x-httpd-php
</FilesMatch>

操作:

  1. 上传 .htaccess 文件,内容是配置某个后缀文件能够交给语言解析。
  2. 上传指定文件

其他 Web Server 可以支持 htaccess 吗?

白名单绕过

字符串截断

上传 shell.php.jpg,通过在 .jpg 开头放置一个结尾符,最后代码遇到就会直接停止在 shell.php,对这个文件名进行操作就成功截断为 php 文件了。

通过结尾符表示文件结束,%00 是 URL 编码后的结尾符。
%00 截断需要 PHP Version 小于 5.3.7。

操作:

  1. Burp 抓包修改文件名处输入的标记字符
  2. 转换到十六进制中将标记字符改为 00

文件头绕过

文件头是不变的,有些代码仅检测文件头,可以把对应文件头后面加上一句话来上传。既限制了后缀有检查了文件头那么可以上传一个正常图片配合解析漏洞/文件包含拿 Shell。

下面是 16 进制的文件头(使用 UltraEdit 查看)
常见文件头格式

上传+文件包含解析文件

File Inclusion

验证文件内容和后缀,那我们直接上传正常图片,如果服务器存在文件包含漏洞那么可以在图片文件头后面中添加一句话,让代码把中的内容当做代码执行。

防御

  1. 代码采用白名单校验扩展名。
  2. 对前端传来的图片采用伪随机数命名(时间戳+伪随机数),不返回上传后的路径,增加找 Shell的难度;要是头像这种在模板上调用图片,这种情况也没办法。
  3. 对图片二次处理(其他语言也有对应图片处理库),就算你上传脚本,渲染后图片中代码会被破坏掉无法正常解析。
  4. 限制上传文件大小,以避免服务器资源耗尽(最低成本 DDOS)。
  5. 取消上传目录执行权限(未测试),IIS 可以用 Web.config 配置,其他 Web 容器需要搜索下资料。
  6. 可以将放置图片单独放在一台服务器(阿里云 OSS),脚本在图片服务器上没有执行环境不能被解析。
  7. 使用新版本 Web Server做好安全配置;避免 Web 服务器低版本漏洞和不安全的配置问题。

练习

GitHub - c0ny1/upload-labs: 一个想帮你总结所有类型的上传漏洞的靶场

  1. 前端 JS 验证
    在浏览器关掉 JS

CheckFile.png

closeJS.JPG

这种方法比较好用,还有个地方可以让它不执行 JS 脚本,它是提交表单是调用这个方法我们可以双击把这双引号内内容删掉,就不会触发检测了。

elements.png

也可以在本地写一个 HTML 表单进行提交。

2.文件 MIME 验证

他的验证方式是检测 Content-Type 的MIME是否为图片类型 ,只有匹配上了才放你通过。

MimeSourceCode.png

我们将原来的 mime Content-Type: application/octet-stream 改为图片的 MIME 就可以绕过了。

MIME

3.文件后缀验证

它这里黑名单验证,会把名字转换为小写并重新用“时间+随机值命名,文件后缀无法加空格绕过。

ExtendFormat.JPG

在实战中会遇到各种奇怪的情景,这里提供一个实际场景,有一个上传点只能 Upload DLL 文件,代码直接读取文件名来决定文件存储位置,这时候你如何利用?

参考链接

标签: none

讨论讨论讨论!