V5615. OWASP. Potential XEE vulnerability. Insecure XML parser is used to process potentially tainted data.
Анализатор обнаружил использование небезопасно сконфигурированного XML-парсера для обработки данных, полученных из внешнего источника. Это может сделать приложение уязвимым к XEE-атаке (альтернативные названия: 'billion laughs'-атака или атака с помощью XML-бомб).
XEE-атаки включены в категории OWASP Top 10 2017: A4:2017 – XML External Entities (XXE) и OWASP Top 10 2021: A05:2021 – Security Misconfiguration.
Суть XEE-атаки
Стандарт XML предусматривает использование DTD (document type definition). DTD даёт возможность определять и использовать XML-сущности. Сущности могут как ссылаться на какой-то внешний ресурс, так и быть полностью определены внутри документа. В последнем случае они могут быть представлены какой-то строкой или, например, другими сущностями.
XML-файл с примерами подобных сущностей:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE foo [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;">
]>
<foo>&lol1;</foo>
Здесь определены сущности 'lol' и 'lol1', причём первая определена через строку, а вторая – через другие сущности. Как следствие, значением сущности 'lol1' будет строка 'lollol'.
Вложенность и количество сущностей можно увеличивать. Например, так:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE foo [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
]>
<foo>&lol2;</foo>
Сущность 'lol2' раскрывается следующим образом:
lollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollol
По подобному принципу, путём увеличения количества вложенных сущностей, создаются так называемые XML-бомбы. Они представляют собой небольшие по размеру файлы, которые при раскрытии сущностей разрастаются до огромных размеров. Отсюда же происходят различные названия такого типа атак:
- XEE (XML Entity Expansion)
- billion laughs (из-за многократного повторения 'lol').
Таким образом, DoS-атака на приложение с использованием XML-бомб возможна, если:
- злоумышленник может передать приложению XML-бомбу;
- XML-парсер, который будет обрабатывать этот файл, имеет небезопасную конфигурацию.
Интересный реальный пример уязвимости приложения к XEE описан в статье "Как Visual Studio 2022 съела 100 Гб памяти и при чём здесь XML бомбы?".
Примеры уязвимого кода
Рассмотрим пример:
static void XEETarget(String pathToXml)
{
XmlReaderSettings settings = new XmlReaderSettings()
{
DtdProcessing = DtdProcessing.Parse,
MaxCharactersFromEntities = 0
};
using (var xml = File.OpenRead(pathToXml))
{
using (var reader = XmlReader.Create(xml, settings))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Text)
Console.WriteLine(reader.Value);
}
}
}
}
В данном примере с помощью XML-парсера 'reader' происходит чтение XML-файла. Однако данный парсер уязвим к XML-бомбам, т.к. он создан с небезопасными настройками, в которых:
- разрешена обработка DTD (свойство 'DtdProcessing' имеет значение 'DtdProcessing.Parse');
- не установлено ограничение на размер сущностей (свойство 'MaxCharactersFromEntities' имеет значение 0).
Как следствие, парсер может зависнуть в попытке разобрать XML-бомбу, начать потреблять большое количество памяти и т.п.
Стоит отметить, что обрабатываемые данные приходят из внешнего источника (считываются из файла по пути 'pathToXml'). Обнаружив сочетание всех перечисленных факторов, анализатор выдаст предупреждение.
Чтобы сделать парсер устойчивым к XEE-атакам, достаточно:
- запретить или игнорировать обработку DTD (установить для свойства 'DtdProcessing' значения 'Prohibit' или 'Ignore' соответственно). В более старых версиях .NET Framework вместо свойства 'DtdProcessing' используется 'ProhibitDtd'. Оно должно иметь значение 'true', чтобы обработка DTD была запрещена.
- установить ограничение на максимальный размер сущностей.
Пример настроек, в которых разрешена обработка DTD, но при этом ограничен максимальный размер сущностей:
XmlReaderSettings settings = new XmlReaderSettings()
{
DtdProcessing = DtdProcessing.Parse,
MaxCharactersFromEntities = 1024
};
Если в ходе разбора XML-файла будет превышен установленный лимит, парсер сгенерирует исключение типа 'XmlException'.
Анализатор также отслеживает межпроцедурные вызовы. Изменим предыдущий пример:
static XmlReaderSettings GetDefaultSettings()
{
var settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;
settings.MaxCharactersFromEntities = 0;
return settings;
}
public static void XEETarget(String pathToXml)
{
using (var xml = File.OpenRead(pathToXml))
{
using (var reader = XmlReader.Create(xml, GetDefaultSettings()))
{
ProcessXml(reader);
}
}
}
static void ProcessXml(XmlReader reader)
{
while (reader.Read())
{
// Process XML
}
}
В данном случае анализатор выдаст предупреждение на вызов метода 'ProcessXml', так как отследит, что:
- внутри этого метода происходит обработка XML-файла;
- XML-парсер создан с небезопасными настройками, пришедшими из метода 'GetDefaultSettings';
- парсер обрабатывает потенциально опасные данные (считанные из файла 'pathToXml').
Кроме того, анализатор укажет на фрагменты кода, соответствующие перечисленным выше действиям.
Стоит отметить, что анализатор также считает источниками небезопасных данных параметры методов, доступных из других сборок. Более подробно эта тема раскрыта в заметке "Почему важно проверять значения параметров общедоступных методов".
Пример:
public class XEETest
{
public static void XEETarget(Stream xmlStream)
{
var rs = new XmlReaderSettings()
{
DtdProcessing = DtdProcessing.Parse,
MaxCharactersFromEntities = 0
};
using (var reader = XmlReader.Create(xmlStream, rs))
{
while (reader.Read())
{
// Process XML
}
}
}
}
Анализатор выдаст предупреждение низкого уровня достоверности на данный код, так как источник небезопасных данных – параметр публично-доступного метода – используется в опасно сконфигурированном XML-парсере.
Обратите внимание, что в разных версиях .NET Framework настройки по умолчанию могут отличаться. Как следствие, один и тот же код может либо быть уязвимым к XEE-атакам, либо устойчивым.
Пример подобного кода:
static void XEETarget(String pathToXml)
{
using (var xml = File.OpenRead(pathToXml))
{
var settings = new XmlReaderSettings()
{
DtdProcessing = DtdProcessing.Parse
};
using (var reader = XmlReader.Create(xml, settings))
{
while (reader.Read())
{
// Process XML
}
}
}
}
Данный код уязвим к XEE-атакам в версиях .NET Framework 4.5.1 и более старых, так как не устанавливает ограничения на размер сущностей (значение свойства 'MaxCharactersFromEntities' - 0). В версиях .NET Framework 4.5.2 и более новых по умолчанию установлено ограничение на размер сущностей, как следствие – данный код в них будет устойчив к XEE.
Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки непроверенного использования чувствительных данных (ввода пользователя, файлов, сети и пр.). |
Данная диагностика классифицируется как: