ASP.NET中的SMTP头注入?

Ben*_*lls 8 asp.net security smtp code-injection

我的ASP.NET网站有一个全局错误处理程序,当Web应用程序中出现任何类型的错误时,它会向我(和另一个开发人员)发送电子邮件.我们最近收到一条错误,其中包含我们从未听说过的电子邮件地址的CC.可怕的是,发送错误电子邮件的开发人员列表在编译的ASP.NET代码中进行了硬编码.我们没有看到如何添加CC.

我们也非常怀疑犯规行为,因为导致错误的请求是尝试使用我们的某个表单发送垃圾邮件.发送请求的IP地址也列在http://www.projecthoneypot.org/上.

我们现在最好的猜测是,请求在某种程度上是错误的,它在电子邮件中注入了CC标头.问题是我们无法弄清楚如何做到这一点.我们正在使用System.Net.Mail发送电子邮件,它似乎可以防止这种情况.MailMessage对象的主题只接受一行,因此您不会创建带有CC行的多行主题.在MailMessage中设置to和cc地址似乎非常强大.而且我看不出你如何在消息体中添加CC头.我找不到任何关于此的信息,我很想知道这是否是一个真正的问题.

编辑:有人要求代码.它有点长,但它是:

public class Global : System.Web.HttpApplication
{
    protected void Application_Error(Object sender, EventArgs e)
    {
        // Get the last exception.
        Exception objException = Server.GetLastError();

        // Work out the error details based on the exception.
        string ErrorType = "";
        string ErrorDescription = "";
        string ErrorHtml = "";

        if (objException == null)
        {
            // This should never occur.
            ErrorType = "Unknown Error";
            ErrorDescription = "Unknown Error";
        }
        else if (objException.GetType() == typeof(HttpException))
        {
            // This will occur when the ASP.NET engine throws a HttpException.
            HttpException objHttpException = objException as HttpException;
            if (objHttpException.GetHttpCode() == 404)
            {
                string Resource = Globals.GetFullUrl(this.Context);
                Server.ClearError();
                Response.Redirect("/ResourceNotFound.aspx?BadUrl=" + Server.UrlEncode(Resource));
                return;
            }
            else
            {
                ErrorType = objHttpException.GetHttpCode().ToString();
                ErrorDescription = objHttpException.Message;
            }
        }
        else if (objException.GetType() == typeof(HttpUnhandledException) && objException.InnerException != null && objException.InnerException.GetType() == typeof(HttpException))
        {
            // This will occur when the code throws a HttpException (e.g. a fake 404).
            HttpException objHttpException = objException.InnerException as HttpException;
            if (objHttpException.GetHttpCode() == 404)
            {
                string Resource = Globals.GetFullUrl(this.Context);
                Server.ClearError();
                Response.Redirect("/ResourceNotFound.aspx?BadUrl=" + Server.UrlEncode(Resource));
                return;
            }
            else
            {
                ErrorType = objHttpException.GetHttpCode().ToString();
                ErrorDescription = objHttpException.Message;
            }
        }
        else if (objException.GetType() == typeof(HttpUnhandledException))
        {
            // This will occur when a page throws an error.
            HttpUnhandledException objHttpUnhandledException = (HttpUnhandledException) objException;
            ErrorType = objHttpUnhandledException.GetHttpCode().ToString();
            if (objHttpUnhandledException.InnerException != null)
                ErrorDescription = objHttpUnhandledException.InnerException.Message;
            else
                ErrorDescription = objHttpUnhandledException.Message;
            if (objHttpUnhandledException.GetHtmlErrorMessage() != null)
            {
                ErrorHtml = objHttpUnhandledException.GetHtmlErrorMessage();
            }
        }
        else if (objException.GetType() == typeof(HttpRequestValidationException) && !Globals.IsTtiUser(this.Context))
        {
            // Do nothing.  This is mostly just spider junk and we don't want to know about it.
        }
        else
        {
            // This will occur when the ASP.NET engine throws any error other than a HttpException.
            ErrorType = objException.GetType().Name;
            ErrorDescription = objException.Message;
        }

        // Send an email if there's an error to report.
        if (ErrorType != "" || ErrorDescription != "")
        {
            Globals.SendErrorEmail(this.Context, ErrorType, ErrorDescription, ErrorHtml);
        }
    }

