上传漏洞-上传漏洞的原理

作者: 来源: 日期:2009-10-18

上传漏洞是一个非常恐怖的漏洞,如果你的程序里面有这种漏洞,那么恶意攻击者可以直接向你的服务器上传一个 webshell( 又称 ASP 木马、PHP 木马等即利用服务器端的文件操作语句写成的动态网页,可以用来编辑你服务器上的文件 ),从而控制你的网站。

那么,上传漏洞是怎么样一种漏洞呢。

一般对于上传漏洞的概念定义如下:由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。打个比方来说,如果你使用 windows 服务器并且以 asp 作为服务器端的动态网站环境,那么在你的网站的上传功能处,就一定不能让用户上传 asp 类型的文件,否则他上传一个 webshell,你服务器上的文件就可以被他任意更改了。

相对于我前面所谈到的跨站漏洞,不得不承认,上传漏洞对于网站的危害是致命的,那么,上传漏洞是如何产生的呢。

我们知道,在 WEB 中进行文件上传的原理是通过将表单设为 multipart/form-data,同时加入文件域,而后通过 HTTP 协议将文件内容发送到服务器,服务器端读取这个分段 (multipart) 的数据信息,并将其中的文件内容提取出来并保存的。通常,在进行文件保存的时候,服务器端会读取文件的原始文件名,并从这个原始文件名中得出文件的扩展名,而后随机为文件起一个文件名 ( 为了防止重复 ),并且加上原始文件的扩展名来保存到服务器上。

慢着,就在这个扩展名这里就出了问题了,究竟是什么问题呢,我们开启一个新的章节来详细说说,上传漏洞的几种形式和各自的防护方法。

上传漏洞的几种形式及其防护

第一、 完全没有处理。

完全没有处理的情况不用我说,看名字想必大家都能够了解,这种情况是程序员在编写上传处理程序时,没有对客户端上传的文件进行任何的检测,而是直接按照其原始扩展名将其保存在服务器上,这是完全没有安全意识的做法,也是这种漏洞的最低级形式,一般来说这种漏洞很少出现了,程序员或多或少的都会进行一些安全方面的检查。

第二、 将 asp 等字符替换。

我们再看一些程序员进阶的做法,程序员知道 asp 这样的文件名是危险的,因此他写了个函数,对获得的文件扩展名进行过滤,如:

Function checkExtName(strExtName)

strExtName = lCase(strExtName) ' 转换为小写

strExtName = Replace(strExtName,"asp","") ' 替换 asp 为空

strExtName = Replace(strExtName,"asa","") ' 替换 asa 为空

checkExtName = strExtName

End Function

使用这种方式,程序员本意是将用户提交的文件的扩展名中的“危险字符”替换为空,从而达到安全保存文件的目的。粗一看,按照这种方式,用户提交的 asp 文件因为其扩展名 asp 被替换为空,因而无法保存,但是仔细想想,这种方法并不是完全安全的。

突破的方法很简单,只要我将原来的 webshell 的 asp 扩展名改为 aaspasp 就可以了,此扩展名经过 checkExtName 函数处理后,将变为 asp,即 a 和 sp 中间的 asp 三个字符被替换掉了,但是最终的扩展名仍然是 asp。

因此这种方法是不安全的。如何改进呢,请接着往下看。

第三、 不足的黑名单过滤。

知道了上面的替换漏洞,你可能已经知道如何更进一步了,对了,那就是直接比对扩展名是否为 asp 或者 asa,这时你可能采用了下面的程序:

Function checkExtName(strExtName)

strExtName = lCase(strExtName) ' 转换为小写

If strExtName = "asp" Then

checkExtName = False

Exit Function

ElseIf strExtName = "asa" Then

checkExtName = False

Exit Function

End If

checkExtName = True

End Function

你使用了这个程序来保证 asp 或者 asa 文件在检测时是非法的,这也称为黑名单过滤法,那么,这种方法有什么缺点呢。

黑名单过滤法是一种被动防御方法,你只可以将你知道的危险的扩展名加以过滤,而实施上,你可能不知道有某些类型的文件是危险的,就拿上面这段程序来说吧,你认为 asp 或者 asa 类型的文件可以在服务器端被当作动态脚本执行,事实上,在 windows2000 版本的 IIS 中,默认也对 cer 文件开启了动态脚本执行的处理,而如果此时你不知道,那么将会出现问题。

实际上,不只是被当作动态网页执行的文件类型有危险,被当作 SSI 处理的文件类型也有危险,例如 shtml、stm 等,这种类型的文件可以通过在其代码中加入 <!-- #include file="conn.asp"--> 语句的方式,将你的数据库链接文件引入到当前的文件中,而此时通过浏览器访问这样的文件并查看源代码,你的 conn.asp 文件源代码就泄露了,入侵者可以通过这个文件的内容找到你的数据库存放路径或者数据库服务器的链接密码等信息,这也是非常危险的。

