发一个能防止改名木马漏洞的无组件上传类
现在流行的asp上传组件除了无惧的化境之外,最多的可能就是ewebEditor 和Fckeditor的上传是,但是经过测试都很难防止改名为gif和asp文件上传,在FckEditor中改名后的asp木马不能直接上传,系统会检测到<%等字符而拒绝,但是经过修改后的asp木马再改名为gif后却可以顺利上传,如在文件前端加上许多空行,或对木马进行加密处理。当然有人会认为木马传到服务器后会被杀掉,但是做过免杀的木马却会漏网。基于这些原因,本人开发了一个可以从根本上解决这个问题的无组件上传类。经过测试常用的文件格式均可通过。做法是对上传的文件进行格式分析,不符合的格式不允许上传,这样就从根本上解决了这个问题。现贴上来请大家指教。
1、文件upfile.asp
<%
'**************************************************************************
'* 类文件名称:upfile.asp
'* 作者:马如风(Melon)
'* 邮箱:mqmelon0@163.com
'* 版权:=====筱风工作室(R)2004.1-2004.3=====
'* 内容:不用组件上传文件类
'* 用法:在接收表单内容的文件中定义UpFileClass类对象,用GetData方法
'* 读取文件内容,并使用FileInfo类的SaveToFile方法存入指定文件
'* 例子:set FileUP=new UpFileClass
'* FileUp.GetData
'* set file1=FileUP.upFile("表单元素名")
'* filename=path&filename
'* file1.SaveToFile(server.mappath(filename))
'* set FileUp=nothing
'**************************************************************************
%>
<%
response.charset="gb2312"
Dim BinaStream '全局变量
'dim FileSavePath
Class UpFileClass '类别名称
'定义Dictionary变量,用于保存上传的信息
Dim upForm,upFile
' 类初始化过程
private sub Class_Initialize
'判断传递的数据,如无,则退出
if Request.TotalBytes<1 Then
Exit sub
End if
'FileSavePath="" '全局变量负值
set BinaStream=Server.CreateObject("adodb.stream")
set upForm=New DictionaryClass
set upFile=New DictionaryClass
End sub
'类清除过程
Private sub Class_Terminate
upFile.RemoveAll
upForm.RemoveAll
set upFile=nothing
set upForm=nothing
BinaStream.Close
set BinaStream=nothing
FileSavePath=""
End sub
'获取数据过程
Public sub GetData
Dim oFileInfo '用于保存文件信息的类对象
Dim oDataSeprator '用于保存分隔符信息,为二进制字符串
Dim oFindStart,oFindEnd '寻找指针
Dim oCrLf ' CHRB(13)&CHRB(10), 分隔数字
Dim oFormData ' 表单数据描述信息,文本串
Dim oFileStart ' 文件开始位置
Dim otmpStream ' 临时Stream 对象,用于中间周转字符串
Dim otmpBinaData ' 临时二进制字符串,用于中间周转
Dim oDataAllSize ' 所有二进制数值大小
Dim oFormName ' 表单元素名称
Dim oFormContent ' 表单元素内容
Dim oFormStart ' 表单元素开始位置
Dim oFormEnd ' 表单元素结束位置
Dim oFileFullName ' 带路径文件名
'变量初始化
set oFileInfo=new FileInfo
oDataSeprator=""
oFindStart=Clng(0)
oFindEnd=Clng(0)
oCrLf=chrB(13)&chrB(10)
oFormData=""
oFileStart=Clng(0)
set otmpStream=Server.CreateObject("adodb.stream")
otmpBinaData=""
oDataAllSize=Clng(0)
oFormName=""
oFormcontent=""
oFormStart=Clng(0)
oFormEnd=Clng(0)
oFileFullName=""
' 获得传递过来的二进制数据
if Request.TotalBytes<1 then
Error_Msg("发生数据错误,传递数据空或丢失!")
Exit sub
End if
BinaStream.Type=1 '二进制
BinaStream.Mode=3 '读写模式,1-读,2-写,3-读写
BinaStream.Open '打开对象,准备读写
'开始读取所有上传的数据
'Thankful long(yrl031715@163.com)
'Fix upload large file.
'**********************************************
' 修正作者:long
' 联系邮件: yrl031715@163.com
' 修正时间:2007年5月6日
' 修正说明:由于iis6的Content-Length 头信息中包含的请求长度超过了 AspMaxRequestEntityAllowed 的值(默认200K), IIS 将返回一个 403 错误信息.
' 直接导致在iis6下调试FCKeditor上传功能时,一旦文件超过200K,上传文件时文件管理器失去响应,受此影响,文件的快速上传功能也存在在缺陷。
' 在参考 宝玉 的 Asp无组件上传带进度条 演示程序后作出如下修改,以修正在iis6下的错误。
Dim nTotalBytes, nPartBytes, ReadBytes
ReadBytes = 0
nTotalBytes = Request.TotalBytes
'循环分块读取
Do While ReadBytes < nTotalBytes
'分块读取
nPartBytes = 64 * 1024 '分成每块64k
If nPartBytes + ReadBytes > nTotalBytes Then
nPartBytes = nTotalBytes - ReadBytes
End If
BinaStream.Write Request.BinaryRead(nPartBytes)
ReadBytes = ReadBytes + nPartBytes
Loop
'读取完毕
BinaStream.Position=0
otmpBinaData=BinaStream.Read
oDataAllSize=BinaStream.Size
'获得分隔符
oDataSeprator=MidB(otmpBinaData,1,InstrB(1,otmpBinaData,oCrLf)-1)
'给寻找指针付值
oFindStart=Lenb(oDataSeprator)+2
oFindEnd=oFindStart
'分解名项目,且保存其值
While oFindStart+2<oDataAllSize
otmpStream.Type=1
otmpStream.MOde=3
otmpStream.Open
oFindEnd=InstrB(oFindStart,otmpBinaData,oCrLf&oCrLf)+3
'此时,oFindEnd指向内容,oFindStart指向描述
BinaStream.Position=oFindStart
BinaStream.CopyTo otmpStream,oFindEnd-oFindStart
'把表单描述存入oFormData
otmpStream.Position=0
otmpStream.Type=2 '设为文本类型数据
otmpStream.Charset="gb2312" '设字符集为中文
oFormData=otmpStream.ReadText '保存数据为文本
'查找表单项目名称
oFormStart=Instr(1,oFormData,"name=",1)+len("name=")+1
oFormEnd=Instr(oFormStart,oFormData,"""",1)
oFormName=Mid(oFormData,oFormStart,oFormEnd-oFormStart)
'调试开始
'open_appe_txt "debug.txt","oFormData="&chr(13)&chr(10)&oFormData
'open_appe_txt "debug.txt","判断前:"&chr(13)&chr(10)&"oFormStart="&oFormStart&"oFormEnd="&oFormEnd&"oFormName="&oFormName
'调试结束
'判断是否为文件
if Instr(oFormEnd,oFormData,"filename=",1)>0 Then
'是文件,则取文件属性
'找到文件名字
oFormStart=Instr(oFormEnd,oFormData,"filename=",1)+len("filename=")+1
'加1是为了去掉文件名字前面的引号
oFormEnd=Instr(oFormStart,oFormData,"""",1)
'此时,oFormEnd指向下一个描述的前一个位置,减1是为去掉引号
'获得文件信息
'获得带路径文件名称
oFileFullName=Mid(oFormData,oFormStart,oFormEnd-oFormStart)
'分解文件名称
oFileInfo.FileName=GetFileName(oFileFullName)
oFileInfo.FileExt=GetFileExt(oFileFullName)
oFileInfo.FilePath=GetFilePath(oFileFullName)
'获得文件类型
oFormStart=Instr(oFormEnd,oFormData,"Content-Type:",1)+len("Content-Type:")
oFormEnd=Instr(oFormStart,oFormData,chr(13)&chr(10),1)
oFileInfo.FileType=Mid(oFormData,oFormStart,oFormEnd-oFormStart)
'获得文件内容起始点
oFileInfo.FileStart=oFindEnd
oFindStart=InstrB(oFindEnd,otmpBinaData,oDataSeprator)
'此时,oFindStart指向分隔符位置
oFileInfo.FileSize=oFindStart-oFindEnd-3
oFileInfo.FormName=oFormName
'把数据加入到upFile[Dictionary对象]中保存
'调试开始
'open_appe_txt "debug.txt","循环中(文件):"&chr(13)&chr(10)&"oFindStart="&oFindStart&"oFormName="&oFormName
'调试结束
upFile.add oFormName,oFileInfo
Else
'如果是表单元素,则取元素值
'关闭otmpStream对象,以便重新读取内容
otmpStream.Close
otmpStream.Type=1
otmpStream.Mode=3
otmpStream.Open
'找到内容结束位置
oFindStart=InstrB(oFindEnd,otmpBinaData,oDataSeprator)
'读出内容
BinaStream.Position=oFindEnd
BinaStream.CopyTo otmpStream,oFindStart-oFindEnd-3
otmpStream.Position=0
otmpStream.Type=2
otmpStream.Charset="gb2312"
oFormContent=otmpStream.ReadText
upForm.add oFormName,oFormContent
End if
'调整寻找指针位置
oFindStart=oFindStart+LenB(oDataSeprator)+1
'此时,寻找指针均指向下一描述
otmpStream.Close
WEnd '循环返回
'变量清空
otmpBinaData=""
set otmpBinaData=nothing
end sub '子程序到此结束