    public static void SendErrorEmail (HttpContext context, string errorType, string errorDescription, string errorHtml)
    {
        // Build the email subject.
        string Subject = "EM: " + errorType + ": " + context.Request.ServerVariables["SCRIPT_NAME"];

        // Build the email body.
        string Body;

        StringBuilder sb = new StringBuilder("");
        sb.Append("Server:\r\n");
        sb.Append(Globals.Server.ToString() + "\r\n");
        sb.Append("\r\n");
        sb.Append("URL:\r\n");
        sb.Append(Globals.GetFullUrl(context) + "\r\n");
        sb.Append("\r\n");
        sb.Append("Error Type" + ":\r\n");
        sb.Append(errorType + "\r\n");
        sb.Append("\r\n");
        sb.Append("Error Description" + ":\r\n");
        sb.Append(errorDescription + "\r\n");
        sb.Append("\r\n");
        sb.Append("Referring Page:\r\n");
        sb.Append(context.Request.ServerVariables["HTTP_REFERER"] + "\r\n");
        sb.Append("\r\n");
        sb.Append("Date/Time:\r\n");
        sb.Append(DateTime.Now.ToString() + "\r\n");
        sb.Append("\r\n");
        sb.Append("Remote IP:\r\n");
        sb.Append(context.Request.ServerVariables["REMOTE_ADDR"] + "\r\n");
        sb.Append("\r\n");
        sb.Append("User Agent:\r\n");
        sb.Append(context.Request.ServerVariables["HTTP_USER_AGENT"] + "\r\n");
        sb.Append("\r\n");
        sb.Append("Crawler:\r\n");
        sb.Append(context.Request.Browser.Crawler.ToString() + "\r\n");
        sb.Append("\r\n");
        sb.Append("Admin User:\r\n");
        sb.Append(context.User.Identity.Name + "\r\n");
        sb.Append("\r\n");
        sb.Append("\r\n");
        Body = sb.ToString();

        // If there's HTML to represent the error (usually from HttpUnhandledException),
        // then stuff the body text into the HTML (if possible).
        bool HtmlMessage = false;

        if (errorHtml != "")
        {
            Regex r = new Regex("(?<thebodytext><body.*?>)", RegexOptions.IgnoreCase);
            if (r.IsMatch(errorHtml))
            {
                Body = Body.Replace("\r\n", "<br>");
                Body = r.Replace(errorHtml, "${thebodytext}" + Body, 1);
                HtmlMessage = true;
            }
        }

        // Send an email to the TTI developers.
        MailMessage objMail;
        objMail = new MailMessage();
        objMail.From = new MailAddress("from-address");
        objMail.To.Add(new MailAddress("to-address"));
        objMail.CC.Add(new MailAddress("cc-address"));
        objMail.CC.Add(new MailAddress("another-cc-address"));
        if (HtmlMessage)
            objMail.IsBodyHtml = true;
        else
            objMail.IsBodyHtml = false;
        if (errorType == "404")
            objMail.Priority = MailPriority.Low;
        else
            objMail.Priority = MailPriority.High;
        objMail.Subject = Subject;
        objMail.Body = Body;

        try
        {
            SmtpClient objSmtpClient = new SmtpClient();
            objSmtpClient.Send(objMail);
        }
        finally
        {
            // Do nothing.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Lar*_*ryF 4

我可以看到这是一个非常有创意的攻击的目标...您正在将用户控制的数据填充到您的消息正文中...此时,巧妙地使用二进制数据可能会导致正文在消息正文中发送正确的数据SMTP 会话使其格式正确...如果可以的话,我建议将正文转换为所有 ASCII 文本,或者在字符串构建过程中编写一个仅允许 RFC 字符进入的字符串清理程序。(过滤 URL, REFERRER、远程地址和用户代理)。这些是您更有可能受到攻击的点。

第二个想法可能是用代码构建一个基本电子邮件,并将您构建的正文附加为文本、HTML 或 PDF 文件。

请记住,SMTP ENVELOPE 数据与消息数据不同......如果有人足够狡猾地发送正确的正文,导致在正文部分期间发送 CRLFCRLF.CRLFCRLF,则将终止发送,然后如果他们继续发送数据,他们可以将整个邮件从:RCPT TO:、DATA 等发送...(当然,这是不太可能发生的情况...)...

我很想看看您收到的电子邮件的原始源...(如实际 SMTP 事务的十六进制转储,而不是 Outlook 希望您看到的内容或其他内容)

您也可以在发送消息之前尝试使用 QP 或 B64 对您的正文进行编码...这可能会解决您的问题...

这是一件很有趣的事情,我很期待它的结果。