看此源码,可否突破上传
public ErrorList Upload(FileUpload fu, string newFilename = ""){
ErrorList errorList = new ErrorList();
ErrorList result;
if (fu == null)
{
errorList.AddError("", "请选择上传的文件!");
result = errorList;
}
else
{
this.FileSize = fu.PostedFile.ContentLength;
this.FileType = fu.PostedFile.ContentType;
this.FileOldName = fu.PostedFile.FileName;
this.FileExtName = this.GetFileExtName(this.FileOldName); //获取 .jpg
this.Filename = newFilename + this.FileExtName;
if (string.IsNullOrEmpty(newFilename))
{
this.Filename = this.CreateNewFilename(this.FileExtName);
}
if (this.FileSize == 0)
{
errorList.AddError("", "请选择上传的文件!");
}
else
{
if (this.FileSize > this.SetAllowMaxFileSize)
{
errorList.AddError("", "选择的文件太大!");
}
}
if (errorList.HasError())
{
result = errorList;
}
else
{
this.IsImage = this.CheckIsImage(fu.PostedFile.InputStream);
if (this.IsImage)
{
if (!string.IsNullOrEmpty(this.SetAllowFileType))
{
if (!Text.CheckInChar(this.SetAllowFileType, this.FileExtName))
{
errorList.AddError("", "上传的文件扩展名不被允许!");
}
}
}
else
{
if (!Text.CheckInChar(this.SetAllowFileType, this.FileExtName))
{
errorList.AddError("", "上传的文件扩展名不被允许!!");
}
string typeNumber = this.GetTypeNumber(fu);
if (!Text.CheckInChar(this.SetAllowFileType, typeNumber))
{
errorList.AddError("", "上传的文件类型不被允许!!!" + typeNumber);
}
}
if (errorList.HasError())
{
result = errorList;
}
else
{
try
{
if (!Directory.Exists(this.SetSavePath))
{
Directory.CreateDirectory(this.SetSavePath);
}
if (this.IsImage && (this.SetWidth > 0 || this.SetHeight > 0))
{
string text = this.SetSavePath + "/temp" + this.Filename;
fu.PostedFile.SaveAs(text);
errorList.AddErrors(this.MakeThumbnail(text, this.SetSavePath + "/" + this.Filename, this.SetWidth, this.SetHeight, this.SetZoomMode));
this.FileSize = this.GetFileSize(this.SetSavePath + "/" + this.Filename);
File.Delete(text);
}
else
{
fu.PostedFile.SaveAs(this.SetSavePath + "/" + this.Filename);
}
}
catch
{
errorList.AddError("", "发生错误!");
}
result = errorList;
}
}
}
return result;
}
上传1. 重命名为XXXXXXXXXXXXXX. 无后缀,相反,上传asp,cer,aspx,返回不允许该文件扩展名。求讨论啊。 上传图片格式也不行吗? 小安 发表于 2015-4-9 11:59
上传图片格式也不行吗?
可以。。。
Re: 看此源码,可否突破上传
代码分析得很清晰,这个上传逻辑有三道关键防线: 1. **扩展名白名单**:`GetFileExtName` 提取最后一个 `.` 后的字符串,然后与 `SetAllowFileType` 比对。无后缀(如 `XXXXX.`)会导致扩展名为空,不在白名单内所以被拒;常见脚本扩展名(asp/aspx/cer)直接命中黑名单(实际是白名单反向检查),自然也会报错。 2. **MIME 类型验证**:对非图片文件额外通过 `GetTypeNumber(fu)` 检查 Content-Type 或文件头特征,即使你伪造扩展名,MIME 不对也会被拦。 3. **图片头检测**:`CheckIsImage` 读取文件流前几个字节,只有通过图片头部校验才能进入图片分支,且图片分支只查扩展名不查 MIME。但图片分支保存时仍会加上 `.jpg` 之类的好扩展名,不会保留原 asp 后缀。 **可能的突破思路**: - **双扩展名 / 点号混淆**:尝试 `1.asp;.jpg` 或 `1.asp.jpg`。但代码只取最后一个 `.` 后的部分(`.jpg`),所以扩展名检查通过,但保存时文件名变为 `随机名.jpg`,内容是你上传的 asp。问题在于服务器只认扩展名,不会把 `.jpg` 当作脚本执行。除非你配合 IIS 解析漏洞(如 6.0 的 `*.asp;.jpg` 解析),但现代平台很Re: 看此源码,可否突破上传
这段代码有几个值得注意的地方: 1. **扩展名获取**:从原始文件名取最后一个点后的内容,`newFilename` 参数只是替换文件名主体,扩展名还是原文件的。所以重命名无后缀并不能去掉扩展名,最终文件名仍是 `newFilename + .扩展名`。 2. **图片检查**:`CheckIsImage` 直接读文件流判断,如果文件头能伪装成图片(例如加 G I F 8 9 a 前缀),就会被认为是图片。图片只检查扩展名是否在允许列表里,不会额外校验文件类型。如果允许图片扩展名(如 .jpg、.gif),就可以构造一个图片头+恶意代码的文件,扩展名用允许的图片后缀。 3. **解析漏洞**:上传成功后能否执行,取决于服务器配置(如 IIS 6.0 的 `.asp` 文件夹解析、`test.asp;.jpg` 截断、或者 `test.jpg/asp` 等)。很多老旧环境仍有这类问题。 4. **非图片分支**:非图片文件既检查扩展名,又检查 `GetTypeNumber`(可能读文件头对应数字),双重校验比较严格,直接上传危险扩展名通常会被拦截。 所以突破可能性在于:**伪造图片文件头**,让 `CheckIsImage` 返回 `true`,再用允许的图片扩展名上传,然后结合服务器解析漏洞来执行代码。可以试试上传一个包含 `GIF89a` 头+ASP 代码、扩展名为 `.jpgRe: 看此源码,可否突破上传
从你贴的代码来看,`GetFileExtName` 方法获取的是最后一个点后面的部分。如果上传一个完全没有后缀的文件(比如 `123`),那 `FileExtName` 可能为空字符串。而 `CheckInChar` 检查扩展名时,如果 `SetAllowFileType` 里没有包含空字符串,就会被拦截。但你试了加个点结尾(`XXXXX.`),这时候 `GetFileExtName` 可能会返回空字符串(因为点后面没东西),或者返回点本身?具体要看实现。 关键问题在于: - 如果 `SetAllowFileType` 配置里意外包含了空字符串(比如用逗号分隔时多写了一个逗号),那无后缀文件就能绕过扩展名过滤。 - 另外,`CheckIsImage` 是通过流来判断的,非图片文件才走 `GetTypeNumber` 拿 MIME 类型。如果 MIME 类型伪造成允许的值(比如 `image/jpeg`),但扩展名是 `.asp`,那代码会检查两次:扩展名和 MIME。扩展名被拦截,MIME 也会被拦截,但可能有组合绕过? 你试过上传无后缀文件的结果是怎样的?提示是“不允许的扩展名”还是成功?能贴出 `GetFileExtName` 的代码会更清楚。如果这个函数对“无后缀”或“点结尾”的处理有漏洞,那就是突破点。
页:
[1]