点击星标关注公众号,不再迷路~
原文转载自自己在Freebuf上面的投稿,链接:https://www.freebuf.com/articles/web/400213.html
前言
此处审计的oa系统有个前提,就是/resource目录下专门存储静态文件,是不解析的,想要文件上传就需要利用目录穿越到代码所在的/C6目录下面
思路历程
咱们findstr搜索下上传的关键字,比如:uploadfile这类的
好吧一看还挺多,咱们挑一个来看,比如Web.Module.dll文件
反编译dll文件打开查看Web.Module.dll,找到一个Save关键字的上传方法
看下类UploadFileEditorSave,初始化方法为Page_Load
传参FileName会被作为文件保存的路径,存入text中
之后判断fileSerName是否为””的字符串,而fileSerName是从配置中读取到的
是””则调用
path = UploadFileEditorSave.MapFilePath(text);
不是””则调用
path = Upload.MapFilePath(text);
这边假设他不为””,因为一般配置中信息不为空
追踪Upload.MapFilePath方法:
首先代码先对_FilePath做了处理
_FilePath = _FilePath.ToLower();
首先获取转成小写的字符串路径
_FilePath = _FilePath.Replace("\", "//").Replace("/resource/", "/");
将路径中的所有\替换为//,所有/resource/替换为/(有先后顺序)
已假设fileServerName不为空,则进入if判断中,if判断又分了三个子判断
代码如下:
text = ConfigurationSettings.AppSettings["FileServerPath"];
if (_FilePath.Replace("../", "/").Length < _FilePath.Length)
{
text += _FilePath.Replace("\", "/").Replace("../", "/").Replace("/", "\");
}
else if (_FilePath.Split(new char[]
{
'^'
}).Length > 1)
{
text += _FilePath.Replace("resource", "^").Split(new char[]
{
'^'
})[1].Replace("../", "").Replace("/", "\");
}
else
{
text += _FilePath.Replace("\", "/").Replace("../", "/").Replace("/", "\");
}
text = text.Replace("\\", "\");
text = "\" + text.Replace("\\", "\");
Upload.DealGarbageChar(ref text, "\");
text = fileServerName + text;
判断1
if (_FilePath.Replace("../", "/").Length < _FilePath.Length)
{
text += _FilePath.Replace("\", "/").Replace("../", "/").Replace("/", "\");
}
此处如果_FilePath存在../字符串,则对_FilePath又进行了处理,将所有\替换为/,所有../替换为/,所有/替换为\(有先后顺序)
判断2
text += _FilePath.Replace("resource", "^").Split(new char[]
{
'^'
})[1].Replace("../", "").Replace("/", "\");
如果_FilePath存在多个^
符号,则通过Split
方法在^
处分割字符串,得到一个字符串数组。
然后选取这个数组的第二个元素(索引为 1),并对该元素进行替换操作:删除所有的../,然后将/替换为反斜杠
判断3
如果都不满足,则对_FilePath进行处理,将所有\替换为/,所有../替换为/,所有/替换为\(有先后顺序)
text += _FilePath.Replace("\", "/").Replace("../", "/").Replace("/", "\");
最后再对_FilePath处理一遍,将所有\\替换为\
text = text.Replace("\\", "\");
text = "\" + text.Replace("\\", "\");
Upload.DealGarbageChar(ref text, "\");
text = fileServerName + text;
然后调用DealGarbageChar方法删除多余的\\
绕过
看上去是不是已经绝望到无法上传然后目录穿越,其实不然
注意到他对目录穿越只处理的对象是../,可以双写..来绕过。咱们传入….,其中会变成\这样的字符串,代码中就变成了\….\,咱们就直接进入子判断的判断3中
text += _FilePath.Replace("\", "/").Replace("../", "/").Replace("/", "\");
首先替换\为/,字符串就变为/…./,之后替换../为/,则字符串变为/../,最后替换/为\,字符串变为\..\
结果还是能实现目录穿越,且用..避开了判断1,直接进入判断3中
最后拼接到fileServeName,然后返回最为文件路径
text = fileServerName + text;
之后调用Upload.NoAESRead方法存入输入的内容到文件路径
利用
完整的调用分析就到这里,咱们构造数据包尝试下:
FileName传参为……..C6commonAdd.aspx,目录穿越/C6/common/Add.aspx文件中,到再上传aspx一句话木马的内容
上传成功返回状态码200
使用冰蝎连接一下,测试上传成功
至此利用链分析完毕
END
关注HackingWiki漏洞感知
了解更多安全相关内容~
原文始发于微信公众号(HackingWiki漏洞感知):.Net代码审计之某OA系统任意文件上传