Внедрение заголовка SMTP в ASP.NET?

На моем веб-сайте ASP.NET есть глобальный обработчик ошибок, который отправляет электронное письмо мне (и другому разработчику), когда в веб-приложении возникает какая-либо ошибка. Недавно мы получили сообщение об ошибке, содержащее CC на адрес электронной почты, о котором мы никогда не слышали. Страшно то, что список разработчиков, которым отправляется электронное письмо с ошибкой, жестко закодирован в скомпилированном коде ASP.NET. Мы не видим, как можно было добавить CC.

Мы также очень подозрительно относимся к нечестной игре, потому что запрос, вызвавший ошибку, был попыткой использовать одну из наших форм для рассылки спама. IP-адрес, с которого был отправлен запрос, также указан на http://www.projecthoneypot.org/.

Сейчас мы можем предположить, что запрос был каким-то образом искажен, и в него был добавлен заголовок CC в электронное письмо. Проблема в том, что мы не можем понять, как это можно сделать. Мы используем System.Net.Mail для отправки электронных писем, и, похоже, он защищает от подобных вещей. Тема объекта MailMessage принимает только одну строку, поэтому вы не создаете многострочную тему со строкой CC. Установка адресов «to» и «cc» в MailMessage кажется довольно надежной. И я не понимаю, как можно добавить заголовок 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.
        }
    }
}

person Ben Mills    schedule 12.03.2009    source источник
comment
Покажите нам свой код, и мы поможем. Иначе люди будут гадать ...   -  person Eppz    schedule 12.03.2009
comment
Я добавил код. Как я уже сказал, это сложно, но я не хотел слишком упрощать его, так как не знаю, в чем может быть проблема.   -  person Ben Mills    schedule 12.03.2009
comment
Отправьте электронное письмо (в необработанном виде, включая все заголовки; скрывайте как можно реже), содержащее ошибку, содержащую CC, на адрес электронной почты, о котором вы никогда не слышали. Более вероятно, что вся электронная почта является поддельной.   -  person bzlm    schedule 13.03.2009
comment
Вы видите ошибку в журналах ошибок, которая предположительно вызвала отправку этого письма? Если нет, то это явная подделка, как предполагал bzlm. Если да, то какие значения URL, агента пользователя и HTTP-реферера регистрировались при возникновении ошибки?   -  person Chetan S    schedule 13.03.2009
comment
Спасибо за показ кода, но, конечно же, большая часть его не имеет отношения к вашей проблеме. Копия не проходит через форматирование тела письма!   -  person John Saunders    schedule 13.03.2009
comment
Кроме того, вы, конечно же, имели в виду попробовать {send} catch {}. И я думаю, что я бы попытался зарегистрировать исключение в блоке catch. Может быть, это исключение, которое должно вызвать сбой вашего приложения. Вы никогда не узнаете, если скроете от себя исключение.   -  person John Saunders    schedule 13.03.2009


Ответы (3)


Я мог видеть, что это цель ОЧЕНЬ творческой атаки .... Вы вбиваете данные, контролируемые пользователем, в тело сообщения ... В этот момент хитрое использование двоичных данных МОЖЕТ < / em> приведет к BODY, который отправляет правильные данные во время сеанса SMTP для его форматирования JUST RIGHT ... Если можно, я бы предложил либо преобразовать тело во весь текст ASCII, либо во время построения строки напишите средство очистки строк, которое позволяет вводить только символы RFC (фильтрует URL-адреса, REFERRER, удаленный адрес и UserAgent). Это ваши наиболее вероятные точки атаки.

Вторая мысль могла бы состоять в том, чтобы создать простое электронное письмо в коде и ПРИКЛЮЧИТЬ тело, которое вы создали в виде текста, HTML или PDF-файла.

Имейте в виду, что данные SMTP ENVELOPE НЕ совпадают с данными сообщения .... Если кто-то был достаточно хитрым, чтобы отправить правильное тело, которое вызвало отправку CRLFCRLF.CRLFCRLF во время части тела, это прекратили бы отправку, а затем, если бы они продолжали отправлять данные, они могли бы отправить всю MAIL FROM: RCPT TO :, DATA и т.д ... (Конечно, это маловероятный сценарий ...) ...

Мне бы очень хотелось увидеть источник RAW электронного письма, которое вы получили ... (Как в шестнадцатеричном дампе фактической SMTP-транзакции, а не то, что Outlook хочет, чтобы вы видели, или что-то еще).

Вы также можете попробовать кодировать свое тело с помощью QP или B64 перед отправкой сообщения .... Это может решить вашу проблему ...

Это интересный вопрос, и я с нетерпением жду его результатов.

person LarryF    schedule 18.03.2009
comment
Я так и не решил эту проблему, и у нас проблема была только 1 раз. Я собираюсь принять этот ответ как наиболее вероятный сценарий. Я думаю, что введенные пользователем данные должны быть созданы очень хитрым способом. Мне также очень нравится идея добавления введенных пользователем данных в виде вложения текстового файла. - person Ben Mills; 24.02.2012

Ваш код выглядит очень безопасным, поэтому я не думаю, что проблема на вашей стороне.

IMO, либо кто-то перехватил SMTP-сообщение, когда оно было отправлено на почтовый сервер, и ввел дополнительную строку CC:; или почтовый сервер был взломан.

Если вы не можете найти ответ, я предлагаю напрямую связаться с Microsoft - возможно, вы обнаружили эксплойт в .NET Framework.

person Ian Kemp    schedule 18.03.2009

В качестве обходного пути, почему бы вам не зашифровать сообщение электронной почты, используя асимметричное шифрование (например, шифрование с открытым ключом)? Таким образом, только предполагаемый получатель сможет его прочитать.

Таким образом, даже если плохие парни получат копию вашего сообщения (любым способом), оно будет им полезно.

Давайте посмотрим правде в глаза: если у вас есть сайт высокого профиля, такой как ФБР или Google, многие очень творческие люди потратят много времени и приложат все усилия, чтобы скомпрометировать его. Чрезвычайно важно защитить подробные сообщения об ошибках.

person JonnyBoats    schedule 19.07.2009