那么,如果你真的要把上面我所提到的文件都加入黑名单,就安全了吗,也不一定。现在很多服务器都开启了对 asp 和 php 的双支持,那么,我是不是可以上传 php 版的 webshell 呢,所以说,黑名单这种被动防御是不太好的,因此我建议你使用白名单的方法,改进上面的函数,例如你要上传图片,那么就检测扩展名是否是 bmp、jpg、jpeg、gif、png 之一,如果不在这个白名单内,都算作非法的扩展名,这样会安全很多。

第四、 表单中传递文件保存目录。

上面的这些操作可以保证文件扩展名这里是绝对安全的,但是有很多程序,譬如早期的动网论坛,将文件的保存路径以隐藏域的方式放在上传文件的表单当中 ( 譬如用户头像上传到 UserFace 文件夹中,那么就有一个名为 filepath 的隐藏域,值为 userface),并且在上传时通过链接字符串的形式生成文件的保存路径,这种方法也引发了漏洞。

FormPath=Upload.form("filepath")

For Each formName in Upload.file '' 列出所有上传了的文件

Set File=Upload.file(formName) '' 生成一个文件对象

If file.filesize<10 Then

Response.Write " 请先选择你要上传的图片  [ <a href=# onclick=history.go(-1)> 重新上传 </a> ]"

Response.Write "</body></html>"

Response.End

End If

FileExt=LCase(file.FileExt)

If CheckFileExt(FileExt)=false then

Response.Write " 文件格式不正确  [ <a href=# onclick=history.go(-1)> 重新上传 </a> ]"

Response.Write "</body></html>"

Response.End

End If

Randomize

ranNum=Int(90000*rnd)+10000

FileName=FormPath&year(now)&month(now)&day(now)&hour(now)&minute(now)

&second(now)&ranNum&"."&FileExt

大家可以看出这段代码,首先获得表单中 filepath 的值,在最后将其拼接到文件的保存路径 FileName 中。

在这里就会出现一个问题。

问题的成因是一个特殊的字符:chr(0),我们知道,二进制为 0 的字符实际上是字符串的终结标记,那么,如果我们构造一个 filepath,让其值为 filename.asp ■ ( 这里是空字符,即终结标记 ),这个时候会出现什么状况呢,FileName 的值就变成了 filename.asp,再进入下面的保存部分,所上传的文件就以 filename.asp 文件名保存了,而无论其本身的扩展名是什么。

黑客通常通过修改数据包的方式来修改 filepath,将其加入这个空字符,从而绕过了前面所有的限制来上传可被执行的网页,这也是我们一般所指上传漏洞的原理。

那么,如何防护这个漏洞呢,很简单,尽量不在客户端指定文件的保存路径,如果一定要指定,那么需要对这个变量进行过滤,如:

FormPath = Replace(FormPath,chr(0),"")

第五、 保存路径处理不当。

经过以上的层层改进,从表面上来说,我们的上传程序已经很安全了,事实上也是这样的,从 2004 年的动网上传漏洞被指出后,其他程序纷纷改进上传模块,因此上传漏洞也消失了一段时间,但是今年春节的时候,另种上传漏洞被黑客发掘了出来,即结合 IIS6 的文件名处理缺陷而导致的一个上传漏洞。这里简单说一句,这个漏洞最早被发现与 * 易 CMS 系统。

在该系统中,用户上传的文件将被保存到其以用户名为名的文件夹中,上传部分做好了充分的过滤,只可以上传图片类型的文件,那么,为什么还会出现漏洞呢。

IIS6 在处理文件夹名称的时候有一个小问题,就是,如果文件夹名中包含 .asp,那么该文件夹下的所有文件都会被当作动态网页,经过 ASP.dll 的解析,那么此时,在 * 易系统中,我们首先注册一个名为 test.asp 的用户名,而后上传一个 webshell,在上传时将 webshell 的扩展名改为图片文件的扩展名,如 jpg,而后文件上传后将会保存为 test.asp/20070101.jpg 这样的文件,此时使用 firefox 浏览器访问该文件 (IE 会将被解析的网页文件当作突破处理,因为其扩展名为图片 ),此时会发现我们上传的“图片”又变成了 webshell。

这个漏洞其实是十分有趣的,他不只是简单的 asp 漏洞,而是结合了 IIS 的一个缺陷,的确非常的隐蔽。

当然,防御这个漏洞也是很简单的,如果没有必要,那么不要将突破按照用户名分目录保存,如果一定要这样,那么需要检测用户名中是否有非法字符,例如 . 等。

相关文章